Showing posts with label mathematics. Show all posts
Showing posts with label mathematics. Show all posts

15 February 2013

JSEN: JavaScript Expression Notation

That idea I was talking about yesterday? Storing mathematical expressions as JSON? I went ahead and made it as a TypeScript project and released it on GitHub:


JavaScript Expression Notation (JSEN)



Still need to complete the unit test coverage and add a couple more features. I made a change from my original post to the syntax for namespace references. (The reason? I realized I needed to be able to use "*" as a local identifier for multiplication.) They work within Namespace declaration blocks, but I need to make them work at the higher level of Namespaces declaration blocks as well. (Done.) I also want to allow functions to be used as namespaces. (Done.)

This is possible right now:

jsen.decl('my-fake-namespace', {
   'js': 'http://ecma-international.org/ecma-262/5.1',

   'x': 10,
   'y': ['js:Array', 1, 2, 3],
   'z': ['js:[]', 'y', 1]
});

jsen.eval('my-fake-namespace', 'x'); // 10
jsen.eval('my-fake-namespace', 'y'); // [1, 2, 3]
jsen.eval('my-fake-namespace', 'z'); // 2

jsen.expr('my-fake-namespace', 'x'); // 10 // Deprecated
jsen.expr('my-fake-namespace', 'y'); // Deprecated
    // ["http://ecma-international.org/ecma-262/5.1:Array", 1, 2, 3]
jsen.expr('my-fake-namespace', 'z'); // Deprecated
    // ["http://ecma-international.org/ecma-262/5.1:[]", "y", 1]

Eventually something like this will be possible as well:

14 February 2013

Mathematical expressions as JSON (and phyloreferencing)

For Names on Nodes I did a lot of work with MathML (specifically MathML-Content), an application of XML for representing mathematical concepts. But now, as XML wanes and JSON waxes, I've started to look at ideas for porting Names on Nodes concepts over to JSON.

I've been drawing up a very basic and extensible way to interpret JSON mathematically. Each of the core JSON values translates like so:
  • Null, Boolean, and Number values are interpreted as themselves.
  • Strings are interpreted as qualified identifiers (if they include ":") or local identifiers (otherwise).
  • Arrays are interpreted as the application of an operation, where the first element is a string identifying the operation and the remaining elements are arguments.
  • Objects are interpreted either as:
    • a set of declarations, where each key is a [local] identifier and each value is an evaluable JSON expression (see above), or
    • a namespace, where each key is a URI and each value is a series of declarations (see previous).

Examples

Here's a simple object declaring some mathematical constants (approximately):

{
    "e": 2.718281828459045,
    "pi": 3.141592653589793
}

Supposing we had declared some operations (only possible in JavaScript, since JSON doesn't have functions) equivalent to those of MathML (whose namespace URI is "http://www.w3.org/1998/Math/MathML"), we could do this:

{
    "x":
        ["http://www.w3.org/1998/Math/MathML:plus",
            1,
            2
        ],
    "y":
        ["http://www.w3.org/1998/Math/MathML:sin",
            ["http://www.w3.org/1998/Math/MathML:divide",
                "http://www.w3.org/1998/Math/MathML:pi",
                2
            ]
        ]
}

Once evaluated, x would be 3 and y would be 1 (or close to it, given that this is floating-point math).

Now for the interesting stuff. Suppose we had declared Names on Nodes operations and some taxa using LSIDs:

{
    "Homo sapiens": "urn:lsid:ubio.org:namebank:109086",
    "Ornithorhynchus anatinus": "urn:lsid:ubio.org:namebank:7094675",
    "Mammalia":
        ["http://namesonnodes.org/ns/math/2013:clade",
            ["http://www.w3.org/1998/Math/MathML:union",
                "Homo sapiens",
                "Ornithorhynchus anatinus"
            ]
        ]
}

Voilá, a phylogenetic definition of Mammalia in JSON!

I think this could be pretty useful. My one issue is the repetition of  long URIs. It would be nice to have a mechanism to import them using shorter handles. Maybe something like this?

{
    "mathml":   "http://www.w3.org/1998/Math/MathML:*",
    "namebank": "urn:lsid:ubio.org:namebank:*",
    "NoN":      "http://namesonnodes.org/ns/math/2013:*",

    "Mammalia":
        ["NoN:clade",
            ["mathml:union",
                "namebank:109086",
                "namebank:7094675"
            ]
        ]
}

Something to ponder. Another thing to ponder: what should I call this? MathON? MaSON?

27 February 2012

What Is Phylogenetic Nomenclature?

Sometimes when discussing the PhyloCode, I get the feeling a lot of potentially interested parties don't understand what phylogenetic nomenclature actually is. I have gone into excruciating detail on this topic elsewhere, but who wants to be excruciated? So here's a brief summary of the process of creating a phylogenetic taxonomy.

1. Declare Operational Taxonomic Units
Result: Alpha Taxonomy

The very first step is to decide what your units are. Are you dealing with individual organisms? Populations? Species? Which ones? Whatever you select, there should be an unambiguous way of referring to these taxonomic units (specimen numbers, species names, etc.).

Phylogenetic nomenclature is flexible as to how you determine and name taxonomic units. (Although the names must be relateable to those used in definitions [see Step 3].)

Example: My operational taxonomic units are the whale species Aetiocetus cotylalveusBalaena mysticetus, Balaenoptera physalus, Delphinus delphis, and Monodon monoceros.

Operational Taxonomic Units
Silhouettes by Chris huh and T. Michael Keesey, taken from PhyloPic.
Image license: CC-BY-SA 3.0

14 December 2010

pymathema, a Python tool for evaluating MathML

Lately I've been learning the programming language Python, and I've really been enjoying it. In particular, as a dynamic language (i.e., having loose types), it's really well-suited for mathematical tools. (Having sets and tuples as native types doesn't hurt, either.)

I started creating a MathML-Content evaluator in Python, with an extension for Names on Nodes which implements phyloreferencing expressions. As part of this I am working on Version 2.0 of the Names on Nodes MathML Definitions, which will expand upon the current ones.

Basic functionality is pretty much complete, although there are some niceties to add. If you'd like to check it out and maybe collaborate, have a look here: PYMATHEMA.

27 May 2010

Upcoming Names on Nodes Presentation

I'll also be presenting Names on Nodes at iEvoBio, at the Software Bazaar on June 29. Here's the abstract:

Names on Nodes: Automating the Application of Taxonomic Names within a Phylogenetic Context

Names on Nodes1 is an open-source2 Flex application which utilizes a mathematical approach to automate the application of phylogenetically-defined names to phylogenetic hypotheses. Phylogenetic hypotheses are modeled as directed, acyclic graphs, and may be read from bioinformatics or graph files (Nexus, NexML, Newick, and GraphML) or created de novo. Hypotheses may also be merged from multiple sources. Names on Nodes stores hypotheses as MathML, an XML-based language for representing mathematical content and presentation. Phylogenetic definitions may be constructed using a visual editor and exported in MathML. Thus, it is possible to create a dictionary of defined names and automatically apply them to phylogenetic hypotheses. In the current version of the application, such dictionaries exist only as MathML files, but in future versions definitions may also be loaded from databases (e.g., RegNum).

Additional functionality in Names on Nodes includes the ability to coarsen a phylogenetic graph (thereby simplifying it while still reflecting the overall structure) or to export it as an image file (raster or vector, potentially with semantic annotations).

  1. Source code available at: http://bitbucket.org/keesey/namesonnodes-sa/
  2. MIT license
I have my work cut out for me....

26 May 2010

Upcoming Talk: Toward a Complete Phyloreferencing Language

I'll be giving a “Lightning Talk” (five minutes) at the iEvoBio Conference in Portland, Oregon. Here's the abstract:

Toward a Complete Phyloreferencing Language

A phyloreference is a statement indicating a taxon within a phylogenetic context. A common use for phyloreferences is in phylogenetic definitions, which tie taxonomic names to taxa via such statements. Several conventions for writing phyloreferences have been proposed, but most only cover a few “standard” forms (node-, branch-, and perhaps apomorphy-based clades) without the capacity to represent more “exotic” forms (e.g., ancestor-based clades and qualified/modified references). In order to build a complete phyloreferencing language, the mathematical underpinnings of phylogenetic contexts must be clarified. A phylogenetic context may be modeled as a directed, acyclic graph, wherein nodes model taxonomic units and directed edges model immediate descent. Higher taxa are modeled as unions of nodes. A phyloreferencing language must minimally allow for certain classes of entity: Boolean values, sets (including taxa, relations, and the empty set), and lists (including graphs and functions). It must also minimally allow for basic operations related to logic, set theory, and graph theory. Higher structures such as declarations and piecewise constructs must also be possible. With these as a basis, functions related to phylogeny can be defined: maximal, minimal, predecessor union/intersection, successor union/intersection, exclusive predecessors, synapomorphic predecessors, clade, crown clade, and total clade. I show how such a language may be used to represent various types of phyloreference, both “standard” and “exotic”.


Now to figure out how to condense that into a five-minute talk....

21 May 2010

Names on Nodes Issue Tracker

Yesterday I transferred the list of remaining Names on Nodes issues from my whiteboard to the bitbucket issue tracker. My goal is to get through most of these by the end of June. (Some "nice-to-haves", like DOT or HTML 5 exporting, may have to wait.)

Essential features left to implement, complete or fix:

FILES AND FORMATS

  • Certain formats for import, especially NexML and NEXUS. (Currently only Newick can be imported. MathML files can be loaded as well.)
  • Certain formats for export, especially NexML. (Currently only PNG can be exported. MathML files can be saved as well.)
  • Ability to save just the definitions or just the phylogeny to a MathML file.
  • Ability to import definitions from a MathML file.
  • MathML tweaks. (Use csymbol instead of ci for taxa. Normalize presentation.)
  • Ability to write in Newick strings directly.
DISPLAY
  • Skin various components (sliders, steppers, checkboxes, etc.).
  • Fix line breaks in MathML formulas.
  • Various scrollbar issues.
  • Special character issues.
NAMES
  • Rich editor for taxon labels, including ability to edit taxon URIs.
NODES
  • Arc bisection tool.
  • Fix node merging (i.e., synonymization).
  • Add ability to select definition type when creating a name.
  • Node Pane Control Bar revisions. (Change Resolution Slider to a stepper. Add Zoom Slider.)
DEFINITIONS
  • Definition Editor tweaks/fixes. (Some actions are blocked that should be possible. Textual Editor does not always update. Various layout issues.)
OTHER
  • About/Help Panel.

09 April 2010

Biota: Another Example of Coarse vs. Fine Phylogenies

Yesterday I posted an example of how graph-coarsening algorithms can be used to make the high-level patterns of a phylogeny more immediately visible. That example used a phylogenetic hypothesis about placental mammals. The hypothesis involves a lot of nodes (i.e., taxonomic units), but not much branching complexity. By which I mean each node has only a single parent.

So here's an example where nodes may have multiple parents. This is a phylogeny of Biota, i.e., Life:


