Skip to content

Models API

fuzzy_infer.models

Data models for the FuzzyInfer system.

This module provides dataclasses for Facts, Rules, Conditions, and Actions with validation and pythonic interfaces.

Fact dataclass

Fact(
    predicate: str,
    args: List[Union[str, Any]],
    degree: float = 1.0,
)

Represents a fuzzy fact in the knowledge base.

Attributes:

  • predicate (str) –

    The predicate name (e.g., 'is-zebra')

  • args (List[Union[str, Any]]) –

    List of arguments for the predicate

  • degree (float) –

    Degree of membership (0.0 to 1.0)

Examples:

>>> fact = Fact('is-zebra', ['sam'], 0.8)
>>> fact.predicate
'is-zebra'
>>> fact.degree
0.8

to_dict

to_dict() -> Dict[str, Any]

Convert fact to dictionary representation.

Source code in fuzzy_infer/models.py
def to_dict(self) -> Dict[str, Any]:
    """Convert fact to dictionary representation."""
    return {"pred": self.predicate, "args": self.args, "deg": self.degree}

from_dict classmethod

from_dict(data: Dict[str, Any]) -> Fact

Create a Fact from dictionary representation.

Source code in fuzzy_infer/models.py
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "Fact":
    """Create a Fact from dictionary representation."""
    return cls(
        predicate=data.get("pred", data.get("predicate", "")),
        args=data.get("args", []),
        degree=data.get("deg", data.get("degree", 1.0)),
    )

matches_pattern

matches_pattern(
    pattern: Fact, bindings: Optional[Dict[str, Any]] = None
) -> Tuple[bool, Dict[str, Any]]

Check if this fact matches a pattern with variables.

Parameters:

  • pattern (Fact) –

    Pattern fact potentially containing variables (e.g., '?x')

  • bindings (Optional[Dict[str, Any]], default: None ) –

    Existing variable bindings

Returns:

  • Tuple[bool, Dict[str, Any]]

    Tuple of (matches: bool, updated_bindings: dict)

Source code in fuzzy_infer/models.py
def matches_pattern(
    self, pattern: "Fact", bindings: Optional[Dict[str, Any]] = None
) -> Tuple[bool, Dict[str, Any]]:
    """
    Check if this fact matches a pattern with variables.

    Args:
        pattern: Pattern fact potentially containing variables (e.g., '?x')
        bindings: Existing variable bindings

    Returns:
        Tuple of (matches: bool, updated_bindings: dict)
    """
    if bindings is None:
        bindings = {}

    if self.predicate != pattern.predicate:
        return False, bindings

    if len(self.args) != len(pattern.args):
        return False, bindings

    new_bindings = bindings.copy()
    for self_arg, pattern_arg in zip(self.args, pattern.args):
        if isinstance(pattern_arg, str) and pattern_arg.startswith("?"):
            # Variable binding
            if pattern_arg in new_bindings:
                if new_bindings[pattern_arg] != self_arg:
                    return False, bindings
            else:
                new_bindings[pattern_arg] = self_arg
        elif self_arg != pattern_arg:
            return False, bindings

    return True, new_bindings

Condition dataclass

Condition(
    predicate: Optional[str] = None,
    args: List[Union[str, Any]] = list(),
    degree_var: Optional[str] = None,
    degree_constraint: Optional[List[Any]] = None,
    negated: bool = False,
    or_conditions: Optional[List[Condition]] = None,
    and_conditions: Optional[List[Condition]] = None,
)

Represents a condition in a rule.

Attributes:

  • predicate (Optional[str]) –

    The predicate to match

  • args (List[Union[str, Any]]) –

    Arguments (can contain variables like '?x')

  • degree_var (Optional[str]) –

    Variable to bind the degree to

  • degree_constraint (Optional[List[Any]]) –

    Optional constraint on degree (e.g., ['>', '?d', 0.5])

  • negated (bool) –

    Whether this is a negated condition

  • or_conditions (Optional[List[Condition]]) –

    List of OR'ed conditions

  • and_conditions (Optional[List[Condition]]) –

    List of AND'ed conditions

from_dict classmethod

from_dict(data: Dict[str, Any]) -> Condition

Create a Condition from dictionary representation.

