How to Use Temporal Intelligence with Allen Interval Algebra in Knowledge Graphs
Semantica implements a fully deterministic temporal reasoning engine based on Allen interval algebra, exposing 13 precise interval relations through both Python API and CLI without any LLM dependency.
The semantica-agi/semantica repository provides native temporal intelligence capabilities for knowledge graphs, built directly on James F. Allen's foundational interval algebra from 1970. This article explains how to leverage these features for deterministic temporal reasoning in your knowledge graph applications.
Understanding Allen Interval Algebra in Semantica
Allen interval algebra defines 13 possible relations between two time intervals: BEFORE, MEETS, OVERLAPS, DURING, STARTS, FINISHES, EQUALS, plus their inverses. The semantica implementation encodes these relations in pure Python, making temporal queries fully reproducible and explainable.
The core implementation lives in semantica/kg/temporal_reasoning.py, specifically the TemporalReasoningEngine class (lines 44-79). This engine operates on the TemporalInterval data class, which stores:
start: A concretedatetimeobjectend: Either adatetimeorTemporalBound.OPENsentinel for unbounded intervals
When you call engine.relation(a, b), the method normalizes interval endings via _end_value (converting OPEN to datetime.max) and evaluates a cascade of comparisons that mirror the original Allen paper's logical ordering.
Core Components of the Temporal Engine
TemporalReasoningEngine
The TemporalReasoningEngine class provides the primary interface for Allen algebra operations. Its relation() method returns an IntervalRelation enum value representing how two intervals relate.
from semantica.kg.temporal_reasoning import (
TemporalReasoningEngine,
TemporalInterval,
)
engine = TemporalReasoningEngine()
TemporalInterval and TemporalBound
Intervals are immutable objects supporting both bounded and open-ended ranges:
from datetime import datetime
from semantica.kg.temporal_reasoning import TemporalInterval, TemporalBound
# Bounded interval
bounded = TemporalInterval(
start=datetime(2022, 1, 1),
end=datetime(2022, 1, 10)
)
# Open-ended interval (valid indefinitely)
open_ended = TemporalInterval(
start=datetime(2022, 1, 1),
end=TemporalBound.OPEN
)
Higher-Level Helper Methods
Beyond the raw relation() method, the engine provides convenient predicates for common queries:
| Method | Purpose | Allen Relations Covered |
|---|---|---|
overlaps(a, b) |
Check if intervals share any time | OVERLAPS, DURING, STARTS, FINISHES, EQUALS |
contains(a, b) |
Check if a fully contains b |
CONTAINS (inverse of DURING) |
active_at(a, point) |
Check if point falls within interval | Derived from DURING with zero-width interval |
gap_analysis(a, b) |
Calculate temporal distance between intervals | Used for scheduling and sequencing |
Using the Temporal Engine in Python
Basic Interval Comparison
from semantica.kg.temporal_reasoning import (
TemporalReasoningEngine,
TemporalInterval,
)
engine = TemporalReasoningEngine()
# Define two intervals using ISO-8601 strings
interval_a = TemporalInterval(
start=engine._coerce_datetime("2022-01-01T00:00:00Z"),
end=engine._coerce_datetime("2022-01-10T00:00:00Z"),
)
interval_b = TemporalInterval(
start=engine._coerce_datetime("2022-01-05T00:00:00Z"),
end=engine._coerce_datetime("2022-01-15T00:00:00Z"),
)
relation = engine.relation(interval_a, interval_b)
print(f"Relation: {relation.name}") # → Relation: OVERLAPS
Working with Open-Ended Intervals
from semantica.kg.temporal_reasoning import TemporalBound
# Current employment (open-ended)
current_role = TemporalInterval(
start=engine._coerce_datetime("2020-03-15T00:00:00Z"),
end=TemporalBound.OPEN
)
# Project period
project = TemporalInterval(
start=engine._coerce_datetime("2021-06-01T00:00:00Z"),
end=engine._coerce_datetime("2021-12-31T00:00:00Z")
)
# Check if project occurred during employment
relation = engine.relation(current_role, project)
print(f"Employment relation to project: {relation.name}") # → CONTAINS
CLI Interface for Temporal Queries
The semantica temporal allen command (implemented in semantica/cli.py, lines 58-66) provides direct access to Allen algebra without writing Python code.
Human-Readable Output
semantica temporal allen \
--interval1 "2022-01-01T00:00:00Z/2022-01-10T00:00:00Z" \
--interval2 "2022-01-05T00:00:00Z/2022-01-15T00:00:00Z"
Output:
2022-01-01T00:00:00Z/2022-01-10T00:00:00Z ── OVERLAPS ──► 2022-01-05T00:00:00Z/2022-01-15T00:00:00Z
Machine-Readable JSON Output
semantica temporal allen \
--interval1 "2022-01-01T00:00:00Z/2022-01-10T00:00:00Z" \
--interval2 "2022-01-05T00:00:00Z/2022-01-15T00:00:00Z" \
--json
Result:
{
"interval1": "2022-01-01T00:00:00Z/2022-01-10T00:00:00Z",
"interval2": "2022-01-05T00:00:00Z/2022-01-15T00:00:00Z",
"relation": "OVERLAPS"
}
Integrating Temporal Intelligence with Knowledge Graph Queries
The TemporalGraphQuery class leverages the same engine for filtering entities based on temporal constraints.
from semantica.kg import TemporalGraphQuery
tgq = TemporalGraphQuery(config={})
# Find events that contain a specific time window
events = tgq.query(
"MATCH (e) WHERE e.valid_from <= '2022-03-01' AND e.valid_until >= '2022-04-01' RETURN e"
)
Under the hood, this translates to Allen's CONTAINS relation between the entity's validity interval and the query interval. The engine's deterministic logic ensures consistent results across all temporal graph operations.
Parsing and Serialization Utilities
The semantica/kg/temporal_model.py file provides helper functions for converting between string representations and internal datetime objects:
parse_temporal_value(): Handles ISO-8601 strings, Unix timestamps, and datetime objectsparse_temporal_bound(): Specifically handles theOPENsentinel and bounded endpointsBiTemporalFact: Wrapper class combining valid-time and transaction-time dimensions
These utilities ensure consistent temporal value handling across the entire knowledge graph stack.
Summary
- Allen interval algebra provides 13 precise relations for temporal reasoning, fully implemented in
TemporalReasoningEngineatsemantica/kg/temporal_reasoning.py - Pure Python implementation means deterministic, explainable results without LLM dependency or external service calls
TemporalIntervalsupports both bounded and open-ended ranges viaTemporalBound.OPEN- CLI access via
semantica temporal allenenables quick interval testing with human or JSON output - Integration points include
TemporalGraphQueryfor KG filtering and extension points for version management and retroactive analysis
Frequently Asked Questions
What are the 13 Allen interval relations supported by Semantica?
The complete set includes: BEFORE, MEETS, OVERLAPS, DURING, STARTS, FINISHES, EQUALS, and their inverses (AFTER, MET_BY, OVERLAPPED_BY, CONTAINS, STARTED_BY, FINISHED_BY). The TemporalReasoningEngine.relation() method returns the most specific applicable relation as an IntervalRelation enum value.
How does Semantica handle unbounded or ongoing time intervals?
Open-ended intervals use TemporalBound.OPEN as the end value. The engine's _end_value() helper converts this to datetime.max during comparison, effectively treating ongoing intervals as extending to the maximum representable time. This allows CONTAINS and other relations to evaluate correctly against fixed-date intervals.
Can I use temporal reasoning without the full knowledge graph?
Yes. The TemporalReasoningEngine has no dependencies on other semantica components. Import directly from semantica.kg.temporal_reasoning and use it for any interval comparison logic, or use the semantica temporal allen CLI command for standalone queries.
Where are the Allen algebra test cases located?
Comprehensive unit tests verifying all 13 interval relations are in semantica/tests/kg/test_temporal_reasoning.py. These tests exercise edge cases including equal endpoints, adjacent intervals (MEETS), and open-ended comparisons.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →