Changes

Jump to: navigation, search

PatternQuery:Principles

4 bytes added, 13:45, 25 April 2015
no edit summary
'''A new paradigm for describing structural fragments patterns in molecules'''
This text describes the basic principles of the '''MotiveQueryPatternQuery''' language for describing structural fragments patterns in molecules. First, the text puts two approaches for identifying molecular fragments patterns in contrast: the imperative approach, and the declarative one, taken by the '''MotiveQueryPatternQuery''' language. Next, basic principles of the language are illustrated on several examples and later described in a more formal way. Finally, the original example is revisited and explained in the terms of the newly introduced concepts.
==Example, Part One==
'''Goal: Find all HET residues in a protein.'''
Let’s assume we have loaded a protein stored in a PDB or mmCIF file with correctly annotated HET groupsand '''we want to find all HET residues in it'''.
The characteristics of an imperative approach is explicitly stating steps that need to be performed in order achieve a particular goal. In contrast a declarative approach states the goal we would like to achieve, leaving the individual steps as an "implementation detail".
if residue.IsHet():
result.Add(residue)
</syntaxhighlight >
In the declarative approach, our code would look like this:
</syntaxhighlight>
Internally, the function <code>[[MotiveQueryPatternQuery:Language_Reference#AmbientAtoms | AmbientAtoms()]]</code> might run code similar to the imperative version. However, what is important is that this complexity is hidden from the user when the declarative approach is used.
Now, let’s extend our example even further: "all HET residues and atoms within 4A around them, where the entire structure contains at least one calcium atom".
We will not bother the reader with writing down the imperative version - implementing the condition "at least one calcium atom" is rather boring. However, using the declarative approach, the description of the fragment pattern becomes simply:
<syntaxhighlight lang="python">
===Intuitive Description===
As we've seen in the example above, it is very easy to ''compose'' our ideas about the final shape of the fragment pattern we are interested in. The way this works is that the input molecule is decomposed into a stream of fragmentspatterns. These streams can then be modified and combined into new streams, which can be modified and combined again.
As an example, take the query <code>Atoms('Ca')</code>. What the '''MotiveQueryPatternQuery''' language does is to extract all calcium atoms from the input molecule and represent them as a stream of sets containing one atom each as illustrated on the image below:
[[Image:MotiveQueryPatternQuery-Principles Atoms(Ca).png|center|600px]]
Now, each element of this stream can be modified, for example to include all atoms 4A within the original calcium atom. Now we have a stream of sets of atoms, where each set contains the original Ca atom and the atoms within the given radius. This would be represented by the query <code>Atoms('Ca').AmbientAtoms(4)</code> and is illustrated on the image bellow:
[[Image:MotiveQueryPatternQuery-Principles Atoms(Ca) surr.png|center|600px]] In the next step, we might wish to keep only these fragments that contain at least 6 atoms. This is achieved by looking at each fragment, counting the number of atoms and throwing away these fragments that do not meet the criteria. Written as a query, this could be represented as <code>Atoms('Ca').AmbientAtoms(4).Filter(lambda m: m.Count(Atoms()) >= 6)</code>. In the graphical form:
[[ImageIn the next step, we might wish to keep only these patterns that contain at least 6 atoms. This is achieved by looking at each pattern, counting the number of atoms and throwing away these patterns that do not meet the criteria. Written as a query, this could be represented as <code>Atoms('Ca').AmbientAtoms(4).Filter(lambda m:MotiveQuery-Principles m.Count(Atoms(Ca) surr filt) >= 6)</code>.png|center|600px]]In the graphical form:
The previous filter query also demonstrates another interesting concept of the language: ability to identify fragments within fragments, which is what the expression <code>m.Count(Atoms())</code> does - the <code>[[MotiveQueryImage:Language_Reference#Atoms | PatternQuery-Principles Atoms()]]</code> query is executed for each fragment from the original input sequence provided by the expression <code>Atoms('Ca')surr filt.AmbientAtoms(4)</code>, and creates a new sequence of fragments that each contain a single atom. Then the Count function takes over and returns the number of fragments produced by its argument. In this way, the query <code>[[MotiveQuery:Language_Reference#Atoms png| Atoms()]]</code> inside the Count function can be replaced by any function that also produces a sequence of fragments, for example <code>[[MotiveQuery:Language_Reference#Rings center| Rings()600px]]</code>.
Finally, streams The previous filter query also demonstrates another interesting concept of fragments can be combined. For example, let’s say we want the language: the ability to find all pairs of calcium atoms that are no further than 4A identify patterns within each otherpatterns, which is what the expression <code>m. This can be achieved using Count(Atoms())</code> does - the query <code>Near(4, [[PatternQuery:Language_Reference#Atoms | Atoms('Ca'), ]]</code> query is executed for each pattern from the original input sequence provided by the expression <code>Atoms('Ca').AmbientAtoms(4)</code>, and creates a new sequence of patterns that each contain a single atom. So this query Then the Count function takes as over and returns the input two identical streams of calcium atoms and for each pair number of them determines if the atoms are closer than 4A to each otherpatterns produced by its argument. For each pair that satisfies In this conditionway, a new fragment from the 2 atoms is created. Therefore, the result of the above query <code>[[MotiveQueryPatternQuery:Language_Reference#Near Atoms | NearAtoms()]]</code> query is inside the Count function can be replaced by any function that also produces a stream sequence of sets of atoms patterns, for example <code>[[PatternQuery:Language_Reference#Rings | Rings(fragments) that each contain two calcium atoms that are no further than 4A from each other:]]</code>.
Finally, streams of patterns can be combined. For example, let’s say we want to find all pairs of calcium atoms that are no further than 4A apart. This can be achieved using the query <code>Near(4, Atoms('Ca'), Atoms('Ca'))</code>. So this query takes as the input two identical streams of calcium atoms and for each pair of them determines if the atoms are closer than 4A to each other. For each pair that satisfies this condition, a new pattern from the 2 atoms is created. Therefore, the result of the above <code>[[ImagePatternQuery:Language_Reference#Near.png|center|600pxNear()]]</code> query is a stream of sets of atoms (patterns) that each contain two calcium atoms that are no further than 4A from each other:
With these basic types queries outline in the previous paragraphs, the sky's the limit. Due to the composable nature of the language if a new type of motif emerges, only a single function needs to be added to the language for it to work with all its other parts. As an example, assume we didn’t know that proteins had secondary structure called “sheet” and we just discovered it and a fancy algorithm to identify these "sheets". Now we would be interested in how this new type of protein substructure interacts with other parts of the molecule. All that would be needed is to add a function called <code>[[MotiveQueryImage:Language_Reference#Sheets PatternQuery-Principles-Near.png| Sheets()]]</code> to the language and immediately we would be able to analyze and filter it’s neighborhood using the functions <code>[[MotiveQuery:Language_Reference#AmbientAtoms | AmbientAtoms()]]</code> and <code>[[MotiveQuery:Language_Reference#Filter center| Filter()600px]]</code>.
With these basic types of queries outlined in the previous paragraphs, the sky's the limit. Due to the composable nature of the language if a new type of pattern emerges, only a single function needs to be added to the language for it to work with all its other parts. As an example, assume we didn’t know that proteins had secondary structure called “sheet” and we just discovered it and a fancy algorithm to identify these "sheets". Now we would be interested in how this new type of protein substructure interacts with other parts of the molecule. All that would be needed is to add a function called <code>[[PatternQuery:Language_Reference#Sheets | Sheets()]]</code> to the language and immediately we would be able to analyze and filter it’s neighborhood using the functions <code>[[PatternQuery:Language_Reference#AmbientAtoms | AmbientAtoms()]]</code> and <code>[[PatternQuery:Language_Reference#Filter | Filter()]]</code>.
===A More Formal Description===
There are two basic data structures that the language is built upon. These are:
* '''FragmentPattern'''. A fragment pattern is simple simply an arbitrary set of atoms.* '''Fragment Pattern Sequence'''. A sequence of fragmentspatterns. In mathematical terms, can be understood as a "set of fragmentspatterns" which is another way of saying "set of sets of atoms".
And on these data structures, there are three basic types of queries:
* '''Generator queries'''. Generator queries, as the name suggests, generate sequences of fragments patterns from the original input. They are the tool that transforms the input molecule into a stream of fragments patterns that can be later modified or combined. Examples of these queries include <code>[[MotiveQueryPatternQuery:Language_Reference#Atoms | Atoms()]]</code>, <code>[[MotiveQueryPatternQuery:Language_Reference#Residues | Residues()]]</code>, and <code>[[MotiveQueryPatternQuery:Language_Reference#RegularMotifs | RegularMotifs()]]</code>.* '''Modifier queries'''. These queries operate on individual fragments patterns and modify them or throw them away. Examples include <code>[[MotiveQueryPatternQuery:Language_Reference#AmbientAtoms | AmbientAtoms()]]</code>, <code>[[MotiveQueryPatternQuery:Language_Reference#ConnectedResidues | ConnectedResidues()]]</code>, and <code>[[MotiveQueryPatternQuery:Language_Reference#Filter | Filter()]]</code>.* '''Combinator queries'''. Combinatorial queries take as input two or more sequence of fragments patterns and combine them into a single new sequence that satisfies given criteria. Examples include <code>[[MotiveQueryPatternQuery:Language_Reference#Near Or | NearOr()]]</code>, <code>[[MotiveQueryPatternQuery:Language_Reference#Cluster Near | ClusterNear()]]</code>, and <code>[[MotiveQueryPatternQuery:Language_Reference#Star Path | StarPath()]]</code>.
==Example, Revised==
This corresponds to the following process.
# A generator query <code>[[MotiveQueryPatternQuery:Language_Reference#HetResidues | HetResidues()]]</code> is executed that produces a sequence of fragments patterns that are composed of atoms corresponding to HET residues.# Next, the original sequence is modified by adding atoms within 3 angstrom from any original atom to each fragmentpattern.# Finally, each fragment pattern in the modified sequence is examined: all “calcium atom fragments” patterns” are identified and counted. Only these fragments patterns that contain at least 1 Ca atom are kept.
Graphically:
<code>[[MotiveQueryPatternQuery:Language_Reference#HetResidues | HetResidues()]]</code>[[Image:PatternQuery-Principles-HetResidues.png|none|500px]]  <code>[[PatternQuery:Language_Reference#AmbientAtoms | .AmbientAtoms(3)]]</code>[[Image:MotiveQueryPatternQuery-Principles-HetResiduesAmbientAtoms.png|centernone|500px]]
<code>[[MotiveQuery:Language_Reference#AmbientAtoms | .AmbientAtoms(3)]]</code>
[[Image:MotiveQuery-Principles-AmbientAtoms.png|center|500px]]
<code>[[MotiveQueryPatternQuery:Language_Reference#Filter | .Filter(lambda l: l.Count(Atoms('Ca')) > 0)]]</code>[[Image:MotiveQueryPatternQuery-Principles-AmbientAtoms-filter.png|centernone|500px]]

Navigation menu