Source code in fuzzy_infer/models.py
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "Condition":
    """Create a Condition from dictionary representation."""
    if "or" in data:
        return cls(or_conditions=[cls.from_dict(c) for c in data["or"]])
    if "and" in data:
        return cls(and_conditions=[cls.from_dict(c) for c in data["and"]])
    if "not" in data:
        inner = data["not"]
        return cls(
            predicate=inner.get("pred"),
            args=inner.get("args", []),
            degree_var=inner.get("deg"),
            degree_constraint=inner.get("deg-pred"),
            negated=True,
        )

    return cls(
        predicate=data.get("pred"),
        args=data.get("args", []),
        degree_var=data.get("deg"),
        degree_constraint=data.get("deg-pred"),
    )

to_dict

to_dict() -> Dict[str, Any]

Convert to dictionary representation.

Source code in fuzzy_infer/models.py
def to_dict(self) -> Dict[str, Any]:
    """Convert to dictionary representation."""
    if self.or_conditions:
        return {"or": [c.to_dict() for c in self.or_conditions]}
    if self.and_conditions:
        return {"and": [c.to_dict() for c in self.and_conditions]}

    result = {}
    if self.negated:
        inner = {}
        if self.predicate:
            inner["pred"] = self.predicate
        if self.args:
            inner["args"] = self.args
        if self.degree_var:
            inner["deg"] = self.degree_var
        if self.degree_constraint:
            inner["deg-pred"] = self.degree_constraint
        return {"not": inner}

    if self.predicate:
        result["pred"] = self.predicate
    if self.args:
        result["args"] = self.args
    if self.degree_var:
        result["deg"] = self.degree_var
    if self.degree_constraint:
        result["deg-pred"] = self.degree_constraint
    return result

Action dataclass

Action(action_type: str, fact: Dict[str, Any])

Represents an action to take when a rule fires.

Attributes:

  • action_type (str) –

    Type of action ('add', 'remove', 'modify')

  • fact (Dict[str, Any]) –

    Fact to add/remove/modify

to_dict

to_dict() -> Dict[str, Any]

Convert action to dictionary representation.

Source code in fuzzy_infer/models.py
def to_dict(self) -> Dict[str, Any]:
    """Convert action to dictionary representation."""
    return {"action": self.action_type, "fact": self.fact}

from_dict classmethod

from_dict(data: Dict[str, Any]) -> Action

Create an Action from dictionary representation.

Source code in fuzzy_infer/models.py
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "Action":
    """Create an Action from dictionary representation."""
    return cls(action_type=data.get("action", "add"), fact=data.get("fact", {}))

Rule dataclass

Rule(
    conditions: List[Condition],
    actions: List[Action],
    name: Optional[str] = None,
    priority: int = 0,
)

Represents a production rule with conditions and actions.

Attributes:

  • conditions (List[Condition]) –

    List of conditions that must be satisfied

  • actions (List[Action]) –

    List of actions to execute when conditions are met

  • name (Optional[str]) –

    Optional name for the rule

  • priority (int) –

    Priority for rule execution (higher = earlier)

to_dict

to_dict() -> Dict[str, Any]

Convert rule to dictionary representation.

Source code in fuzzy_infer/models.py
def to_dict(self) -> Dict[str, Any]:
    """Convert rule to dictionary representation."""
    result = {
        "cond": [c.to_dict() for c in self.conditions],
        "actions": [a.to_dict() for a in self.actions],
    }
    if self.name:
        result["name"] = self.name
    if self.priority != 0:
        result["priority"] = self.priority
    return result

from_dict classmethod

from_dict(data: Dict[str, Any]) -> Rule

Create a Rule from dictionary representation.

Source code in fuzzy_infer/models.py
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "Rule":
    """Create a Rule from dictionary representation."""
    conditions = []
    raw_conditions = data.get("cond", data.get("conditions", []))
    for cond in raw_conditions:
        conditions.append(Condition.from_dict(cond))

    actions = []
    raw_actions = data.get("actions", [])
    for action in raw_actions:
        actions.append(Action.from_dict(action))

    return cls(
        conditions=conditions,
        actions=actions,
        name=data.get("name"),
        priority=data.get("priority", 0),
    )

RuleBuilder

RuleBuilder()

Builder pattern for constructing complex rules.

Example

rule = (RuleBuilder() ... .when('is-zebra', ['?x']) ... .with_degree_greater_than(0.5) ... .then_add('has-stripes', ['?x']) ... .with_degree_multiplied_by(0.9) ... .build())

Initialize the builder.

