User Tools

Site Tools


02_user_tutorials:15_rules:01_xl-queries-and-operators

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
02_user_tutorials:15_rules:01_xl-queries-and-operators [2025/12/10 13:14] – removed - external edit (Unknown date) 127.0.0.102_user_tutorials:15_rules:01_xl-queries-and-operators [2025/12/12 11:54] (current) groimp
Line 1: Line 1:
 +~~NOTOC~~
 +====== XL queries and operators ======
  
 +===== Queries =====
 +
 +Graph queries are used to analyse the actual structure (graph), which can be for example a plant structure. 
 +
 +In XL, queries are enclosed in asterixed parentheses ''(*  *)''.
 +
 +The elements in a query are given in their expected order, e.g. ''(* A A B *)'' searches for a subgraph which consists of a sequence of nodes of the types ''A'' ''A'' ''B'', connected by successor edges.
 +
 +To try out how queries work, we first create a simple plant model.
 +
 +==== Test model ====
 +
 +<code java>
 +module Bud extends Sphere(0.1).(setShader(GREEN));
 +
 +module Internode(int age, super.length) extends Cylinder(length, 0.1).(setShader(YELLOW));
 +
 +module Leaf(int age, super.length, double width) extends Parallelogram(length, width).(setShader(GREEN)) 
 +{
 +    double area;
 +
 +    { setArea(); }
 +
 +    void setArea() {
 +        area = length*width;
 +    }
 +}
 +
 +protected void init()
 +[
 +    Axiom ==> Bud;
 +]
 +
 +public void run()
 +[
 +    Bud ==> 
 +        Internode(1, 1) 
 +        [RL(60) Leaf(1, 1, 1)] 
 +        RH(180)
 +        Bud
 +    ;
 +
 +    i:Internode ::> { i[age]++; i[length] += 1; }
 +    l:Leaf ::> { l[age]++; l[length] += 1; l.setArea(); }
 +]
 +</code>
 +
 +We create a new method called ''analyse()''. The method will appear as a new button in the RGG toolbar. Before running the ''analyse()'' method, press the ''Reset'' button in the RGG Toolbar, to reset the graph structure. Inside this method, we first call the ''run()'' method for 3 steps. The result is a simple plant made of 3 internodes and 3 leaves.
 +
 +{{ :tutorials:testplant_crop.png?100|}}
 +
 +<code java>
 +public void analyse()
 +{
 +    for (apply(3)) { run(); }
 +    
 +    println("add here a query example");
 +}
 +</code>
 +
 +{{ :tutorials:graph_query_example_2rot.png?200|}}
 +
 +The underlying 2d graph of the generated structure is given below:
 +
 +Beginning from //RGGRoot//, we have the sequence of three //Internodes//, where to each //Internode// a //Leaf// is linked by a branching edge. The last internode, additionally, has a //Bud// node successor.
 +
 +
 +==== Query examples ====
 +
 +Replace the text (in red) inside the ''println()'' one by one by the queries below.
 +
 +Below each query, there is a result of the print command, for illustration. Note, that the ids will differ with different model execution. 
 +
 +  * Find all the internodes in the structure:
 +
 +<code java>
 +(* Internode *)
 +</code>
 +
 +The query will return ids of all the internodes in the plant structure. 
 +
 +<hidden answer>
 +Model.Internode[id=1911]@ecc95fb
 +
 +Model.Internode[id=1906]@7b431a06
 +
 +Model.Internode[id=1901]@5753e950
 +
 +__Note:__
 +
 +Internode with the id=1901 is the first internode from the bottom (with the highest age: 3).
 +
 +Internode with the id=1911 is the top internode (with the lowest age: 1)
 +</hidden>
 +
 +Notice, that when you click with a mouse on an internode in the 3D View window, information about the selected internode will be displayed in the Attribute Editor. In the Attribute Editor, you can check the internode id (e.g. Model$Internode [Internode.1756]) and compare it with the one that was printed in the XL Console. Another option is to look at the node ids in the 2D Graph (Panels -> 2D -> Graph, in the graph window: View -> Redraw).
 +
 +  * Find all newly created internode(s), with age == 1:
 +
 +<code java>
 +(* i:Internode, (i[age] == 1) *)
 +</code>
 +
 +<hidden answer>
 +Model.Internode[id=1911]@ecc95fb
 +</hidden>
 +
 +  * Find the internode below the bud:
 +
 +{{ :tutorials:testplant_graph.png?150|}}
 +
 +<code java>
 +(* Bud < RH < Internode *)
 +</code>
 +
 +''<'' represents a successor edge in the indicated direction
 +
 +<hidden answer>
 +Model.Internode[id=1911]@ecc95fb
 +</hidden>
 +
 +  * Find all leaves connected to an internode:
 +
 +<code java>
 +(* Internode +> RL > Leaf *)
 +</code>
 +
 +This is just to illustrate how to define different edge types inside a query. ''+>'' represents a branch edge.
 +
 +<hidden answer>
 +Model.Leaf[id=1913]@4b0f7bd
 +
 +Model.Leaf[id=1908]@1c6dbfa5
 +
 +Model.Leaf[id=1903]@668c1f97
 +
 +__Note:__
 +Leaf with the id=1903 is the first (and the oldest) leaf, leaf with the id=1913 is the last (and the yongest) leaf.
 +</hidden>
 +
 +==== Aggregators ====
 +
 +Aggregate operations are used to collect multiple values when traversing the graph structure and return a single value.
 +
 +Standard [[:15_cheatsheet:operators|aggregate operations]] are: ''count'', ''sum'', ''empty'', ''exist'', ''forall'', ''first'', ''last'', ''max'', ''min'', ''mean'', ''selectRandomly'', ''selectWhereMin'', ''selectWhereMax'', ...
 +
 +  * Count all leaves: 
 +
 +<code java>
 +count((* Leaf *))
 +</code>
 +
 +<hidden answer>
 +3
 +</hidden>
 +
 +
 +  * Sum up the area of all leaves:
 +
 +<code java>
 +sum((* Leaf *)[area])
 +</code>
 +
 +<hidden answer>
 +6.0
 +</hidden>
 +
 +
 +  * Sum up the length of internodes:
 +
 +<code java>
 +sum((* Internode *)[length])
 +</code>
 +
 +<hidden answer>
 +6.0
 +</hidden>
 +
 +In this particular example with internodes forming (only) the main stem, the query will return stem length.
 +
 +  * Select the leaf with the highest leaf area:
 +
 +<code java>
 +selectWhereMax((* l:Leaf *), (l[area]))
 +</code>
 +
 +<hidden answer>
 +Model.Leaf[id=1903]@668c1f97
 +</hidden>
 +
 +
 +  * Count internodes that are older than 2 (time units):
 + 
 +<code java> 
 +count((* i:Internode, (i[age] >= 2) *))
 +</code>
 +
 +<hidden answer>
 +2
 +</hidden>
 +
 +==== Transitive closure ====
 +
 +Transitive closure is a concept used to derive relations between successive nodes connected by several edges of the same type. For example, we want to find all descendants of some given node that are of type Internode.
 +
 +The quantifier ''+'' stands for 1-to-//n// repetitions, the quantifier ''*'' stands for 0-to-//n// repetitions.
 +
 +  * Find all internodes connected to the bud:
 + 
 +<code java> 
 +(* Bud (<--)+ Internode *)
 +</code>
 +
 +Special syntax is used after the quantifier if we are interested only in finding minimal elements '':(node_type)'' 
 +
 +  * Find the first internode connected to the bud:
 + 
 +<code java> 
 +(* Bud (<--)+ :(Internode) *)
 +</code>