Hoppa till innehåll

Predicates

Det här innehållet är inte tillgängligt på ditt språk än.

Predicates are functions that return a boolean value. They are used to filter nodes, simplifying code, and making it more readable. The predicates allows the developer to extract the desired information, in an efficient manner, without having deep knowledge of the underlying tree structure. They reduce the risk of bugs creeping in, as correct tree traversal code can be tricky to write. They can be combined to create complex structural queries. They are also efficient, even beating manual traversal code written by the author.

Mental Model: Always think of predicates from the current evaluated node’s perspective (e.g., “Is this node a descendant of X?”, “Does this node have children?”).


The following predicates evaluate the structure of a node.

PredicateArgumentsDescription
InnerIs an inner node (i.e., can have children, height > 0).
LeafIs a leaf node (i.e., cannot have children, height == 0).
Heightmin, maxHeight is in [min..max].
Offsetmin, maxOffset is in [min..max].

Below you can find a binary tree diagram to illustrate when the different predicates return true.

---
config:
  layout: dagre
  look: classic
---
flowchart TB
  %% Vertical column for labels
  L3["Height 3 (Inner)"] ~~~ L2["Height 2 (Inner)"]
  L2 ~~~ L1["Height 1 (Inner)"]
  L1 ~~~ L0["Height 0 (Leaf)"]

  %% Tree Structure
  A{{"`Root
Offset: 0`"}} --> B{
Offset: 0}
  A --> C{Offset: 1}
  B --> D{Offset: 0}
  B --> E[Offset: 1]
  D --> F((Offset: 0))
  D --> G((Offset: 1))
  C --> H{Offset: 0}
  C --> I[Offset: 1]
  H --> J((Offset: 0))
  H --> K((Offset: 1))

  %% Strip background/borders from labels
  classDef textLabel fill:none,stroke:none,font-weight:bold,font-size:16px;
  class L3,L2,L1,L0 textLabel;

The following predicates evaluate the current state of a node.

PredicateDescription
HasChildrenHas children.
ChildlessIs childless.
ExistsExists.
ModifiedIs in a modified state.

These predicates evaluate a node based on its position relative to a target node (T).

PredicateArgumentsDescription
AncestorOfqueryIs an ancestor of the given query node.
SiblingOfqueryShares the same parent as the given query node.
DescendantOfqueryIs a descendant of the given query node.

These predicates evaluate the physical intersection between a node and a given geometry.

PredicateDiagramArgumentsDescription
ContainsGNgeometrynode contains the geometry.
DisjointNGgeometrynode is disjoint from the geometry.
IntersectsNGgeometrynode intersects with the geometry.
InsideNGgeometrynode is inside the geometry.
PredicateArgumentsDescription
Xmin, maxIntersects along the x-axis with the range [min, max].
Ymin, maxIntersects along the y-axis with the range [min, max].
Zmin, maxIntersects along the z-axis with the range [min, max].
Wmin, maxIntersects along the w-axis with the range [min, max].

The following predicates are used to combine, negate, or compare other predicates.

PredicateArgumentsDescription
AndP1,,PnP_1, \dots, P_nTrue if all predicates are true (P1PnP_1 \land \dots \land P_n).
OrP1,,PnP_1, \dots, P_nTrue if at least one predicate is true (P1PnP_1 \lor \dots \lor P_n).
IfThenP,QP, QTrue if PP is false or QQ is true (PQP \rightarrow Q).
IffP,QP, QTrue if both arguments are either true or false (PQP \leftrightarrow Q).
XorP,QP, QTrue if exactly one argument is true (PQP \oplus Q).
PQAnd
PQP \land Q
Or
PQP \lor Q
IfThen
PQP \rightarrow Q
Iff
PQP \leftrightarrow Q
Xor
PQP \oplus Q
TTTTTTF
TFFTFFT
FTFTTFT
FFFFTTF

In C++, you can use standard operators to make complex queries much more readable:

C++ OperatorPredicateEquivalent Logic
&&And
||Or
!Negate
>>IfThen
^Xor
(None)Iff!(P ^ Q)

Example: Combining Predicates Using the operators, this verbose functional code:

auto pred = Or(And(a, Xor(b, c), d), e, Iff(f, IfThen(g, h)))

Can be written cleanly as:

auto pred = (a && (b ^ c) && d) || e || !(f ^ (g >> h));

Example: Negating Predicates For predicates that check for ranges, it can be more efficient to negate the predicate instead of splitting it into two predicates. Below, the first predicate will be two separate checks per node, while the second predicate will be a single check per node.

// Instead of this:
auto pred = 3 > depth || depth > 5;
// You can write this:
auto pred = !(3 < depth < 5);

⚠️ Note on C++ Range Syntax In standard C++, 3 < depth < 5 evaluates incorrectly as (3 < depth) < 5. However, our library overrides these operators to build a safe expression chain, meaning you can write mathematical ranges exactly as they appear above!

auto pred = 3 > depth > 5;
// Is equivalent to:
auto pred = (3 > depth) > 5;
// Which results in:
auto pred = depth > 5; // Since there is only one predicate at play here

While:

auto pred = 3 < depth < 5;
// Is equivalent to:
auto pred = 3 < depth && depth < 5;

These are the simplest predicates, used primarily for testing or forcing specific evaluation states.

PredicateArgumentsDescription
TrueAlways true.
FalseNever true.
BoolBTrue if the provided boolean B is true.

PredicateArgumentsDescription
SatisfiesRetFun, IntFunSatisfies RetFun and all ancestors satisfy IntFun.

These predicates are only available if the map has color, i.e., ColorMap is used.

Note: Color properties are evaluated using the Oklch color space.

PredicateArgumentsDescription
HasColorHas color.
Lightnessmin, maxLightness is in [min, max]. Valid range: [0, 1].
Chromamin, maxChroma is in [min, max]. Valid range: [0, 0.4].
Huemin, maxHue is in [min, max]. Valid range: [0, 360].
Alphamin, maxAlpha is in [min, max]. Valid range: [0, 1].
ColorWeightmin, maxColor weight is in [min, max].

These predicates are only available if the map has confidence, i.e., ConfidenceMap or SemanticMap is used.

PredicateArgumentsDescription
Confidencemin, maxConfidence is in [min, max].

These predicates are only available if the map has cost, i.e., CostMap is used.

PredicateArgumentsDescription
Costmin, maxCost is in [min, max].

These predicates are only avilable if the map has count, i.e., CountMap is used.

PredicateArgumentsDescription
Countmin, maxCount is in [min, max].

These predicates are only avilable if the map has distance, i.e., DistanceMap is used.

PredicateArgumentsDescription
Distancemin, maxDistance is in [min, max].

These predicates are only avilable if the map has dynamics, i.e., DynamicsMap is used.

PredicateArgumentsDescription
DynamicIs dynamic.
StaticIs static.
HasDynamicItself or any child is dynamic.
HasStaticItself or any child is static.

These predicates are only avilable if the map has intensity, i.e., IntensityMap is used.

PredicateArgumentsDescription
Intensitymin, maxIntensity is in [min, max].

These predicates are only avilable if the map has labels, i.e., LabelMap or SemanticMap is used.

PredicateArgumentsDescription
LabellabelHas the given label.

These predicates are only avilable if the map has occupancy, i.e., OccupancyMap is used.

PredicateArgumentsDescription
FreeIs free.
OccupiedIs occupied.
UnknownIs unknown.
Occupancymin, maxOccupancy is in [min, max]. Valid range: [0, 1].
OccupancyStatesstatesOccupancy is one of the given states.
HasFreeItself or any child is free.
HasOccupiedItself or any child is occupied.
HasUnknownItself or any child is unknown.

These predicates are only avilable if the map has reflection, i.e., ReflectionMap is used.

PredicateArgumentsDescription
Hitsmin, maxHits is in [min, max].
Missesmin, maxMisses is in [min, max].
Reflectivenessmin, maxReflectiveness is in [min, max]. Valid range: [0, 1].

These predicates are only avilable if the map has semantic, i.e., SemanticMap is used.

PredicateArgumentsDescription
Semanticlabel, min, maxHas label with confidence in [min, max].

These predicates are only avilable if the map has surfels, i.e., SurfelMap is used.

PredicateArgumentsDescription
SurfelRadiusmin, maxSurfel radius is in [min, max].
IsPlanarSurfel is planar.

These predicates are only avilable if the map has time, i.e., TimeMap is used.

PredicateArgumentsDescription
Timemin, maxTimestamp is in [min, max].
ufo::Map<ufo::OccupancyMap, ufo::DynamicsMap, ufo::SemanticMap> map;
// Fill in map with data
namespace up = ufo::pred;
auto pred = up::childless && up::occupied && up::dynamic && up::Semantic("car", 0.7, 1.0);
for (auto node : pred) {
// Node is a node that satisfies the predicate, so it is:
// - Childless
// - Occupied
// - Dynamic
// - Has label "car" with confidence in [0.7, 1.0]
}