Source code in fuzzy_infer/models.py
def __init__(self):
    """Initialize the builder."""
    self.conditions = []
    self.actions = []
    self.current_condition = None
    self.current_action = None
    self.name = None
    self.priority = 0
    self.degree_var = None  # Track degree variable

when

when(
    predicate: str, args: List[Union[str, Any]]
) -> RuleBuilder

Add a condition to the rule.

Source code in fuzzy_infer/models.py
def when(self, predicate: str, args: List[Union[str, Any]]) -> "RuleBuilder":
    """Add a condition to the rule."""
    self.current_condition = Condition(predicate=predicate, args=args)
    self.conditions.append(self.current_condition)
    return self

when_not

when_not(
    predicate: str, args: List[Union[str, Any]]
) -> RuleBuilder

Add a negated condition to the rule.

Source code in fuzzy_infer/models.py
def when_not(self, predicate: str, args: List[Union[str, Any]]) -> "RuleBuilder":
    """Add a negated condition to the rule."""
    self.current_condition = Condition(predicate=predicate, args=args, negated=True)
    self.conditions.append(self.current_condition)
    return self

with_degree_greater_than

with_degree_greater_than(
    threshold: float, var_name: str = "?d"
) -> RuleBuilder

Add a degree constraint to the current condition.

Source code in fuzzy_infer/models.py
def with_degree_greater_than(self, threshold: float, var_name: str = "?d") -> "RuleBuilder":
    """Add a degree constraint to the current condition."""
    if not self.current_condition:
        raise RuleValidationError("No condition to add degree constraint to")
    self.current_condition.degree_var = var_name
    self.current_condition.degree_constraint = [">", var_name, threshold]
    self.degree_var = var_name  # Store for later use
    return self

with_degree_less_than

with_degree_less_than(
    threshold: float, var_name: str = "?d"
) -> RuleBuilder

Add a degree constraint to the current condition.

Source code in fuzzy_infer/models.py
def with_degree_less_than(self, threshold: float, var_name: str = "?d") -> "RuleBuilder":
    """Add a degree constraint to the current condition."""
    if not self.current_condition:
        raise RuleValidationError("No condition to add degree constraint to")
    self.current_condition.degree_var = var_name  
    self.current_condition.degree_constraint = ["<", var_name, threshold]
    self.degree_var = var_name  # Store for later use
    return self

then_add

then_add(
    predicate: str,
    args: List[Union[str, Any]],
    degree: float = 1.0,
) -> RuleBuilder

Add an action to add a fact.

Source code in fuzzy_infer/models.py
def then_add(
    self, predicate: str, args: List[Union[str, Any]], degree: float = 1.0
) -> "RuleBuilder":
    """Add an action to add a fact."""
    fact = {"pred": predicate, "args": args, "deg": degree}
    self.current_action = Action(action_type="add", fact=fact)
    self.actions.append(self.current_action)
    return self

then_remove

then_remove(
    predicate: str, args: List[Union[str, Any]]
) -> RuleBuilder

Add an action to remove a fact.

Source code in fuzzy_infer/models.py
def then_remove(self, predicate: str, args: List[Union[str, Any]]) -> "RuleBuilder":
    """Add an action to remove a fact."""
    fact = {"pred": predicate, "args": args}
    self.current_action = Action(action_type="remove", fact=fact)
    self.actions.append(self.current_action)
    return self

with_degree_multiplied_by

with_degree_multiplied_by(factor: float) -> RuleBuilder

Modify the degree of the current action's fact.

Source code in fuzzy_infer/models.py
def with_degree_multiplied_by(self, factor: float) -> "RuleBuilder":
    """Modify the degree of the current action's fact."""
    if not self.current_action or self.current_action.action_type != "add":
        raise RuleValidationError("No add action to modify degree for")
    # Always create a degree variable for the first condition if none exists
    if not hasattr(self, 'degree_var') or self.degree_var is None:
        # Add degree variable to first condition
        if self.conditions:
            self.conditions[0].degree_var = "?_deg"
            self.degree_var = "?_deg"

    # Use the degree variable to multiply
    if self.degree_var:
        self.current_action.fact["deg"] = ["*", factor, self.degree_var]
    else:
        # Fallback to just using the factor
        self.current_action.fact["deg"] = factor
    return self

named

named(name: str) -> RuleBuilder

Set the rule's name.

Source code in fuzzy_infer/models.py
def named(self, name: str) -> "RuleBuilder":
    """Set the rule's name."""
    self.name = name
    return self

with_priority