Eukaryotes (organisms with cellular nuclei, i.e., plants [Embryophyta, etc.], animals [Metazoa], fungi [Eumycota], and "protists") have been highlighted in yellow. Some nodes have multiple parents due to one of two phenomena:

  • Lateral transfer. Many organisms (especially bacteria) are capable of acquiring genetic material from unrelated organisms.
  • Endosymbiosis. Some organisms have evolved into organelles within the cells of other organisms, notably mitochondria (descended from proteobacteria related to those that cause rickets) and plastids (photosynthesizing organelles in plants, descended from cyanobacteria). In these cases, the organelle often retains its own DNA, although much of it may have leapt over to the "host's" nuclear DNA. In some cases, all of it may have leapt over (as with mitochondria descendants like mitosomes).
Both lateral transfer and endosymbiosis are considered valid forms of descent in this hypothesis.

Here's the graph coarsened one step:

We can see the general patterns more clearly here. Eukaryotes share a relationship with archaeans, but also have descent from proteobacteria (via mitochondria). One clade of eukaryotes (Plastida) is also descended from a basal form of cyanobacteria (via plastids). A few cases of lateral transfer are visible, but not in detail. We can also see there there is a lot of bacterial diversity, although the details are not spelled out.

Here's the graph coarsened another step:


The endosymbiosis is made even clearer, although most other relationships are obscured.

Disclaimer: This hypothesis was cobbled together from a number of sources and does not represent any rigorous research on my part. I suspect parts of it are outdated, but this area of the Tree of Life is not my bailiwick. I just wanted to throw something together for a demonstration.

08 April 2010

Viewing Phylogenies at Different Graph Resolution

Although I've been primarily reining in features on the next version of Names on Nodes, there was a new feature I couldn't resist adding. I think it's coming along pretty well.

A common problem with working with phylogenies is that many of them are gigantic, far too big to view all at once. As an example, consider Figure 1 from Beck et al. (2006). It models a hypothesis about placental mammal phylogeny, at an arbitrary resolution ("family-level"). Here's how the current version of Names on Nodes renders it:


When you look at it "zoomed out", it's almost impossible to know what's going on. When you look at it full size, you can see various local areas, but you lose a sense of what's going on with the larger image. Note that I've highlighted our own species' twig on the tree (Hominidae, the great ape clade) in yellow.

Earlier I used the term "resolution" to refer to the size of the graph's nodes. We can refer to a graph with very small nodes (e.g., each node representing an individual organism) as being "fine" and a graph with very large nodes (e.g., "class-level") as being "coarse". Thinking about the problem from this angle, I had the idea to create a control for coarsening or refining the viewed graph.

I implemented a simple graph-coarsening algorithm*, and then created an algorithm for picking the best name for the new, coarser graph's nodes. And here is the phylogeny at near-maximum coarseness:


This is placental phylogeny boiled down to its basics: rodents, laurasiatheres, and a bunch of other junk (including us). The node labelled "Placentalia*" contains the placental ancestor but not all descendants—it lacks an unnamed clade included most non-afrothere placentals. The unnamed greenish node includes all members of that unnamed clade except for rodents and laurasiatheres. (This happens to include Hominidae, which is why it has that greenish color.)

Let's refine it one step:


We're starting to get a better idea of the hypothesis. Finer:


Now we can see the basal split between afrotheres and other placentals, as well as developing complexity in Rodentia and Laurasiatheria. Finer:

Getting a little bit on the big side, now, but we can see more details. There are a lot of unnamed clades within Hystricoidea and Chiroptera—we can see that those clades are diverse, although we can't see details. Finer:
This has about 2/5 as many nodes as the base graph. It's a bit large, but still much easier to view than the base graph. Many important details are visible (e.g., the platyrrhine-catarrhine split), while others are just suggested (e.g., lots of diversity in Caviomorpha).

Obviously this works best if lots of clades have been named. I think it'll be a useful for boiling a phylogeny down to an appropriate level: coarser for quick overviews, finer for in-depth discussion.



