Syntax
I. Core Syntax and Basic Concepts
This section introduces the engine’s foundational syntax units: Constant, Concept, Variable, Operator, CompoundTerm, Assertion, Formula, and Rule.
1. Constant
A constant represents a specific individual entity. It must belong to at least one given concept (Concept) and is an indivisible basic unit.
Code form:
from al_inference_engine.syntax import Constant
constant_1 = Constant('constant_1', concept_1)
# Declare a constant named constant_1 that belongs to concept_1
String form:
WIP
2. Concept
A concept is a set of constants or concepts that share some common property.
Code form:
from al_inference_engine.syntax import Concept
concept_1 = Concept('concept_1') # Declare a concept named concept_1
String form:
WIP
2.1 Registering Subsumption (Subset) Relations
In real problems, concepts often form hierarchies, e.g. int ⊆ real, rational ⊆ real. If an operator parameter expects real, passing an int should be treated as type-compatible.
- Single relation: Maintained by a function on the
Conceptclass
Concept.add_subsumption("int", "real")
- Batch list: A wrapper around
add_subsumption
add_subsumptions([
("int", "real"),
("rational", "real"),
])
- Mapping (child -> list of parents): A wrapper around
add_subsumption
add_subsumptions_from_mapping({
"int": ["real"],
"rational": ["real"],
})
- String DSL (supports
⊆and<=; separators: comma / semicolon / newline): A wrapper aroundadd_subsumption
add_subsumptions_from_string("""
int ⊆ real, rational <= real;
positive_int <= int
""")
- Specify parent concepts at construction time:
Concept("int", parents=["real"])
- Chain-style setting of parent concepts:
Concept("int").set_parents(["real"])
All of the above approaches can be mixed. Duplicate declarations are automatically de-duplicated.
Example: registering subsumption relations
Real = Concept("real")
Int = Concept("int", parents=["real"])
PosInt = Concept("positive_int", parents=["int"])
to_real = Operator("to_real", input_concepts=["int"], output_concept="real")
# Expects int; passing positive_int is also OK (since positive_int ⊆ int)
t1 = CompoundTerm("to_real", [Constant(5, "positive_int")]) # OK
t2 = CompoundTerm("to_real", [Constant(5, "real")]) # Raises an exception
register_concept_relations("int ⊆ real")
# Attempting to register a reverse edge will raise an error
try:
Concept.add_subsumption("real", "int")
except ValueError as e:
print("Prevented mutual subsumption:", e)
3. Variable
A variable is a placeholder in logical expressions, used to refer to unknown or yet-to-be-determined objects. Variables are allowed only in rules and queries and must not appear in facts stored in the FactBase.
Code form:
from al_inference_engine.syntax import Variable
variable_1 = Variable('variable_1') # Declare a variable named variable_1
Tip: Variables with the same name are considered equal (hashed/compared by
name), even if they are different object instances.
String form:
WIP
4. Operator
An operator represents a relation or computation over constants and concepts. When defining an operator, you must specify:
- The list of input-parameter concepts:
input_concepts - The output concept:
output_concept(restricted to exactly one)
Code form:
from al_inference_engine.syntax import Operator
operator_1 = Operator(
'operator_1',
input_concepts=[concept_1, concept_2],
output_concept=concept_3
)
# Declare an operator named operator_1,
# with input concepts concept_1 and concept_2, and output concept concept_3
String form:
WIP
4.1 Action on Operator (Operators with External Implementations)
Operator can also take an implement_func argument to provide an external implementation (hereafter “executable operator”). In that case, the operator’s output is computed by implement_func and does not need to be explicitly stored in the FactBase.
Code form:
from al_inference_engine.syntax import Operator
def action_func(term):
# term is a FlatCompoundTerm; read term.arguments and compute
# Return value must be a TERM_TYPE (usually Constant or FlatCompoundTerm),
# and must satisfy output_concept
return result
action_op = Operator(
name="action_op",
input_concepts=[input_concept1, input_concept2],
output_concept=output_concept,
implement_func=action_func,
)
For executable operators, the corresponding
CompoundTermcurrently must be aFlatCompoundTerm(introduced below). FullCompoundTermsupport is not yet available and will be opened up in later versions.
If a
Rulecontains aCompoundTermwith an executable operator, then allVariables in thatCompoundTermmust also appear in otherAssertions that do not contain executable operators.
5. CompoundTerm
A compound term represents an operator applied to a list of arguments. The elements in the argument tuple can be:
ConstantVariable- Other
CompoundTerms
Code form:
from al_inference_engine.syntax import CompoundTerm
compoundterm_1 = CompoundTerm(operator_1, [constant_1, variable_1])
# Compound term with operator_1 and arguments (constant_1, variable_1)
compoundterm_2 = CompoundTerm(operator_2, [compoundterm_1, constant_2])
# Requirement: operator_1's output concept == operator_2's first input concept
String form:
WIP
Well-formedness requirement: For a well-formed
CompoundTerm, the concept of each argument (or the output concept of a nested compound term) must match the corresponding entry in theOperator’sinput_concepts, position by position.
5.1 FlatCompoundTerm (Atomic Compound Term)
An atomic compound term is a compound term whose arguments do not contain any other CompoundTerms.
Code form:
from al_inference_engine.syntax import FlatCompoundTerm
atom_compoundterm_1 = FlatCompoundTerm(operator_1, [constant_1, variable_1])
# Atomic compound term with operator_1 and arguments (constant_1, variable_1)
String form:
WIP
Usually you do not need to manually create FlatCompoundTerm; the engine will automatically convert a CompoundTerm to a FlatCompoundTerm when conditions are met.
6. Assertion
An assertion is the basic unit of knowledge, stating that “the left-hand side and the right-hand side refer to the same object/value”.
Code form:
from al_inference_engine.syntax import Assertion
assertion_1 = Assertion(compoundterm_1, compoundterm_2)
# Assert that compoundterm_1 equals compoundterm_2
String form:
WIP
7. Formula
A formula is composed of one or more Assertions connected by logical connectives. Supported connectives include:
'AND''OR''NOT''IMPLIES''EQUAL'
Code form:
from al_inference_engine.syntax import Formula
formula_1 = Formula(assertion_1, 'AND', assertion_2)
# Represents: assertion_1 AND assertion_2
formula_2 = Formula(formula_1, 'OR', assertion_3)
# Represents: (assertion_1 AND assertion_2) OR assertion_3
String form:
WIP
8. Rule
A rule consists of a condition formula (body) and a conclusion formula or assertion (head). The inference engine derives new facts from known facts using rules. You can set a rule priority (priority) to control execution order.
Code form:
from al_inference_engine.syntax import Rule
rule_1 = Rule(assertion_3, formula_1)
# If formula_1 holds, then assertion_3 holds as well
# (Note: constructor argument order is head, body)
String form:
WIP
- The constructor argument order for
RuleisRule(head, body, ...). Using keyword arguments (Rule(head=..., body=...)) is recommended to avoid mistakes.- Variables are allowed in
CompoundTerm/Assertiononly insideRules. Facts in the FactBase must not contain variables.- Internally, the engine converts
Formulain a rule into a clause list via DNF (conjunctions containing onlyAssertionandNOT Assertion) and splits it into multiple sub-rules; thereforeFormulamainly serves as syntactic sugar and does not cover the full semantics of all logical connectives.- The rule head supports only a single
Assertionor a conjunction ofAssertions connected only byAND.
II. Special Syntax
1. Intro: Presence/Introduction Marker
Intro(T) is used to indicate whether an instance of a CompoundTerm appears in some assertion in the FactBase.
Code form:
from al_inference_engine.syntax import Intro, CompoundTerm
compoundterm_1 = CompoundTerm(operator_1, [constant_1, variable_1])
I1 = Intro(compoundterm_1)
# I1 is true iff there exists an instance of the form
# CompoundTerm(operator_1, [constant_1, any_constant])
# that appears as a CompoundTerm in some Assertion in the FactBase
String form:
WIP
2. QueryStructure
QueryStructure specifies a query problem for the inference engine. You need to provide:
premises: a list of premise factsquestion: a list of formulas or assertions to be solved; multiple formulas/assertions are treated as a conjunction (i.e., they must all hold)
Code form:
from al_inference_engine.main import QueryStructure
querystructure_1 = QueryStructure(
premises=fact_list, # A list containing multiple Facts
question=formula_2 # The question to solve
)
String form:
WIP
III. Built-in Syntax and Built-in Operators
1. Built-in Concepts
Several built-in concepts are defined in al_inference_engine.knowledge_bases.builtin_base.builtin_concepts:
FREEVARANY: a placeholder concept. It should not be used in external APIs and is compatible with any Concept.Defining a custom
"FREEVARANY"concept will be rejected. Do not force-define it, or you may break placeholder behavior.BOOL_CONCEPT: the Boolean concept. All Boolean values should belong to this concept and use the presettrue_constandfalse_const.COMPLEX_NUMBER_CONCEPT: the complex-number concept.EQUATION_CONCEPT: the arithmetic-equation concept.
2. Built-in Constants
true_const: representsTruefalse_const: representsFalse
3. Built-in Operators
The following arithmetic-related operators are provided in al_inference_engine.knowledge_bases.builtin_base.builtin_operators. They all operate on complex numbers (belonging to COMPLEX_NUMBER_CONCEPT):
arithmetic_plus_op: additionarithmetic_minus_op: subtractionarithmetic_times_op: multiplicationarithmetic_divide_op: divisionarithmetic_negate_op: negation
All of the above are executable operators, and their results are computed by implementation functions.
IV. Safety
To ensure the inference engine runs correctly, rules and facts must satisfy the following safety constraints.
1. Fact Safety
An Assertion used as a Fact must not contain Variables (including initial facts and the premise facts in QueryStructure).
2. Rule Safety
For unsafe rules, the engine will proactively add Intro (and raise a warning) to ensure smooth usage. However, this may slow execution; users are advised to understand this section and manually optimize rules. For readability by non-engine specialists, safety is defined below in a segmented (non-recursive) way.
- Assign a boolean value T/F to each
Assertionin a rule body. Consider all assignments that can make the body true. If anAssertionis true under all such assignments, call it a T-typeAssertion. - Every
Variableappearing in the rule should appear in some T-typeAssertion. - Variables inside a
CompoundTermcontaining an executable operator must appear in at least one T-typeAssertionthat does not contain executable operators. - Any
CompoundTermcontaining an executable operator must be aFlatCompoundTerm.
Examples
- Safe rule example:
r(X) = r(Y) AND h(X) = h(Y) -> g(X) = 1
- Unsafe example 1:
r(X) = r(Y) OR h(Z) = h(Y) -> g(X) = 1
Reason: In the disjunctive branch h(Z) = h(Y), the variable X in the head does not appear.
- Unsafe example 2:
r(X) = r(Y) AND NOT(h(Z) = h(Y)) -> g(X) = 1
Reason: Variable Z appears only in a negated Assertion and does not appear in any non-negated Assertion.
```