with_priority(priority: int) -> RuleBuilder

Set the rule's priority.

Source code in fuzzy_infer/models.py
def with_priority(self, priority: int) -> "RuleBuilder":
    """Set the rule's priority."""
    self.priority = priority
    return self

build

build() -> Rule

Build and return the Rule object.

Source code in fuzzy_infer/models.py
def build(self) -> Rule:
    """Build and return the Rule object."""
    return Rule(
        conditions=self.conditions, actions=self.actions, name=self.name, priority=self.priority
    )

Overview

The fuzzy_infer.models module provides data classes for representing facts, rules, conditions, and actions in the fuzzy inference system.

Classes

Fact

Represents a fuzzy fact in the knowledge base.

Attributes:

  • predicate (str) –

    The predicate name (e.g., 'is-zebra')

  • args (List[Union[str, Any]]) –

    List of arguments for the predicate

  • degree (float) –

    Degree of membership (0.0 to 1.0)

Examples:

>>> fact = Fact('is-zebra', ['sam'], 0.8)
>>> fact.predicate
'is-zebra'
>>> fact.degree
0.8

predicate instance-attribute

predicate: str

args instance-attribute

args: List[Union[str, Any]]

degree class-attribute instance-attribute

degree: float = 1.0

__post_init__

__post_init__()

Validate the fact after initialization.

Source code in fuzzy_infer/models.py
def __post_init__(self):
    """Validate the fact after initialization."""
    if not self.predicate:
        raise FactValidationError("Predicate cannot be empty")
    if not isinstance(self.args, list):
        raise FactValidationError("Arguments must be a list")
    if not 0.0 <= self.degree <= 1.0:
        raise FactValidationError(f"Degree must be between 0 and 1, got {self.degree}")

to_dict

to_dict() -> Dict[str, Any]

Convert fact to dictionary representation.

Source code in fuzzy_infer/models.py
def to_dict(self) -> Dict[str, Any]:
    """Convert fact to dictionary representation."""
    return {"pred": self.predicate, "args": self.args, "deg": self.degree}

from_dict classmethod

from_dict(data: Dict[str, Any]) -> Fact

Create a Fact from dictionary representation.

Source code in fuzzy_infer/models.py
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "Fact":
    """Create a Fact from dictionary representation."""
    return cls(
        predicate=data.get("pred", data.get("predicate", "")),
        args=data.get("args", []),
        degree=data.get("deg", data.get("degree", 1.0)),
    )

matches_pattern

matches_pattern(
    pattern: Fact, bindings: Optional[Dict[str, Any]] = None
) -> Tuple[bool, Dict[str, Any]]

Check if this fact matches a pattern with variables.

Parameters:

  • pattern (Fact) –

    Pattern fact potentially containing variables (e.g., '?x')

  • bindings (Optional[Dict[str, Any]], default: None ) –

    Existing variable bindings

Returns:

  • Tuple[bool, Dict[str, Any]]

    Tuple of (matches: bool, updated_bindings: dict)

Source code in fuzzy_infer/models.py
def matches_pattern(
    self, pattern: "Fact", bindings: Optional[Dict[str, Any]] = None
) -> Tuple[bool, Dict[str, Any]]:
    """
    Check if this fact matches a pattern with variables.

    Args:
        pattern: Pattern fact potentially containing variables (e.g., '?x')
        bindings: Existing variable bindings

    Returns:
        Tuple of (matches: bool, updated_bindings: dict)
    """
    if bindings is None:
        bindings = {}

    if self.predicate != pattern.predicate:
        return False, bindings

    if len(self.args) != len(pattern.args):
        return False, bindings

    new_bindings = bindings.copy()
    for self_arg, pattern_arg in zip(self.args, pattern.args):
        if isinstance(pattern_arg, str) and pattern_arg.startswith("?"):
            # Variable binding
            if pattern_arg in new_bindings:
                if new_bindings[pattern_arg] != self_arg:
                    return False, bindings
            else:
                new_bindings[pattern_arg] = self_arg
        elif self_arg != pattern_arg:
            return False, bindings

    return True, new_bindings

__hash__

__hash__()

Make Fact hashable for use in sets.

Source code in fuzzy_infer/models.py
def __hash__(self):
    """Make Fact hashable for use in sets."""
    return hash((self.predicate, tuple(self.args), self.degree))

__eq__

__eq__(other)

Check equality based on predicate and arguments (not degree).

