@@ -393,16 +393,73 @@ aggregation in a simpler form:
393
393
Monotonic aggregates
394
394
====================
395
395
396
- In addition to the standard aggregates, QL also supports monotonic aggregates.
397
- These are a slightly different way of computing aggregates which have some advantages.
398
- For example, you can use monotonic aggregates :ref: `recursively <recursion >`.
399
- You can't do this with normal aggregates.
396
+ In addition to standard aggregates, QL also supports monotonic aggregates.
397
+ Monotonic aggregates differ from standard aggregates in the way that they deal with the
398
+ values generated by the ``<expression> `` part of the formula:
399
+
400
+ - Standard aggregates take the ``<expression> `` values for each ``<formula> `` value and
401
+ flatten them into a list. A single aggregation function is applied to all the values.
402
+ - Monotonic aggregates take an ``<expression> `` for each value given by the ``<formula> ``,
403
+ and create combinations of all the possible values. The aggregation
404
+ function is applied to each of the resulting combinations.
405
+
406
+ In general, if the ``<expression> `` is total and functional, then monotonic aggregates are
407
+ equivalent to standard aggregates. Results differ when there is not precisely one ``<expression> ``
408
+ value for each value generated by the ``<formula> ``:
409
+
410
+ - If there are missing ``<expression> `` values (that is, there is no
411
+ ``<expression> `` value for a value generated by the ``<formula> ``), monotonic aggregates
412
+ won't compute a result, as you cannot create combinations of values
413
+ including exactly one ``<expression> `` value for each value generated by the ``<formula> ``.
414
+
415
+ - If there is more than one ``<expression> `` per ``<formula> `` result, you can create multiple
416
+ combinations of values including exactly one ``<expression> `` value for each
417
+ value generated by the ``<formula> ``. Here, the aggregation function is applied to each of the
418
+ resulting combinations.
419
+
420
+ Recursive monotonic aggregates
421
+ ------------------------------
422
+
423
+ Monotonic aggregates may be used :ref: `recursively <recursion >`, but the recursive call may only appear in the
424
+ expression, and not in the range. The recursive semantics for aggregates are the same as the
425
+ recursive semantics for the rest of QL. For example, we might define a predicate to calculate
426
+ the distance of a node in a graph from the leaves as follows:
400
427
401
- For more information and examples, see `Monotonic aggregates in QL
402
- <https://help.semmle.com/QL/learn-ql/advanced/monotonic-aggregates.html> `_.
428
+ .. code-block :: ql
429
+
430
+ int depth(Node n) {
431
+ if not exists(n.getAChild())
432
+ then result = 0
433
+ else result = 1 + max(Node child | child = n.getAChild() | depth(child))
434
+ }
435
+
436
+ Here the recursive call is in the expression, which is legal. The recursive semantics for aggregates
437
+ are the same as the recursive semantics for the rest of QL. If you understand how aggregates work in
438
+ the non-recursive case then you should not find it difficult to use them recursively. However, it is
439
+ worth seeing how the evaluation of a recursive aggregation proceeds.
440
+
441
+ Consider the depth example we just saw with the following graph as input (arrows point from children to parents):
442
+
443
+ .. |image0 | image :: ../images/monotonic-aggregates-graph.png
444
+
445
+ |image0 |
446
+
447
+ Then the evaluation of the ``depth `` predicate proceeds as follows:
448
+
449
+ +-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
450
+ | **Stage ** | **depth ** | **Comments ** |
451
+ +===========+============================================+==========================================================================================================================================================================+
452
+ | 0 | | We always begin with the empty set. |
453
+ +-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
454
+ | 1 | ``(0, b), (0, d), (0, e) `` | The nodes with no children have depth 0. The recursive step for **a ** and **c ** fails to produce a value, since some of their children do not have values for ``depth ``. |
455
+ +-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
456
+ | 2 | ``(0, b), (0, d), (0, e), (1, c) `` | The recursive step for **c ** succeeds, since ``depth `` now has a value for all its children (**d ** and **e **). The recursive step for **a ** still fails. |
457
+ +-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
458
+ | 3 | ``(0, b), (0, d), (0, e), (1, c), (2, a) `` | The recursive step for **a ** succeeds, since ``depth `` now has a value for all its children (**b ** and **c **). |
459
+ +-----------+--------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
403
460
404
- .. TODO: Eventually replace this link with just the relevant examples.
405
- (Some of the content is a duplicate of the above discussion on aggregates.)
461
+ Here, we can see that at the intermediate stages it is very important for the aggregate to
462
+ fail if some of the children lack a value - this prevents erroneous values being added.
406
463
407
464
.. index :: any
408
465
0 commit comments