* Basic summary of the coarsening algorithm:
  1. Look through all nodes that have children, and find the ones whose children are all terminal (sinks).
  2. Merge each of those nodes with their children to create a "supernode".
  3. Merge all overlapping supernodes. (This is important for graphs where nodes may have multiple ancestors, although it doesn't come into play in this example.)
  4. Remove the supernodes from the graph and repeat from step 1. Keep going until no nodes are left.
  5. Add the supernodes to a new graph. A supernode is ancestral to another supernode if any of its subnodes are ancestral to any of the other supernode's subnodes.

02 April 2010

Names on Nodes: MathML Definitions (Version 1.2)

After the epiphany that Names on Nodes did not have to be associated with a database, I set to work creating a "standalone" version of the application. Progress has been pretty good, and if you are interested in the details (or collaborating), you can check the project out at its new home on Bitbucket (which also houses the related project, ASMathema).

I've just updated the Names on Nodes website based on these revisions to the project, most notably the MathML Definitions document. Most of the changes have actually been removals: no more mentions of rank-based taxonomy (which may be covered in future versions but not in this one), qualified names as taxonomic identifiers (no longer a necessary feature), etc. So if you didn't read it before because it was too long and dense ... well, it's still pretty long and dense, actually. But less so!

I've also added an example MathML document as a supplement. This document:
  1. Defines a phylogenetic context (the same one used in the MathML Definitions examples), arranging taxonomic units as vertices in a directed, acyclic graph.
  2. Defines sets based on characters ("wings used for powered flight" and "extant")
  3. Refers a specimen (YPM-VP 1450) to a taxonomic unit (Ichthyornis).
  4. Equates several species names as synonyms.
  5. Defines some hybrid formulas as referring to specific taxonomic units.
  6. Defines a number of clade names.
This file can be opened with Names on Nodes: Standalone Version, which I am currently developing and hope to release this year.

27 February 2010

Defining Rank-Based Taxa Mathematically

Let U be the set of all individuals.

Let ranks be represented by a contiguous series of natural numbers (). Let 1 represent the lowest (finest) rank and let some natural number n represent the highest (coarsest) rank.

Let T be a sequence of n sets of type individuals (i.e., individuals represented by type specimens). Let each set in the sequence (other than the last set) be a superset of the next set, i.e., T1 ⊇ T2 ⊇ … Tn.

Let d be a metric function measuring some distance between any two individuals: d(x, y) ∈ ℝ0+ (the set of nonnegative real numbers). Note that, because it is a metric, d(x, x) = 0 and d(x, y) = d(y, x).

For each rank level r, let pr be a function mapping each member, t, of Tr to a taxon (set of individuals): pr(t) := {x ∈ U | for all s ∈ Tr, d(x, t) ≤ d(x, s)}. Let Pr be the image of pr. Then Pr is the taxonomy of rank level r.

Note that some individuals may be placed in multiple taxa of the same rank if they are equidistant between type individuals. These individuals may be considered unclassifiable for that rank. Let U′ be the set of all individuals except for those which are unclassifiable for some rank. Similarly, let P′r be Pr but with all unclassifiable individuals removed from each member taxon. P′r is a partition on U′. For any two rank levels q and r, if q < r, then P′q is a refinement of (or equal to) P′r.

25 February 2010

Tricksy Definitions Expressed Mathematically

Just for fun, here are a few definitions of nonstandard type to go along with those in the previous post. As any practitioner of phylogenetic nomenclature knows, most definitions are node-, branch-, or apomorphy-based, but there have been a few that don't fall into these categories.

Here are Wagner's (2004) definitions of Panbiota and Biota:

   Panbiota := (Cladeprc)(Homo sapiens).

   Biota := Crown(Panbiota, "extant as of or after 2004").

This is one of the few cases where it makes more sense to define the crown clade based on the total clade rather than vice versa. (Maybe the only case? Not sure.) Technically, Wagner's wording for the definition of Panbiota might be better translated as (sucminprc)(Homo sapiens), but it works out to the same thing.

And here's Clarke's (2004) definition of Ichthyornis:

   Let M := "apomorphy 2" ∩ "apomorphy 5" ∩ "apomorphy 6" ∩ "apomorphy 7" ∩ "apomorphy 8".
   (These refer to apomorphies in Clarke's Ichthyornis dispar Diagnosis.)

   Ichthyornithes := Clade(YPM 1450 Struthio camelusTinamus majorVultur gryphus).
   ("YPM" refers to the Yale Peabody Museum's Vertebrate Paleontology collection. YPM 1450 is the Ichthyornis dispar holotype specimen.)

   Ichthyornis := Clade((M @ YPM 1450) ∩ Ichthyornithes).

Names on Nodes: MathML Definitions (Version 1.1)

After posting Version 1.0 earlier this week, I had a revelation: the cladogen functions are completely unnecessary, and everything would work a lot nicer if I just tossed them. I also realized that there really was no reason I couldn't include the various relations (precedence, immediate precedence, proper precedence, etc.), just in case anyone wanted to do some seriously non-standard definitions. After some significant revisions, I present Version 1.1.

Some examples of the updated notation, using humans (Homo sapiens), platypuses (Ornithorhynchus anatinus), and Dimetrodon grandis, a stem-mammal:

Union. Homo sapiensOrnithorhynchus anatinus = all humans and all platypuses (polyphyletic taxon, also monothetic)

Exclusive Predecessors. Homo sapiensOrnithorhynchus anatinus = humans and all of their ancestors, except for the ancestors shared with platypuses (lineage)

Synapomorphic Predecessors. "milk glands" @ Homo sapiens = humans and all human ancestors to possess milk glands synapomorphic with those in humans (lineage)

Node-Based Clade. Clade(Homo sapiensOrnithorhynchus anatinus) = Mammalia

Branch-Based Clade (simple). Clade(Homo sapiensOrnithorhynchus anatinus) = "Pan-Theria"

Branch-Based Clade (multiple external specifiers). Clade(Homo sapiensOrnithorhynchus anatinusDimetrodon grandis) = "Pan-Theria"

Branch-Based Clade (multiple internal specifiers). Clade(Homo sapiensOrnithorhynchus anatinusDimetrodon grandis) = (unnamed clade comprised mostly of Therapsida)

Null Branch-Based Definition (multiple internal specifiers). Clade(Homo sapiensDimetrodon grandisOrnithorhynchus anatinus) = ∅

Apomorphy-Based Clade. Clade("milk glands" @ Homo sapiens) = "Apo-Mammalia"

Node-Modified Crown Clade. Crown(Homo sapiensDimetrodon grandis, "extant as of or after 2010") = Mammalia

Branch-Modified Crown Clade. Crown(Homo sapiensOrnithorhynchus anatinus, "extant as of or after 2010") = Theria

Apomorphy-Modified Crown Clade. Crown("milk glands" @ Homo sapiens, "extant as of or after 2010") = Mammalia

Total Clade. Total(Mammalia, "extant as of or after 2010") = Synapsida (or "Pan-Mammalia")

Image showing a node-based clade (Mammalia) under a given phylogenetic hypothesis. Click to enlarge. More here.

21 February 2010

Names on Nodes: MathML Definitions (Version 1.0)

I've just posted version 1.0 of the MathML definition for Names on Nodes. This document provides the foundation for the mathematical entities and operations in Names on Nodes. Previously I had posted an incomplete draft version—this is the first complete version, and also the first version with illustrations. It won't be the last version, but it (or a slightly edited version) will be associated with the first release of Names on Nodes.

This document refines and rectifies concepts laid out in my 2007 paper. It's an important milestone to completing Names on Nodes, a project I've been working on for almost six years.

One of the illustrations, showing how the Clade function works.

23 July 2009

Two "Names on Nodes"-Related Launches

I'm still a clear way away from launching the beta application, but I've just made a couple of launches related to my long-time work-in-progress, Names on Nodes.

First up, and probably of more interest to most people, I've begun the documentation for the MathML definitions used by Names on Nodes. The document includes general reviews of relevant mathematical and biological concepts, a quick review of MathML and the technologies it's based on, some comments on correlating mathematical and biological concepts, and definitions for all entities (including operations) used by Names on Nodes. Note that this covers a lot of the same ground as in my 2007 paper, with a few minor changes in the symbols and terminology (e.g., I now call the ancestor of a clade a "cladogen" rather than a "cladogenetic set").

Secondly, I've made the project open-source, by moving it to Google Code. If you are a developer interested in checking this out, go here. It's incomplete, so I don't know if anyone will have any real interest in looking at it yet. (Honestly, I mostly posted so that, on the off chance that I unexpectedly kick the bucket, my magnum opus won't be lost forever.)

This information is also on the new Names on Nodes home page.

01 February 2009

Taxa Without Organisms?

In my 2007 paper, I built up an array of phylogenetic operations (precedence, parentage, minimal, maximal, all descendants, common ancestors, synapomorphic ancestors, clade, node-based ancestors, crown, etc.) relying on these definitions/assumptions:
  1. Organisms are discrete units.
  2. Ancestry can be encapsulated as discrete relations.
  3. Taxa are sets of organisms.
Although I argued for this discrete, organism-level approach (pp. 608–609), there are certain problems with it.

Organisms are discrete units.

This works well enough for the organisms I tend to focus on (amniotes). But there are many cases where it's not clear. Is a slime mold growth a multicellular organism, or is it a colony of unicellular organisms? Are plastids and mitochondria separate organisms, or organelles that are descended from other organisms? Is a lichen a mutualistic association of organisms, or one composite organism? Is a Portuguese Man o'War a colony of individuals, or a superorganism made up of zooids? What about an ant colony? And are viruses organisms?

Apart from these problems of interpretation, there's also a problem to do with taxonomic conventions. Basically, there's no common method in taxonomy to denote an individual organism. The closest thing we have is specimen identifiers, but, as I pointed out in the paper, this is really just another way of indicating a taxon, since a specimen may represent any number of organisms: "An individual organism may have multiple specimens which represent it (e.g., an organism may have several parts catalogued as different specimens), or a specimen may represent no organism (e.g., a mineralogical sample) or multiple organisms (e.g., a microbe slide)." (p. 612)

Ancestry can be encapsulated as discrete relations.

Again, this works well enough for many taxa, but it's problematic elsewhere. Is lateral transfer among bacteria a form of ancestry? What about transfer of mitochondrial genes to the nucleus? Gene-splicing? Introgression of viral DNA?

Taxa are sets of organisms.

How can this be, if there is no such objective unit as "the organism"? And how can phylogenetic taxa be based on ancestry if there is no single objective definition for "ancestry"?

A solution?

I hinted at an escape route for some of these problems in a parenthetical note: "It should be noted, however, that the methods presented here will work for any type of entity which has parents and/or children. Thus, they may be applicable to some types of ‘population-level’ organism groupings." (p. 609; emphasis added)

Basically, it doesn't matter what the units are. Taxa are sets. It doesn't matter if the units are genes, genomes, organisms, colonies, populations, or whatever. Taxa can still overlap, be disjoint, include each other, or be identical to each other.

This still leaves the difficulty of what, exactly, "ancestry" is. You can say that all members of taxon A are ancestral to all members of taxon B, but what exactly does that mean? Clearly it has something to do with the replication of the discrete molecular patterns in genetic material, but can it be stated explicitly and objectively? I'm not sure. For now, the only solution I can offer is to let that be a taxonomic decision—the only taxonomic decision you have to make when applying phylogenetic nomenclature.

08 January 2009

Using SQL to make phylogenetic queries

"Computer, can any dinosaurs fly?"

It would be great if we could ask computers questions this easily. Unfortunately, computers lack our natural linguistic skills. But this doesn't mean they are incapable of answering such questions—the questions just need to be rephrased.

SQL (pronounced either as "S.Q.L." or "sequel", and standing for "Structured Query Language") is the most commonly-used language for querying relational databases. This past week I have been adapting the phylogenetic operations in my 2007 paper into SQL (specifically the PostgreSQL version) as part of my Names on Nodes project. There have been a few difficulties to do with the fact that the database only records taxa (sets of organisms), while my published algorithms work at the organism level. But this is a minor difficulty so far, and things seem to be working.

To get an idea of how the system works, let's look at the question posited at the beginning of this post. How can the question be translated into a SQL query?

First, a quick summary of what's in the database: taxa (sets of organisms) of all kinds are represented by a table of "signifiers". Each signifier references an "authority", which could be anything from a publication to a nomenclatural code to a systematics dataset to a personal opinion. Each signifier also has a name which is unique under that authority. For example, under the authority of the International Code of Zoological Nomenclature (ICZN for short), the name "Homo sapiens" signifies a particular taxon (a species). Under the authority of the Yale Peabody Museum's Vertebrate Paleontology collection, the name "1450" refers to a specimen, and by proxy the set of organisms (in this case, just one) which that specimen represents. Under the authority of a particular NEXUS file, "data/flight/present" may refer to a character state, and by proxy the set of all organisms exhibiting that state.

Each authority is represented by one or more Universal Resource Identifiers, or URIs. Website addresses (URLs) are one kind of URI, so, for example, the Yale Peabody Museum's Vertebrate Paleontology collection can be represented as http://www.peabody.yale.edu/collections/vp. ISBN numbers are another type of URI, so the ICZN can be represented as urn:isbn:0853010064. Systematics files are a little trickier; my current solution is to use a custom schema and a unique "hash" string of characters programmatically derived from the data in the file, e.g., something like biofile:08192A3 (actually longer, but I'll keep it short for this discussion).

Each signifier can be represented as a "qualified name" (or "QName"), which combines the authority's URI and the signifier's name. Examples:
  • http://www.peabody.yale.edu/collections/vp::1450
  • urn:isbn:0853010064::Homo_sapiens
  • biofile:08192A3::data/flight/present
(A fuller discussion of the Names on Nodes database can be found in this earlier post.)

Definitions may be stored as MathML, as indicated in my 2007 paper. Let's suppose that someone defines Dinosauria as, "the final common ancestor of Megalosaurus bucklandii von Meyer 1832, Hylaeosaurus armatus Mantell 1833, and Iguanodon bernissartensis Boulenger in Beneden 1881, plus all descendants of that ancestor." This can be rendered as:

<apply xmlns="http://www.w3.org/1998/Math/MathML">
<csymbol definitionURL="http://namesonnodes.org/phylo/math​::nodeClade"/>
<csymbol definitionURL="urn:isbn:0853010064​::Hylaeosaurus_armatus"/>
<csymbol definitionURL="urn:isbn:0853010064​::Iguanodon_bernissartensis"/>
<csymbol definitionURL="urn:isbn:0853010064​::Megalosaurus_bucklandii"/>
</apply>

Basically, this means, "Apply the nodeClade function to the the union of the signified taxa." The nodeClade function corresponds to the phrase, "the final common ancestors and all descendants thereof". It relies on three other phylogenetic functions: allDescendants, maximal, and commonAncestors. ("Maximal" in this context means "all members of a set which are not ancestral to any other members in that set"—a more precise way to say "final".)

Names on Nodes will take a MathML definition like this and convert it into a SQL query like this:
  SELECT * FROM node_clade(
ARRAY(SELECT * FROM resolve_signifier_identities(
ARRAY[
'urn:isbn:0853010064::Hylaeosaurus_armatus',
'urn:isbn:0853010064::Iguanodon_bernissartensis',
'urn:isbn:0853010064::Megalosarus_bucklandii'
])),
0);
The resolve_signifier_identities function converts an array of qualified names into a set of identity numbers corresponding to signifiers, using a query like this:
  SELECT identity_id
FROM signifier
WHERE qname = ANY(qname_list);
This is a relatively simple SQL query. The grammar is fairly intuitive (at least for a computer language). The query for the node_clade function is far more complex, though. To discuss that, I'll have to go into the database structure a bit more.

A phylogenetic definition cannot be applied without some kind of phylogenetic hypothesis. Names on Nodes is capable of reading phylogenies encoded as Newick trees, including those in NEXUS files. Let's suppose someone uploaded a NEXUS file with this Newick tree in it:

((Iguano_bern, Hylaeo_arma), (Megalo_buck, (Tyrann_rex, (Anas_plat, Passer_dome))))

Let's suppose the URI for this file is biofile:08192A3. Then this file authorizes some new signifiers:
  • biofile:08192A3::taxa/Iguano_bern
  • biofile:08192A3::taxa/Hylaeo_arma
  • biofile:08192A3::taxa/Megalo_buck
  • biofile:08192A3::taxa/Tyrann_rex
  • biofile:08192A3::taxa/Anas_plat
  • biofile:08192A3::taxa/Passer_dome
These can be objectively equated with other signifiers:
  • urn:isbn:0853010064::Iguanodon_bernissartensis
  • urn:isbn:0853010064::Hylaeosaurus_armatus
  • urn:isbn:0853010064::Megalosaurus_bucklandii
  • urn:isbn:0853010064::Tyrannosaurus_rex
  • urn:isbn:0853010064::Anas_platyrhynchos
  • urn:isbn:0853010064::Passer_domesticus
(The last two could conceivably be equated with vernacular names from a field guide as well, e.g., urn:isbn:0679428518::Mallard and urn:isbn:0679428518::House_Sparrow, respectively) Equated signifiers share the same identity. This file also authorizes some less visible signifiers: the hypothetical ancestors, such as the ancestor of Iguano_bern and Hylaeo_arma, the ancestor of Anas_plat and Passer_dome, etc. Names on Nodes assigns these ancestors arbitrary, numerical names.

The phylogeny in the Newick tree can be represented as a set of arcs, each pointing from a parent signifier (or "head") to a child signifier (or "tail"):
  ~1 → ~2
~1 → ~3
~2 → Iguano_bern
~2 → Hylaeo_arma
~3 → Megalo_buck
~3 → ~4
~4 → Tyrann_rex
~4 → ~5
~5 → Anas_plat
~5 → Passer_dome
These get stored in the database as rows representing parentage relations. Similar relations are used for supersets and subsets (e.g., to indicate that Tyrannosaurus includes Tyrannosaurus rex). Phylogenetic functions, such as maximal, all_ancestors, and common_ancestors, utilize the data in these relations.

Some of these functions use another function called find_parentage_arcs to get a list of all parent-child relations which involve any of a given set of signifiers. For example, maximal uses a query like this:
  SELECT id
FROM signifieridentity
WHERE id = ANY(identity_list)
EXCEPT
SELECT arc.head
FROM find_parentage_arcs(identity_list, context_id)
AS arc;
In other words, select all signifier identities from a given list, except those which are the parent (head) in any parent-child arc whose parent and child are in that list. (The context_id variable specifies which datasets to use and which to ignore, but that's an essay unto itself.)

The node_clade function uses a query like this:
  SELECT * FROM all_descendants(ARRAY(
SELECT * FROM maximal(ARRAY(
SELECT * FROM common_ancestors(identity_list,
context_id)),
context_id)),
context_id);
In other words, select all descendants/members of all maximal members of the common ancestors of the specified signifiers. (Again, context_id specifies which datasets to use; a value of zero means that all datasets should be used.)

Running the Dinosauria SQL query mentioned earlier will now yield a set including all of the signifiers mentioned so far. In other words, according to the provided definition and the provided phylogenetic hypothesis, I. bernissartensis, H. armatus, M. bucklandii, T. rex, A. platyrhynchos, and P. domesticus are all members of Dinosauria (as are the hypothetical ancestors in the phylogenetic tree).

Suppose the aforementioned NEXUS file also had a character matrix including the character "flight". This would be scored as "present" in Anas_plat and Passer_dome. Thus, the table of inclusions would include these arcs:
  flight/present → Anas_plat
flight/present → Passer_dome
(Names on Nodes also extrapolates the arc flight/present → ~5, but, again, that's another essay.)

A function called subsets retrieves all signifiers indicated as subsets of a given signifier. Thus, the question that began this essay can be written in SQL as:
  SELECT COUNT(dinosaur) > 0 AS verdict
FROM node_clade(
ARRAY(SELECT * FROM resolve_signifier_identities(
ARRAY[
'urn:isbn:0853010064::Hylaeosaurus_armatus',
'urn:isbn:0853010064::Iguanodon_bernissartensis',
'urn:isbn:0853010064::Megalosarus_bucklandii'
])),
0) AS dinosaur
JOIN subsets(
resolve_signifier_identity(
'biofile:08192A3::data/flight/present'
),
0) AS flier ON dinosaur = flier;
The verdict: true.

10 November 2008

Names on Nodes: Entities

Here's a UML diagram of the latest class schema for the core Names on Nodes entities:

The white arrows indicate inheritance, i.e., "is-a" relationships. For example, a PhyloDefinition is a type of Definition. The black diamonds indicate composition, i.e., "has" relationships. For example, a Definition has any number of Anchor entities, each of which has exactly one Signifier entity.

Some comments on the major classes of entity:

Signifier.—This is what everything revolves around. A Signifier signifies a set of organisms, that is, a taxon. Signifier entities may be scientific names, specimens, character states, or taxonomic units in systematic studies.

Several Signifier entities may share the same SignifierIdentity, indicating that they are different ways of referring to the exact same thing. For example, Felis leo (ICZN) and Panthera leo (ICZN) are objective synonyms. (Subjective synonyms do not share the same identity.)

Authority.—Every Signifier is unique within an Authority. Authority entities may be publications, nomenclatural codes, personal opinions, specimen repositories, or bioinformatics files. Every Authority is associated with a unique URI (e.g., a web address, a DOI, an ISBN number, etc.).

Like Signifier entities, different Authority entities may share an identity (AuthorityIdentity). These Identity entities are hidden from other entities, so that Authority and Signifier entities can be equated or differentiated without affecting other entities in the database.

Relator.—A Relator is a set of Relation entities, each of which represent a statement about two Signifier entities, either Inclusion (i.e., a is a superset of b) or Parentage (i.e., a is immediately ancestral to b).

Definition.—A Definition defines a Signifier according to an Authority, and may have any number of Anchor entities, each of which tells whether a given Signifier is objectively a subset of the defined Signifier.

RankDefinition.—A RankDefinition consists of a rank and some number of internal Anchor entities. For example, under the ICZN (an Authority), Hominidae (a Signifier) is defined as the family (a rank) typified by Homo (a Signifier referenced by an internal Anchor).

PhyloDefinition.—A PhyloDefinition consists of a formula, expressed prosaically and mathematically. For example, according to Gauthier & de Queiroz 2001 (an Authority), Aves ( a Signifier) is defined as, "the crown clade stemming from the most recent common ancestor of Ratitae (Struthio camelus Linnaeus 1758), Tinamidae (Tetrao [Tinamus] major Gmelin 1789), and Neognathae (Vultur gryphus Linnaeus 1758)." This Definition is specified by three internal Anchor entities, respectively referencing the species Struthio camelus, Tetrao major, and Vultur gryphus (all of which are Signifier entities).

Dataset.—The relations in a Dataset are based on observation or hypothesis. A Dataset entity's Authority may be a bioinformatics file, a publication, or a personal opinion. As with Signifier entities, every Dataset can be uniquely identified by a qualified name, combining the URI of its Authority and a local name.

Context.—Applying phylogenetic definitions requires a Context, which is essentially a set of Dataset entities. All Definition and DefinitionApplication entities are implicitly included under every Context.

DefinitionApplication.—This is sort of the crux of the whole idea behind this project: that a PhyloDefinition can be automatically applied under a given Context.

17 August 2008

Sets for ActionScript

It's been a busy couple of months!

One of the things keeping me busy is, of course, Names on Nodes, the web application I am developing that will automate phylogenetic nomenclature. As part of that project, I have developed a mathematics package that I would eventually like to release as its own package. One class, however, is so useful that I have decided to jump the gun and offer it on its own.

We (ActionScript programmers) all know how useful the Array class is. It can be used to store a sequence of anything, so it can be repurposed as a list, a vector, an edge—all manner of collections.

Well, not all manner of collections. Just ordered collections that allow duplicate elements. What if you want a set: an unordered collection with no duplicates? I find I need sets all the time, but I have to use arrays. And arrays are not optimal for looking up an element's membership, or preventing duplication. As lists they're great, but as sets they suck.

For a while I used a class I'd made called ArraySet that wrapped an array, but this was only an improvement in API, not in performance. Then I took a cue from Java and created: HashSet.


The HashSet class wraps a Dictionary object, which it uses as a hash table. If an element belongs to the set, then that element is a self-referential key in the dictionary. If it doesn't, then there is no such key in the dictionary. And HashSet extends Proxy, so you can use bracket notation for many operations,. You can also use for..in and for each..in loops.

Here's a quick example:


// Create and populate the set.
var s:HashSet = HashSet.fromObject([1, 2, 3]);

trace(s.size); // 3
trace(s[1]); // 1
trace(s[2]); // 2
trace(s[0]); // undefined
trace(s.has(1)) // true

// Trace all elements of the set.
for each (var i:int in s)
{
trace(i);
}
// Trace all elements of the set (different method).
for (var x:* in s)
{
trace(x);
}

trace(s); // {1, 2, 3}
s.add(1);
trace(s); // {1, 2, 3}
s.add(4);
trace(s); // {1, 2, 3, 4}
s.remove(1);
trace(s); // {2, 3, 4}
delete s[2];
trace(s); // {3, 4}
s[3] = undefined;
trace(s); // {4}


...and so on. Full documentation is in the class itself, so you can figure out the details for yourself. I will mention that HashSet also has a number of functions in common with Array (every, filter, forEach, map, some) and others that are unique to sets (get empty, diff, intersect, prSubsetOf, subsetOf, union). It also has a few functions that Array really ought to have (clone, equals, remove).

Download it and try it! The full version is integrated into the mathematics package that I'm still tweaking, but this is too useful to keep to myself any longer. At least, I think so—let me know what you think.

03 March 2008

Names on NEXUS: Under the Hood

I nearly have the basic data model and data processing functions pinned down for Names on NEXUS. Once again, that's my project, hinted at in a paper of mine (Keesey 2007), to relate the data in NEXUS files (Maddison et al. 1997) to definitions of names as governed by the PhyloCode.

I've had to learn some new technologies and code packages to accomplish this. Here's a rundown of some key ones:

BioJava
This is the most recent addition. Originally I had built my own library in ActionScript 3.0 to parse NEXUS files. But it had some limitations. NEXUS is a rather old format (as bioinformatics formats go), and different applications produce somewhat different versions. So rather than use my own ad hoc library, I decided I should get an open source one.

There aren't any in ActionScript, of course, but there are some in Java. This meant I had to switch NEXUS parsing from the front end to the back end, but in some ways that's better. It means I can stored parsed data in the database instead of having client application parse NEXUS data every time. In fact, it means that the client never has to actually see raw NEXUS data—it can just fetch the pre-parsed data.

I first looked into using the NEXUS-parsing code in Mesquite, an open-source phylogenetic analysis program. But it's not set up for simply using the parsing engine on its own—the parser is tied into a whole file-browsing package. Then I found BioJava, which had exactly what I needed. Just looka this package!

Unfortunately there are still some problems with opening certain NEXUS files. I downloaded some samples from TreeBASE and they flagged errors in the TREES section. The reason, as I found after hours of searching and considering whether it might be better just to write my own parser after all, turns out to be an extra comma in the TRANSLATE section. Still not exactly sure how I'm going to solve that one. But it works when I remove the comma!

Hibernate
Remember how I wrote a post a while ago about building classes that map from the Java back-end to the database? Turns out that was all unnecessary. Hibernate is a persistence layer that provides pretty seamless integration between Java and a database (in this case, a PostgreSQL database). Augmented by Hibernate Annotations and Hibernate Validator, it makes it fairly easy to set up and use a complex, well-organized database.

Well, okay, there's a bit of a learning curve first, but it's totally worth it. Incidentally, the book I used to learn it has what is possibly the best title ever.

Flex Data Management Services
Basically, Hibernate is to Java and databases as mx.data is to Flex and Java. It provides a persistence layer so that I don't have to keep track of whether or not I need to request certain data from the Java back-end. I just create DataService objects, tie them to Assembler classes on the back end, and it's all taken care of.

FlexUnit and JUnit
I've already extolled the virtues of unit testing. These wonderful (and, yes, comically-named) packages (huh huh) make it possible. I haven't built enough unit tests, really, but the few I have have been enormously useful in hunting down peculiar errors. And aside from that, since Eclipse can run JUnit tests natively, I can even use them to perform certain important tasks, such as setting up the database from annotated classes via Hibernate.

So What's Left For Me To Do?
Plenty. Although these premade packages help out enormously, I've still had to build an entire mathematics library, a MathML parser, and some tools for handling URIs. I've still got tons of work left to do on the user interface. (Event bubbling is helping a lot with that, by the way.) And, even when stuff is already built, just hooking up one pipe to another pipe can be more complicated than it seems.

Here's a rough list of what's left:
  • Finalize the servlet for uploading and parsing NEXUS data. (I'm very close on this one.)
  • Finish the required behind-the-scenes "search" features. Some of these might be a bit involved, like the ones that suggest possible links between NEXUS taxa and species or specimens or between NEXUS character states and apomorphies.
  • Overhaul the way Names on NEXUS entities (particularly specifiers) are referenced in MathML.
  • Finish the user interface. So far I just have a few forms. I still have to do tree visualization, stylesheets, high-level navigation, transitions, etc.
  • Constrain access to certain functionality. Names on NEXUS is going to be a pretty open, collaborative tool, but I need to set a few boundaries. (E.g., I can't have any old person delete data.)
  • Make sure the server's all optimized, with a static, JNDI-named Hibernate factory, etc.

And here are some things that aren't, strictly speaking, essential, but would be awfully nice:
  • Create a servlet to provide permanent links for Names on NEXUS entities.
  • Create unit tests for all relevant classes.
  • Add JavaDoc and ASDoc comments to all code.

Part of me is also thinking about renaming the project. I mean, it's a good name for what it does right now, but what if I start to bring formats other than NEXUS into the fold? (Not that there are many, but....) Well, I'll probably cross that bridge when I come to it.

My goal is to get an alpha version online sometime this Spring and go open source with it by the Fall. We'll see....