Source code in fuzzy_infer/models.py
def __eq__(self, other):
    """Check equality based on predicate and arguments (not degree)."""
    if not isinstance(other, Fact):
        return False
    return self.predicate == other.predicate and self.args == other.args

Examples

from fuzzy_infer import Fact

# Create facts
fact1 = Fact("is-bird", ["tweety"], 0.9)
fact2 = Fact("temperature", ["room-1", "hot"], 0.75)
fact3 = Fact("is-tall", ["john"])  # degree defaults to 1.0

# Convert to/from dict
fact_dict = fact1.to_dict()
# {'pred': 'is-bird', 'args': ['tweety'], 'deg': 0.9}

new_fact = Fact.from_dict(fact_dict)

# Pattern matching
pattern = Fact("is-bird", ["?x"], 1.0)
matches, bindings = fact1.matches_pattern(pattern)
# matches=True, bindings={'?x': 'tweety'}

Rule

Represents a production rule with conditions and actions.

Attributes:

  • conditions (List[Condition]) –

    List of conditions that must be satisfied

  • actions (List[Action]) –

    List of actions to execute when conditions are met

  • name (Optional[str]) –

    Optional name for the rule

  • priority (int) –

    Priority for rule execution (higher = earlier)

conditions instance-attribute

conditions: List[Condition]

actions instance-attribute

actions: List[Action]

name class-attribute instance-attribute

name: Optional[str] = None

priority class-attribute instance-attribute

priority: int = 0

__post_init__

__post_init__()

Validate the rule.

Source code in fuzzy_infer/models.py
def __post_init__(self):
    """Validate the rule."""
    if not self.conditions:
        raise RuleValidationError("Rule must have at least one condition")
    if not self.actions:
        raise RuleValidationError("Rule must have at least one action")

to_dict

to_dict() -> Dict[str, Any]

Convert rule to dictionary representation.

Source code in fuzzy_infer/models.py
def to_dict(self) -> Dict[str, Any]:
    """Convert rule to dictionary representation."""
    result = {
        "cond": [c.to_dict() for c in self.conditions],
        "actions": [a.to_dict() for a in self.actions],
    }
    if self.name:
        result["name"] = self.name
    if self.priority != 0:
        result["priority"] = self.priority
    return result

from_dict classmethod

from_dict(data: Dict[str, Any]) -> Rule

Create a Rule from dictionary representation.

Source code in fuzzy_infer/models.py
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "Rule":
    """Create a Rule from dictionary representation."""
    conditions = []
    raw_conditions = data.get("cond", data.get("conditions", []))
    for cond in raw_conditions:
        conditions.append(Condition.from_dict(cond))

    actions = []
    raw_actions = data.get("actions", [])
    for action in raw_actions:
        actions.append(Action.from_dict(action))

    return cls(
        conditions=conditions,
        actions=actions,
        name=data.get("name"),
        priority=data.get("priority", 0),
    )

Examples

from fuzzy_infer import Rule

# Simple rule
rule = Rule(
    name="birds-fly",
    conditions=[
        {"pred": "is-bird", "args": ["?x"]}
    ],
    actions=[
        {"action": "add", "fact": {"pred": "can-fly", "args": ["?x"], "deg": 0.9}}
    ]
)

# Rule with degree constraints
rule = Rule(
    name="confident-classification",
    conditions=[
        {"pred": "is-mammal", "args": ["?x"], "deg": "?d", "deg-pred": [">", "?d", 0.7]}
    ],
    actions=[
        {"action": "add", "fact": {"pred": "warm-blooded", "args": ["?x"], "deg": "?d"}}
    ]
)

# Rule with priority
rule = Rule(
    name="exception-rule",
    priority=100,
    conditions=[{"pred": "is-penguin", "args": ["?x"]}],
    actions=[{"action": "add", "fact": {"pred": "can-fly", "args": ["?x"], "deg": 0.1}}]
)

# Convert to/from dict
rule_dict = rule.to_dict()
new_rule = Rule.from_dict(rule_dict)

Condition

Represents a condition in a rule.

Attributes:

  • predicate (Optional[str]) –

    The predicate to match

  • args (List[Union[str, Any]]) –

    Arguments (can contain variables like '?x')

  • degree_var (Optional[str]) –

    Variable to bind the degree to

  • degree_constraint (Optional[List[Any]]) –

    Optional constraint on degree (e.g., ['>', '?d', 0.5])

  • negated (bool) –

    Whether this is a negated condition

  • or_conditions (Optional[List[Condition]]) –

    List of OR'ed conditions

  • and_conditions (Optional[List[Condition]]) –

    List of AND'ed conditions

