Represent and Evaluate Boolean Predicate Expressions
CoreweaveSoftware Engineer · OnsiteLast updated
Design an object-oriented or tree-based representation for boolean predicate expressions and implement an evaluation engine that supports logical operators, comparison operations, and short-circuit evaluation against attribute dictionaries.
Problem Statement
Cloud infrastructure platforms frequently need to filter compute resources (nodes, clusters, or workloads) based on dynamic attribute criteria, such as available GPU memory, region, or machine tags.
Design an extensible representation for boolean predicate expressions and implement an evaluation mechanism that assesses whether a given resource context (a dictionary mapping string keys to scalar values) satisfies the predicate.
Your solution should support:
- Comparison Predicates:
Equals(field: str, value: Any): returnsTrueifcontext.get(field) == value.GreaterThan(field: str, value: Union[int, float]): returnsTrueifcontext.get(field) > value. Iffieldis missing or the value is not comparable, evaluate toFalse.InSet(field: str, values: Set[Any]): returnsTrueifcontext.get(field)exists invalues.
- Logical Predicates:
And(*predicates: Predicate): returnsTrueif all child predicates evaluate toTrue. Supports short-circuiting (stops evaluating upon encountering the firstFalse). An emptyAnd()evaluates toTrue.Or(*predicates: Predicate): returnsTrueif any child predicate evaluates toTrue. Supports short-circuiting (stops evaluating upon encountering the firstTrue). An emptyOr()evaluates toFalse.Not(predicate: Predicate): returns the logical negation of the child predicate.
Interface
from abc import ABC, abstractmethod
from typing import Any, Set, Union
class Predicate(ABC):
@abstractmethod
def evaluate(self, context: dict[str, Any]) -> bool:
"""Evaluate the predicate against the given context dictionary."""
pass
class Equals(Predicate):
def __init__(self, field: str, value: Any):
...
class GreaterThan(Predicate):
def __init__(self, field: str, value: Union[int, float]):
...
class InSet(Predicate):
def __init__(self, field: str, values: Set[Any]):
...
class And(Predicate):
def __init__(self, *predicates: Predicate):
...
class Or(Predicate):
def __init__(self, *predicates: Predicate):
...
class Not(Predicate):
def __init__(self, predicate: Predicate):
...
Examples
Example 1
# Expression: gpu == "H100" AND (vram_gb > 40 OR region IN {"us-east-1", "us-west-1"})
expr = And(
Equals("gpu", "H100"),
Or(
GreaterThan("vram_gb", 40),
InSet("region", {"us-east-1", "us-west-1"})
)
)
node_a = {"gpu": "H100", "vram_gb": 80, "region": "eu-central-1"}
node_b = {"gpu": "A100", "vram_gb": 80, "region": "us-east-1"}
assert expr.evaluate(node_a) is True # H100 matches, 80 > 40 matches
assert expr.evaluate(node_b) is False # gpu is A100, short-circuits
Constraints
- Attribute values in context dictionaries can be
str,int,float,bool, orNone. - Comparison with missing keys in comparison operators should safely return
Falserather than raisingKeyError. - The depth of the expression tree will not exceed
100nodes.
Hints
Hint 1
Use the Composite design pattern: both leaf predicates and composite operators share the common abstract interface with an evaluate method.
Hint 2
Implement short-circuiting in And and Or by iterating through child predicates with a generator or early return upon finding an absorbing element.
Hint 3
Ensure comparison methods handle missing keys and incompatible type comparisons gracefully with a try-except block or explicit type checks.
Follow-up questions
- How would you serialize and deserialize this predicate expression tree to and from JSON (e.g., for storing filter rules in a database or passing via REST API)?
- How would you optimize evaluating the same predicate against millions of resource contexts in parallel or via vectorization?
- How would you implement static validation to verify that an expression tree contains no contradictory clauses (e.g., `x > 10 AND x < 5`) before running evaluation?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.