Ed's Big Plans

Computing for Science and Awesome

The Null Coalescing Operator (C#, Ruby, JS, Python)

featured post

without comments

Null coalescence allows you to specify what a statement should evaluate to instead of evaluating to null. It is useful because it allows you to specify that an expression should be substituted with some semantic default instead of defaulting on some semantic null (such as null, None or nil). Here is the syntax and behaviour in four languages I use often — C#, Ruby, JavaScript and Python.

C#

Null coalescencing in C# is very straight forward since it will only ever accept first class objects of the same type (or null) as its operator’s arguments. This restriction is one that exists at compile time; it will refuse to compile if it is asked to compare primitives, or objects of differing types (unless they’re properly cast).

Syntax:

<expression> ?? <expression>

(The usual rules apply regarding nesting expressions, the use of semi-colons in complete statements etc..)

A few examples:

DummyNode a = null;
DummyNode b = new DummyNode();
DummyNode c = new DummyNode();

return a ?? b; // returns b
return b ?? a; // still returns b
DummyNode z = a ?? b; // z gets b
return a ?? new DummyNode(); // returns a new dummy node
return null ?? a ?? null; // this code has no choice but to return null
return a ?? b ?? c; // returns b -- the first item in the chain that wasn't null

No, you’d never really have a bunch of return statements in a row like that — they’re only there to demonstrate what you should expect.

Ruby, Python and Javascript

These languages are less straight forward (i.e. possess picky nuances) since they are happy to evaluate any objects of any class with their coalescing operators (including emulated primitives). These languages however disagree about what the notion of null should be when it comes to numbers, strings, booleans and empty collections; adding to the importance of testing your code!

Syntax for Ruby, Javascript:

<expression> || <expression>

Syntax for Ruby, Python:

<expression> or <expression>

(Ruby is operator greedy :P.)

The use of null coalescence in these languages are the same as they are in C# in that you may nest coalescing expressions as function arguments, use them in return statements, you may chain them together, put in an object constructor as a right-operand expression etc.; the difference is in what Ruby, Python or Javascript will coalesce given a left-expression operand. The below table summarizes what left-expression operand will cause the statement to coalesce into the right-expression operand (i.e. what the language considers to be ‘null’-ish in this use).

Expression as a left-operand Does this coalesce in Ruby? Does this coalesce in Python? Does this coalesce in JavaScript?
nil / None / null Yes Yes Yes
[] No Yes No
{} No Yes n/a*
0 No Yes Yes
0.0 No Yes Yes
“” No Yes Yes
No Yes Yes
false / False / false
Yes Yes Yes

*Note that in JavaScript, you’d probably want to use an Object instance as an associative array (hash) so that the field names are the keys and the field values are the associated values — doing so means that you can never have a null associative array.

Contrast the above table to what C# will coalesce: strictly “null” objects only.

The null coalescing operator makes me happy. Hopefully it’ll make you happy too.

Eddie Ma

July 7th, 2010 at 11:00 am

Parsing a Newick Tree with recursive descent

featured post

with 12 comments

>>> Attached: ( parse_newick.js – implementation in JS | index.html – example use ) <<<

Update: Fixed parse_newick.js source code that caused a field to be mislabelled in index.html (2010 Dec. 19)

This method of parsing works for any language that allows recursive functions — basically any of the curly bracket languages (C#, C, Java) and the fast-development languages (Ruby, JavaScript, Python) can do this. This particular example will include JavaScript code which you can take and do whatever you want with — recursive descent parsing is a well-known and solved problem, so it’s no skin off my back. Before we begin, I should probably explain what a tree in Newick format is.

What exactly is the Newick format?

Remember back in second year CS when your data structures / abstract data types / algorithms instructor said you can represent any tree as a traversal? Well, if not — don’t fret, it’s not hard to get the hang of.

A traversal is a finite, deterministic representation of a tree which can be thought of as a road map of how to visit each node of the tree exactly once. The phylogeny / bioinformatics people will know each of these nodes as either taxa / sequences (the leaves) or profiles (the internal nodes — i.e. not the leaves). A tree in Newick format is exactly that — a traversal. More specifically, it is a depth-first post-order traversal. When traversing a tree, we have a few options about how we want to visit the nodes — depth-first post-order means we want to start at the left-most, deepest leaf, and recursively visit all of the nodes before we end at the root.

A tree expressed in Newick format describes a tree as an observer has seen it having visited each node in a depth-first post-order traversal.

A node in the Newick format can be…

  • A leaf in the form: “<name>:<branch_length>”
    • e.g. “lcl|86165:-0
    • e.g. “gi|15072471:0.00759886
    • e.g. “gi|221105210:0.00759886
  • Or a node in the form “(<node>,<node>):<branch_length>”
    • This is where it gets tricky and recursive — the “node” item above can be another node, or a leaf — when a node is composed of at least another node, we call that a recursive case; when a node is composed of only leaves, we call that a base case. We make this clearer in the next section.
  • Or a node in the form “(<node>,<node>);”
    • The semi-colon at the end means that we have finished describing the tree. There is no branch length as the root of the tree is not connected to a parent.

Understanding recursion in a Newick Tree

Base case e.g.: The below node is composed of two leaves.

(lcl|86165:-0,gi|87118305:-0):0.321158

Recursive case e.g.: The below node is composed of a leaf on the left, and another node on the right; this right-node is composed of two leaves.

“(gi|71388322:0.0345038,(gi|221107809:0.00952396,gi|221101741:0.00952396):0.0249798):0.0111081

If the names look a bit funny, that’s because these are sequences pulled out of a blastp search.

The Newick tree itself may have any number of nodes, the base case being a single node. The only restriction is that any node either is a leaf (has zero children) or must have two children (never a single child). These two children again are allowed to be either leaves or other nodes.

We would visualize the above Recursive case e.g. as follows.:

Where the numbers beside the edges are edge length and the names of the named taxa are indicated inside the circles (leaves). The unnamed internal nodes are the profiles that have been calculated with alignments. You’ll notice that there’s a branch length leading out of the root of this subtree into the rest of the tree (not shown). If this was a complete tree on its own, the root would have no branch length there and no arrow coming out of it.

Finally, Parsing!

Now that we have reviewed the depth-first post-order traversal, the Newick format and how to interpret it; we can move onto parsing these things. In parsing, we hope to create an in-memory structure that represents the tree. The parser I discuss assumes that the Newick format string already has had all newlines stripped, as it uses regular expressions. If your trees aren’t stored that way, just make sure that newlines are stripped before feeding it into my function. The in-memory object that’s created will have the following fields as a minimum.

  • node_type $left – the left child of a node
  • node_type $right – the right child of a node
  • string_type $name – the name of a node (if it is a leaf)
  • float_type $branch_length – the length of the branch coming out of the top of a given node

I also use the following two fields to keep track of a few house keeping items and to make life pleasant for future tasks with this in-memory structure.

  • node_type $parent – the parent of a node
  • integer_type $serial – the order in which this node occurs when parsed

Note that in future, a depth-first post-order traversal will yield the nodes in the exact order that they were read — so in reality “this.serial” isn’t really needed, but it’s nice to have for future functions you might write as a shorthand. Have you understood why these nodes would occur in the same order?

Each language has its own quirks. Python and JavaScript have the advantage that you can define a class and define its properties (fields) on the fly — meaning there’s less code to download and to write, which is particularly good for blogs 😛

Here’s pseudo-code for the recursive descent parsing function “tree_builder(<newick_string>)” — I don’t indicate where to strip away newlines because I assume they’re gone. I also don’t indicate where to strip away whitespace (I did previously, but that took up like half the pseudocode). So if there’s a place where you suspect whitespace can occur, strip it away and increment the cursor by the length of that whitespace.

Note: We are assuming that there are no newlines in the file — that is, the entire newick traversal is one string on a single long unbroken line.

// Note:
// Call tree_builder() with a "new" operator in JavaScript
//     to allow it to use the 'this' keyword.
// In other languages,
//     you may need to explicitly create a new object instead of using 'this'.

var count = 0; // can be either a global variable or a reference
// keeps track of how many nodes we've seen

var cursor = 0; // also either a global or a reference
// keeps track of where in the string we are

function tree_builder(newick_string) {
    // Look for things relating to the left child of this node //
    if $newick_string [ $cursor ] == "(" {
        $cursor ++; // move cursor to position after "(".
        if newick_string [ $cursor ] == "(" {
            // Then the $left node is an internal node: requires recursion //
            $this.left = new tree_builder(newick_string); // RECURSIVE CALL.
            $this.left.parent = $this;
        }
        // try to find a valid $name next at the current cursor position //
        if $name = $newick_string [ $cursor ] . regex match ("^[0-9A-Za-z_|]+") {
            // Then the $left node is a leaf node: parse the leaf data //
            $this.left = new Object;
            $this.left.name = $name;
            $this.left.serial = $count;
            $count ++;
            $this.left.parent = $this;
            $cursor += length of $name;
            // move cursor to position after matched name.
        }
        // notice: if no $name found, just skip to finding branch length.
    }
    if $newick_string [ $cursor ] == ":" {
        // Expect left branch length after descending into the left child //
        $cursor ++; // move cursor to position after the colon.
        // look for the string representation of a floating point value "FPV"...
        $branch_length_string =
            $newick_string [ $cursor ] . regex match ("^[0-9.+eE-]+");
$this.$left.$score = $branch_length_string as a FPV;
        $cursor += length of the string $branch_length_string;
        // move cursor after FPV.
    }
    // Look for things related to the right node //
    if $newick_string [ $cursor ] == "," {
        $cursor ++; // move cursor after the comma
        if newick_string [ $cursor ] == "(" {
            // Then the $right node is an internal node: requires recursion //
            $this.right = new tree_builder($newick_string); // RECURSIVE CALL.
            $this.right.parent = $this;
        }
        // try to find a valid $name next at the current cursor position //
        if $name = $newick_string [ $cursor ] . regex match ("^[0-9A-Za-z_|]+") {
            // Then the $right node is a leaf node: parse the leaf data //
            $this.right = new Object;
            $this.right.name = $name;
            $this.right.serial = $count;
            $serial ++;
            $this.right.parent = $this;
            $cursor += $length of $name;
        }
        // again, accept if no $name found and move onto branch length.
    }
    // Now looking for the branch length ... //
    if $newick_string at $cursor == ":" {
        // Expect right branch length after descending into right child //
        $cursor ++; // moving past the colon.
        $branch_length_string =
            $newick_string [ $cursor ] . regex match ("^[0-9.+eE-]+");
        $this.right.score = $branch_length_string as a FPV;
        $cursor += length of the string $branch_length_string;
    }
    if $newick_string at $cursor == ")" {
        $cursor ++; // move past ")".
    }
    // Expect the branch length of $this node after analyzing both children //
    if $newick_string at $cursor == ":" {
        $cursor ++;
        $branch_length_string =
            $newick_string [ $cursor ] . regex match ("^[0-9.+eE-]+");
        $this.score = $branch_length_string as a FPV;
        $cursor += length of the string $branch_length_string;
    }
    if $newick_string at $cursor == ";" {
        // This case only executes for the root node-- //
        // --the very last node to finish parsing //
        $cursor ++; // to account for the semicolon (optional, consistency)
        $this.serial = $count; // no need to increment $count here
    }
    // Return to complete a recursive instance (internal) or base case (leaf) //
    return this; // not needed if "new" operator was used all along
}

The implementation that’s included in the attached JavaScript does two things differently than the above. First, I don’t force the user to break encapsulation by declaring globals. Instead, I use an object called “ref” which has two fields, “ref.count” and “ref.cursor”. The name “ref” is chosen to remind us that its fields are passed by reference. This is possible because the object “ref” itself is passed by reference (I could have called it anything, but I chose a name that suited its purpose). Imagine trying to pass “count” and “cursor” in this recursive function without an enclosing object — what would happen instead is that the value wouldn’t be updated, instead the integer values would be copied and modified locally in the span of single function instances. The “ref” object is passed as an argument to the “_tree_builder(<ref>, <newick_string>)” function internally where it is instantiated if “null” is passed in the place of “ref”. The calling user doesn’t even need to know about it, as it’s all wrapped together in a pretty package and the user just calls “tree_builder(<newick_string>)” as before — without the need for globals. The enclosing function even does the work of instantiating the root node with the “new” keyword so that the end user doesn’t even need to (and shouldn’t!) say “new”.

Finally, there is a traversal function, and an expose function. The traversal function returns the node objects in an array following in the natural depth-first post-order described previously. The expose function is a debugging function which writes the output using “thoughts_write(<message>)” which wraps “document.write(<message>)”. You can change “thoughts_write(<message>)” to print output elsewhere using “document.getElementById(<some_identity>).innerHTML += (<message>)” where “some_identity” is the “id” of some element in your HTML. Without going into detail, the traversal function also uses an internal “ref” object which refers to the array as it is filled.

Some other things you can try…

The JavaScript recursive descent parser is actually a simplified version of something that I threw together earlier. The major difference is that I tag leaf nodes with fasta protein sequences by passing a reference to an associative array (or hash) as an argument to “tree_builder(<newick_string>, <fasta_hash>)”. Remember, in JavaScript, an associative array is an instance of an Object, not an instance of an Array. Using non-integer field names in an Array is actually not well defined but kind of sort of works semi-consistently between browsers (i.e. don’t try!), but that’s a story for another day. Whenever the name of a leaf is parsed, I would look it up in the hash and put it in a field either “this.left.fasta” or “this.right.fasta” thereby conferring to the leaf nodes of the in-memory structure the appropriate fasta protein sequence.

Lessons Learned

In putting this thing together, I managed to relearn JS, recursive descent parsing and making JS pass things by reference up and down a recursive stack of function calls. Andre Masella helpfully reminded me that I didn’t need to use any kind of BNF or LALR(1) parser — just an easy single-function parser would do. This is actually a port of a C# parser which does the same thing that I wrote in an earlier step for phylogenetic analysis — the difference being that C# offers a “ref” keyword that allows one to specify arguments in a function’s parameter list as emulated references (functionally equivalent to using C’s asterisk and ampersand convention though not operationally equivalent).

Happy parsing! The code presented should be easy enough to understand for you to port it into the language of your choice for whatever purposes you design.

URL mangling for HTML forms (a better Mediawiki search box)

with 3 comments

Followup: This is better than my previous Mediawiki search box solution because it doesn’t require an extra PHP file (search-redirect.php) to deploy. It relies completely on URL mangling inside the HTML form on the page you are putting the search box. Previous post here.

A valid HTML form input type is “hidden”. What this means is that a variable can be set without a control displayed for it in a form. Other input types for instance are “text” for a line of text and “submit” for the proverbial submit button — both of these input types are displayed. Variables set by the “hidden” input type are treated as normal and are shipped off via the GET or POST method that you’ve chosen for the whole html form…

So, to create the following mangled URL…

https://eddiema.ca/wiki/index.php?title=Special%3ASearch&search=searchterms&go=Go

There are the following variables … with the following values:

  • title … “Special%3ASearch” (%3A is the HTML entity “:”)
  • search … “searchterms” (the only variable requiring user input)
  • go … “Go”

The only variable that needs to be assigned from the form is “search” to which I’ve assigned the placeholder “searchterms” in the above URL.

The form thus needs only to take input for the variable “search” with a “text” type input, while “title” and “go” are already assigned– a job for the “hidden” type input.

Here’s what the simplest form for this would look like…

<form action="https://eddiema.ca/wiki/index.php" method="get">
Search Ed's Wiki Notebook:
<input name="title" type="hidden" value="Special:Search" />
<input name="search" type="text" value="" />
<input name="go" type="hidden" value="Go" />
<input type="submit" value="Search" />
</form>

Again, replace the text “Search Ed’s Wiki Notebook” with your own description and replace “https://eddiema.ca/wiki/index.php” with the form handler that you’re using– it’ll either be a bare domain, subdomain or could end with index.php if it’s a Mediawiki installation.

And that’s it! A far simpler solution than last time with the use of the “hidden” type input to assist in URL mangling.

Update: Here’s an even more improved version — this time, the end user doesn’t even see a page creation option when a full title match isn’t found. Demo (hooked up to my wiki) and Code below …





<form id="searchform" action="https://eddiema.ca/wiki/index.php" method="get">
<label class="screen-reader-text" for="s">Search Ed's Wiki Notebook:</label>
<input id="s" type="text" name="search" value="" />
<input name="fulltext" type="hidden" value="Search" />
<input id="searchsubmit" type="submit" value="Search" />
</form>

Notice that the variables “Special:Search” and “go” are not actually needed — instead, the variable “fulltext” is assigned the string “Search” — this causes mediawiki to hide the “You can create this page” option.

Eddie Ma

June 4th, 2010 at 8:39 am

Add an arbitrary Mediawiki search box anywhere!

without comments

Update: A better solution that doesn’t require a separate “search-redirect.php” file has been posted here.

I’ve been looking for this solution for a long time now and I’m happy to have finally found it. Following hints from Dave Taylor and Peter De Decker, I’ve glued together a solution that doesn’t take too much effort and doesn’t require any additional hacking around in SQL.

The objective was to add a search box on the right-column navigation of this blog that would search my wiki notebook. It wasn’t until I stumbled on the above two blogs that I realized I can just mangle URLs to conduct a search on mediawikis! The specific URL used to search my wiki looks a little like this…

https://eddiema.ca/wiki/index.php?title=Special%3ASearch&search=searchterms&go=Go

It might be a bit different for your installation depending on the version that you installed and a few of your settings– to find out what it looks like, search for something and copy down the URL in the address bar.

The file “search-redirect.php” used by Wikipedia takes in your search terms, and mangles those terms into a URL conforming to the above example. It then redirects you to that constructed URL. You can find this used on the main page of Wikipedia as noted by Dave.

My search-redirect.php based on Peter’s work above is two lines long, and looks like this:

<php?
$redirect_url =
     "https://eddiema.ca/wiki/index.php?title=Special%3ASearch&search=".
     $_GET['search'].
     "&go=Go";
@header( "Location: ".$redirect_url );
?>

You probably want to place your own search-redirect.php in the root directory of your wiki installation– however, it looks to me like it doesn’t really matter since the whole URL is rewritten anyway. I bet you can put this file anywhere on the net that supports PHP. The final thing that’s missing is the search box– anything that uses this formula will work:

<form action="https://eddiema.ca/wiki/search-redirect.php" method="get">
Search Ed's Wiki:
<input type="text" name="search" />
<input type="submit" value="Search" />
</form>

Putting this code on a page with your own wiki URL as a stem instead of mine will allow you to search your own wiki from any other page.

Eddie Ma

June 3rd, 2010 at 9:54 am

A Chess Post – S-Chess and Omega Chess

with 2 comments

Update: A link for Omega Chess, and a link for Seirawan Chess.

This is the first of a few posts I’d like to make about chess. In particular, this post is about two chess variants. Seirawan Chess (S-Chess) and Omega Chess. These two variants feature the familiar FIDE chess pieces along with two new pieces each. I’ll introduce each variant on their own first.

In Seirawan Chess, one starts with the familiar eight-by-eight board and opening array with the addition of two pieces set aside in reserve. These pieces are the Hawk and the Elephant. The Hawk is a Bishop and Knight compound while the Elephant is a Rook and Knight compound (a compound is a combination of pieces– a Queen is a Rook and Bishop compound). The two pieces that are set aside are placed onto the board when a player moves a piece from the back rank. The piece being dropped onto the board thus occupies the square in the back rank that has just been vacated. One can only place a single reserved piece in a given move. During a castle if the player so chooses, a reserved piece may be dropped on either the King’s or the Rook’s original square; it is not permitted to drop both reserved pieces during a castle.

In Omega Chess, one starts with a ten-by-ten board and an opening array that is flanked by the addition of a Champion and the Champion’s Pawn. The board is also extended diagonally by a single square in each of the four corners– these corner squares are occupied by a Wizard each. In the opening array, each piece is placed behind a Pawn with the exception of the Wizard. The Champion may move one step orthogonally, leap two steps orthogonally or leap two steps diagonally. The Wizard may move one step diagonally or leap (1, 3) — whereas a Knight leaps (1, 2). The Wizard is hence colour bound. The special corner Wizard squares are not actually special– they are just part of the board topology and can be used by all other pieces (except the Rook which cannot leap or slide diagonally into those spots).

For the fun of it, I have been playing Omega Chess with Seirawan Chess dropped pieces and it’s worked quite well so far. The size of the board accommodates well the Seirawan compounds. Additionally, I have been considering a house rule about dropping the Seirawan pieces– perhaps it shouldn’t be allowed that a dropped piece immediately defend the piece that dropped it. For instance, a Bishop dropping a Hawk makes for a very tough defense. A Wizard dropping a Hawk should be allowed however if the Wizard made its oblong (1, 3) leap.

If you see me walking around with a big black tube, I’m probably carrying this chess set. Challenge me to a game 😀

I’ll post some photos and such soon. The design of all the pieces from both sets is remarkably soothing and fits very well into the Staunton style. I was very lucky to discover that the Seirawan pieces are each appropriately tall compared to the Queen of the Omega Chess set I purchased.

One final thing– I decided to score the pieces in this combined game based on the mobility of each of the pieces on the ten-by-ten board. Here are my findings…

Score Piece Remark
29.40 Queen FIDE
23.76 Elephant Seirawan
18.00 Rook FIDE
17.16 Hawk Seirawan
11.40 Bishop FIDE
9.36 Champion Omega
8.28 Wizard Omega
6.84 King FIDE
5.76 Knight FIDE

The score is proportional to the total number of squares controlled by a piece calculated for every square it can occupy in the ten-by-ten grid. Aside from giving a general impression of how one would rank a piece against other pieces, there’s not really a lot that one can tell from this scheme. In this scheme, the Seirawan pieces rank high, and the Omega pieces rank low but only due to their finite ranges. Leapers’ attacks have the distinct advantage of being immune to blocking.

That’s all for now, back to work.

Eddie Ma

June 2nd, 2010 at 10:47 pm

The Computational Bio & Chem Group (SOLVER Revisited)

without comments

A Revisitation

In the beginnings of the Winter semester, I had an idea to start up a undergraduate/graduate student group that would provide a scaffold for faster, computer assisted research.

The semester was simply too full for me to try and get it running at that time. I’m tempted to do some work on it later this semester, after I’ve gotten more of my thesis done.

The basic idea is as follows. Faculty and graduate students in the biology and chemistry departments often have the need to analyze data with some elegant computing. Whether this be as commonplace as hacking together an excel sheet to do work or learning some existing toolbox, or something slightly more in depth such as analysis in R, Python or PERL. Unfortunately, these research problems often fall by the wayside as the time commitment to learn a new software package or programming language is not trivial without a stronger computing background. Undergraduate students who are raised in the computer science environment, particularly with a bioinformatics interest have some knowledge of the research problem semantics as well as some knowledge of how to do the above analysis by using and coding software.

The “SOLVER” group would fill the gap by performing a matchmaking and coaching service. In my vision, SOLVER creates working teams of three to four– (1) one or two graduate students or faculty with a research problem, (2) one or two undergraduate students with some knowledge in bio / chem and some talent in computing, (3) an experienced coach that can recommend best practices so that the team has a good shot of solve the problem in a reasonable amount of time. In the end, the researcher gets help and a good chance at a working solution– they might even learn some programming; educational / professional / social connections are made; and the student gets an item to add to their resume. In reality, a particular research step would be executed as week-long blocks– whether this means one block or four blocks (one month) depends on the complexity of the task.

To do…

One stretch of work that I have to do is to determine the needs of the department. I wanted to do this in the middle of Winter semester but didn’t find it a priority. For this group to work, there must be research problems. Similarly, I need to determine the capabilities of potential undergraduate students. I’m learning quickly that the key here is to start small and think big (i.e. start with one group, then two, then learn about the administrative logistics, then deploy some progress tracking mechanism, then four groups and onward).

Retuning the image

The almost idealized description above suffers from a few logistical issues. First, I will now address the issue of publication credits. Because researchers must attribute tangible work (including written code and analyses), some graduate students may be hesitant to participate in the program. I don’t know if this will actually become a barrier however as a “tangible contributor” would never be the first nor the last name on a paper (this is true in all CS, Bio and Chem). Furthermore, a paper with more than one author demonstrates the ability to collaborate in a team, and fostering the experience of another student is part of our culture (e.g. co-op students etc.). That brings me to a second major issue. One of the frames that this group could find itself in is a means to circumvent or short-circuit the co-op student appointment process– a frame that I readily reject. In fact, I should hope that this group becomes a means to introduce new putative co-op students to their future advisers which may otherwise be overlooked for their differing background. Finally, there is the problem of attrition, whereby a group dwindles in size as members drop out. The only contract-based perks or penalties I can think of is really ties to the group itself (e.g. unsatisfactory work naturally results in a time out or withdrawal from the program). It is really the only tangible leverage we can offer at the outset– unsteady leverage at best (difficult to assume a reputation when none has yet been built).

Going forward

More research has to be done in terms of polling and documenting the needs of the department. Furthermore, a deeper understanding about the kinds of students we’d attract and want to appoint is needed– this allows us to understand what time commitment is reasonable (both the lower and upper limits need definition). Finally, the group must from the outset be understood as something beneficial to all parties involved. The solutions named above must be deployed at launch time to ensure minimal friction, and maximum return. First steps were made last year by introducing this idea at the BIC-iGEM meeting– BIC students are excited with this idea, wherein an entire room of a dozen students raised their hands. Furthermore, there are no other groups on campus that attempt this activity, so that SOLVER would provide a unique non-conflicted service.

Of course– this all depends on the amount of work I get done on my own thesis in the first half of the semester.

Making friends

As an aside Isabelle Lam, a student I TA’d last semester in Biol-241 (microbio) has been planning on starting a job / volunteer / coop mine for science students. I should go and bother her and see how far she’s gotten. Her project is called “SPORE”. Last I checked, her team was registering a subdomain with the university.

EDIT: I previously confused Isabelle with Lisa– this has been corrected.

Eddie Ma

April 20th, 2010 at 10:08 am