predicate class-attribute instance-attribute

predicate: Optional[str] = None

args class-attribute instance-attribute

args: List[Union[str, Any]] = field(default_factory=list)

degree_var class-attribute instance-attribute

degree_var: Optional[str] = None

degree_constraint class-attribute instance-attribute

degree_constraint: Optional[List[Any]] = None

negated class-attribute instance-attribute

negated: bool = False

or_conditions class-attribute instance-attribute

or_conditions: Optional[List[Condition]] = None

and_conditions class-attribute instance-attribute

and_conditions: Optional[List[Condition]] = None

__post_init__

__post_init__()

Validate the condition.

Source code in fuzzy_infer/models.py
def __post_init__(self):
    """Validate the condition."""
    if not any([self.predicate, self.or_conditions, self.and_conditions]):
        raise RuleValidationError("Condition must have a predicate or logical operators")

from_dict classmethod

from_dict(data: Dict[str, Any]) -> Condition

Create a Condition from dictionary representation.

Source code in fuzzy_infer/models.py
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "Condition":
    """Create a Condition from dictionary representation."""
    if "or" in data:
        return cls(or_conditions=[cls.from_dict(c) for c in data["or"]])
    if "and" in data:
        return cls(and_conditions=[cls.from_dict(c) for c in data["and"]])
    if "not" in data:
        inner = data["not"]
        return cls(
            predicate=inner.get("pred"),
            args=inner.get("args", []),
            degree_var=inner.get("deg"),
            degree_constraint=inner.get("deg-pred"),
            negated=True,
        )

    return cls(
        predicate=data.get("pred"),
        args=data.get("args", []),
        degree_var=data.get("deg"),
        degree_constraint=data.get("deg-pred"),
    )

to_dict

to_dict() -> Dict[str, Any]

Convert to dictionary representation.

Source code in fuzzy_infer/models.py
def to_dict(self) -> Dict[str, Any]:
    """Convert to dictionary representation."""
    if self.or_conditions:
        return {"or": [c.to_dict() for c in self.or_conditions]}
    if self.and_conditions:
        return {"and": [c.to_dict() for c in self.and_conditions]}

    result = {}
    if self.negated:
        inner = {}
        if self.predicate:
            inner["pred"] = self.predicate
        if self.args:
            inner["args"] = self.args
        if self.degree_var:
            inner["deg"] = self.degree_var
        if self.degree_constraint:
            inner["deg-pred"] = self.degree_constraint
        return {"not": inner}

    if self.predicate:
        result["pred"] = self.predicate
    if self.args:
        result["args"] = self.args
    if self.degree_var:
        result["deg"] = self.degree_var
    if self.degree_constraint:
        result["deg-pred"] = self.degree_constraint
    return result

Examples

from fuzzy_infer.models import Condition

# Simple condition
cond = Condition(
    predicate="is-bird",
    args=["?x"]
)

# Condition with degree variable
cond = Condition(
    predicate="is-mammal",
    args=["?x"],
    degree_var="?d"
)

# Condition with degree constraint
cond = Condition(
    predicate="confidence",
    args=["?x"],
    degree_var="?d",
    degree_constraint=[">", "?d", 0.8]
)

# Negated condition
cond = Condition(
    predicate="is-cold",
    args=["?room"],
    negated=True
)

# Convert to dict
cond_dict = cond.to_dict()

Action

Represents an action to take when a rule fires.

Attributes:

  • action_type (str) –

    Type of action ('add', 'remove', 'modify')

  • fact (Dict[str, Any]) –

    Fact to add/remove/modify

action_type instance-attribute

action_type: str

fact instance-attribute

fact: Dict[str, Any]

__post_init__

__post_init__()

Validate the action.

Source code in fuzzy_infer/models.py
def __post_init__(self):
    """Validate the action."""
    if self.action_type not in ["add", "remove", "modify"]:
        raise RuleValidationError(f"Invalid action type: {self.action_type}")
    if not self.fact:
        raise RuleValidationError("Action must specify a fact")

to_dict

to_dict() -> Dict[str, Any]

Convert action to dictionary representation.

Source code in fuzzy_infer/models.py
def to_dict(self) -> Dict[str, Any]:
    """Convert action to dictionary representation."""
    return {"action": self.action_type, "fact": self.fact}

from_dict classmethod

from_dict(data: Dict[str, Any]) -> Action

Create an Action from dictionary representation.

Source code in fuzzy_infer/models.py
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "Action":
    """Create an Action from dictionary representation."""
    return cls(action_type=data.get("action", "add"), fact=data.get("fact", {}))

Examples

from fuzzy_infer.models import Action

# Add action
action = Action(
    action="add",
    fact={"pred": "can-fly", "args": ["?x"], "deg": 0.9}
)

# Add with computed degree
action = Action(
    action="add",
    fact={"pred": "result", "args": ["?x"], "deg": ["*", "?d", 0.85]}
)

# Modify action
action = Action(
    action="modify",
    fact={"pred": "confidence", "args": ["?x"], "deg": ["*", "?d", 1.1]}
)

# Retract action
action = Action(
    action="retract",
    predicate="temporary",
    args=["?x"]
)

# Convert to dict
action_dict = action.to_dict()
new_action = Action.from_dict(action_dict)

RuleBuilder

Builder pattern for constructing complex rules.

Example

rule = (RuleBuilder() ... .when('is-zebra', ['?x']) ... .with_degree_greater_than(0.5) ... .then_add('has-stripes', ['?x']) ... .with_degree_multiplied_by(0.9) ... .build())

Initialize the builder.

Source code in fuzzy_infer/models.py
def __init__(self):
    """Initialize the builder."""
    self.conditions = []
    self.actions = []
    self.current_condition = None
    self.current_action = None
    self.name = None
    self.priority = 0
    self.degree_var = None  # Track degree variable

conditions instance-attribute

conditions = []

actions instance-attribute

actions = []

current_condition instance-attribute

current_condition = None

current_action instance-attribute

current_action = None

name instance-attribute

name = None

priority instance-attribute

priority = 0

degree_var instance-attribute

degree_var = None

when

when(
    predicate: str, args: List[Union[str, Any]]
) -> RuleBuilder

Add a condition to the rule.

Source code in fuzzy_infer/models.py
def when(self, predicate: str, args: List[Union[str, Any]]) -> "RuleBuilder":
    """Add a condition to the rule."""
    self.current_condition = Condition(predicate=predicate, args=args)
    self.conditions.append(self.current_condition)
    return self

when_not

when_not(
    predicate: str, args: List[Union[str, Any]]
) -> RuleBuilder

Add a negated condition to the rule.

Source code in fuzzy_infer/models.py
def when_not(self, predicate: str, args: List[Union[str, Any]]) -> "RuleBuilder":
    """Add a negated condition to the rule."""
    self.current_condition = Condition(predicate=predicate, args=args, negated=True)
    self.conditions.append(self.current_condition)
    return self

with_degree_greater_than

with_degree_greater_than(
    threshold: float, var_name: str = "?d"
) -> RuleBuilder

Add a degree constraint to the current condition.

Source code in fuzzy_infer/models.py
def with_degree_greater_than(self, threshold: float, var_name: str = "?d") -> "RuleBuilder":
    """Add a degree constraint to the current condition."""
    if not self.current_condition:
        raise RuleValidationError("No condition to add degree constraint to")
    self.current_condition.degree_var = var_name
    self.current_condition.degree_constraint = [">", var_name, threshold]
    self.degree_var = var_name  # Store for later use
    return self

with_degree_less_than

with_degree_less_than(
    threshold: float, var_name: str = "?d"
) -> RuleBuilder

Add a degree constraint to the current condition.

Source code in fuzzy_infer/models.py
def with_degree_less_than(self, threshold: float, var_name: str = "?d") -> "RuleBuilder":
    """Add a degree constraint to the current condition."""
    if not self.current_condition:
        raise RuleValidationError("No condition to add degree constraint to")
    self.current_condition.degree_var = var_name  
    self.current_condition.degree_constraint = ["<", var_name, threshold]
    self.degree_var = var_name  # Store for later use
    return self

then_add

then_add(
    predicate: str,
    args: List[Union[str, Any]],
    degree: float = 1.0,
) -> RuleBuilder

Add an action to add a fact.

Source code in fuzzy_infer/models.py
def then_add(
    self, predicate: str, args: List[Union[str, Any]], degree: float = 1.0
) -> "RuleBuilder":
    """Add an action to add a fact."""
    fact = {"pred": predicate, "args": args, "deg": degree}
    self.current_action = Action(action_type="add", fact=fact)
    self.actions.append(self.current_action)
    return self

then_remove

then_remove(
    predicate: str, args: List[Union[str, Any]]
) -> RuleBuilder

Add an action to remove a fact.

Source code in fuzzy_infer/models.py
def then_remove(self, predicate: str, args: List[Union[str, Any]]) -> "RuleBuilder":
    """Add an action to remove a fact."""
    fact = {"pred": predicate, "args": args}
    self.current_action = Action(action_type="remove", fact=fact)
    self.actions.append(self.current_action)
    return self

with_degree_multiplied_by

with_degree_multiplied_by(factor: float) -> RuleBuilder

Modify the degree of the current action's fact.

Source code in fuzzy_infer/models.py
def with_degree_multiplied_by(self, factor: float) -> "RuleBuilder":
    """Modify the degree of the current action's fact."""
    if not self.current_action or self.current_action.action_type != "add":
        raise RuleValidationError("No add action to modify degree for")
    # Always create a degree variable for the first condition if none exists
    if not hasattr(self, 'degree_var') or self.degree_var is None:
        # Add degree variable to first condition
        if self.conditions:
            self.conditions[0].degree_var = "?_deg"
            self.degree_var = "?_deg"

    # Use the degree variable to multiply
    if self.degree_var:
        self.current_action.fact["deg"] = ["*", factor, self.degree_var]
    else:
        # Fallback to just using the factor
        self.current_action.fact["deg"] = factor
    return self

named

named(name: str) -> RuleBuilder

Set the rule's name.

Source code in fuzzy_infer/models.py
def named(self, name: str) -> "RuleBuilder":
    """Set the rule's name."""
    self.name = name
    return self

with_priority

with_priority(priority: int) -> RuleBuilder

Set the rule's priority.

Source code in fuzzy_infer/models.py
def with_priority(self, priority: int) -> "RuleBuilder":
    """Set the rule's priority."""
    self.priority = priority
    return self

build

build() -> Rule

Build and return the Rule object.

Source code in fuzzy_infer/models.py
def build(self) -> Rule:
    """Build and return the Rule object."""
    return Rule(
        conditions=self.conditions, actions=self.actions, name=self.name, priority=self.priority
    )

Examples

from fuzzy_infer.models import RuleBuilder

# Fluent rule construction
rule = (
    RuleBuilder("carnivore-rule")
    .when("eats-meat", ["?x"])
    .when("has-teeth", ["?x"], min_degree=0.5)
    .then_add("is-carnivore", ["?x"], degree=0.9)
    .with_priority(10)
    .build()
)

# Multiple conditions
rule = (
    RuleBuilder("flying-bird")
    .when("is-bird", ["?x"], degree_var="?d1")
    .when("has-wings", ["?x"], degree_var="?d2")
    .then_add("can-fly", ["?x"], degree=["*", ["min", "?d1", "?d2"], 0.9])
    .build()
)

# Multiple actions
rule = (
    RuleBuilder("complex-inference")
    .when("input", ["?x"])
    .then_add("output1", ["?x"], degree=0.8)
    .then_add("output2", ["?x"], degree=0.9)
    .then_modify("confidence", ["?x"], degree=["*", "?d", 1.2])
    .build()
)

Type Hints

from typing import Dict, List, Any, Optional
from fuzzy_infer.models import Fact, Rule, Condition, Action

# Fact type hints
def process_fact(fact: Fact) -> None: ...

# Rule type hints
def add_rules(rules: List[Rule]) -> None: ...

# Condition type hints
def check_condition(cond: Condition, bindings: Dict[str, Any]) -> bool: ...

# Action type hints
def execute_action(action: Action, bindings: Dict[str, Any]) -> Optional[Fact]: ...

JSON Serialization

All models support JSON serialization:

import json
from fuzzy_infer import Fact, Rule

# Fact
fact = Fact("is-bird", ["tweety"], 0.9)
json_str = json.dumps(fact.to_dict())
# '{"pred": "is-bird", "args": ["tweety"], "deg": 0.9}'

loaded_fact = Fact.from_dict(json.loads(json_str))

# Rule
rule = Rule(
    name="test-rule",
    conditions=[{"pred": "is-bird", "args": ["?x"]}],
    actions=[{"action": "add", "fact": {"pred": "can-fly", "args": ["?x"]}}]
)
json_str = json.dumps(rule.to_dict())
loaded_rule = Rule.from_dict(json.loads(json_str))