API Documentation

The heart of the Clorm ORM involves defining the mapping from ground predicates to member variables of a Python object. There are two aspects to this: fields, that define how logical terms are mapped to Python objects, and predicate definitions, that define predicate and function names, their arities and the appropriate field for each of the parameters.

Fields

Fields provide a specification for how to convert clingo.Symbol objects into the appropriate/intuitive Python object. As of Clorm version 1.5, the preferred mechanism to specify fields is to use standard Python type annotations. The primitive logical terms integer and string are specified using the standard Python type int and str respectively, while logical constant terms are specified using a specially defined type:

class clorm.ConstantStr

A special str sub-class for specifying constant logical terms.

Internally within Clorm the type specifiers are mapped to a set of special classes that contain the functions for converting between Python and the clingo.Symbol objects. These special classes are referred to as field definitions and are subclassed from a common base class BaseField.

class clorm.BaseField(default: ~typing.Any = <clorm.orm.core._MISSING_TYPE object>, index: ~typing.Any = <clorm.orm.core._MISSING_TYPE object>)

Define a mapping from ASP logical terms to Python objects.

A field is used as part of a ComplexTerm or Predicate definition. It specifies the translation between ASP terms and Python objects.

It contains two class functions cltopy and pytocl that implement the translation from Clingo to Python and Python to Clingo respectively. For BaseField these functions are abstract. StringField, IntegerField, and ConstantField are standard sub-classes that provide translations for the ASP simple terms; string, integer and constant.

These BaseField subclasses can be further sub-classes to build a chain of translations.

To sub-class BaseField (or one of its sub-classes) simply specify cltopy and pytocl functions that take an input and perform some translation to an output format.

RawField is a special BaseField sub-class that provides direct pass-through for raw clingo symbol objects. It cannot be sub-classed further.

Note: the cltopy and pytocl functions are legitmately allowed to throw either a TypeError or ValueError exception when provided with bad input. These exceptions will be treated as a failure to unify when trying to unify clingo symbols to facts. However, any other exception is passed through as a genuine error. This should be kept in mind if you are writing your own field class.

Example

import datetime

class DateField(StringField):
          pytocl = lambda dt: dt.strftime("%Y%m%d")
          cltopy = lambda s: datetime.datetime.strptime(s,"%Y%m%d").date()

Because DateField sub-classes StringField, rather than sub-classing BaseField directly, it forms a longer data translation chain:

clingo symbol object – BaseField – StringField – DateField – python date object

Here the DateField.cltopy is called at the end of the chain of translations, so it expects a Python string object as input and outputs a date object. DateField.pytocl does the opposite and inputs a date object and is expected to output a Python string object.

Parameters:
  • default – A default value (or function) to be used when instantiating a Predicate or ComplexTerm object. If a Python callable object is specified (i.e., a function or functor) then it will be called (with no arguments) when the predicate/complex-term object is instantiated.

  • index (bool) – Determine if this field should be indexed by default in a FactBase`. Defaults to False.

abstract static cltopy(v)

Called when translating data from Clingo to Python

abstract static pytocl(v)

Called when translating data from Python to Clingo

property default

Returns the default value for the field (or None if no default was set).

Note: 1) if a function was specified as the default then testing default will call this function and return the value, 2) if your BaseField sub-class allows a default value of None then you need to check the has_default property to distinguish between no default value and a None default value.

property has_default

Returns whether a default value has been set

property has_default_factory

Returns whether a default value has been set

property index

Returns whether this field should be indexed by default in a FactBase

For sub-classes of BaseField the abstract member functions cltopy() and pytocl() must be implemented to provide the conversion from Clingo to Python and Python to Clingo (respectively).

Clorm provides three standard sub-classes corresponding to the string, constant, and integer primitive logical terms: StringField, ConstantField, and IntegerField.

class clorm.StringField(default: ~typing.Any = <clorm.orm.core._MISSING_TYPE object>, index: ~typing.Any = <clorm.orm.core._MISSING_TYPE object>)

A field to convert between a Clingo.String object and a Python string.

class clorm.ConstantField(default: ~typing.Any = <clorm.orm.core._MISSING_TYPE object>, index: ~typing.Any = <clorm.orm.core._MISSING_TYPE object>)

A field to convert between a simple Clingo.Function object and a Python string.

Note: currently ConstantField treats a string with a starting “-” as a negated constant. In hindsight this was a mistake and is now deprecated. While I don’t think anyone actually used this functionality (since it was never documented) nevertheless I will keep it there until the Clorm version 2.0 release.

class clorm.IntegerField(default: ~typing.Any = <clorm.orm.core._MISSING_TYPE object>, index: ~typing.Any = <clorm.orm.core._MISSING_TYPE object>)

A field to convert between a Clingo.Number object and a Python integer.

clorm.field(basefield: Type[BaseField] | Tuple[_FieldDefinition, ...]) Any
clorm.field(basefield: Type[BaseField] | Tuple[_FieldDefinition, ...], *, default: _T) _T
clorm.field(basefield: Type[BaseField] | Tuple[_FieldDefinition, ...], *, default: _T, kw_only: bool) _T
clorm.field(basefield: Type[BaseField] | Tuple[_FieldDefinition, ...], *, default_factory: Callable[[], _T]) _T

Return a field definition.

This function is used to override the type annotation field specification. A different field can be specificied as well as default values.

This function operates in a similar way to dataclass.field() in that it allows for more field specification options.

Special Fields

Clorm provides a number of fields for some special cases. The SimpleField can be used to define a field that matches to any primitive type. Note, however that special care should be taken when using SimpleField. While it is easy to disambiguate the Clingo to Python direction of the translation, it is harder to disambiguate between a string and constant when converting from Python to Clingo, since strings and constants are both represented using str. For this direction a regular expression is used to perform the disambiguation, and the user should therefore be careful not to pass strings that look like constants if the intention is to treat it like a logical string.

class clorm.SimpleField(default: ~typing.Any = <clorm.orm.core._MISSING_TYPE object>, index: ~typing.Any = <clorm.orm.core._MISSING_TYPE object>)

A class that represents a field corresponding to any simple term: string, constant, or integer.

Converting from an ASP string, constant, or integer will produce the expected Python string or integer object. However, since ASP strings and constants both map to Python strings therefore converting from Python to ASP is less straightforward. In this case it uses a regular expression to determine if the string matches an ASP constant or if it should be treated as a quoted string.

Because of this potential for ambiguity it is often better to use the distinct IntegerField, ConstantField, and StringField classes rather than the SimpleField class.

A RawField is useful when it is necessary to match any term, whether it is a primitive term or a complex term. This encoding provides no traslation of the underlying Clingo Symbol object and simply wraps it in a special Raw class.

class clorm.Raw(symbol: Symbol | NoSymbol)

A wrapper around a raw Symbol object.

The Raw object is for use with a RawField field definition. It provides a thin wrapper around a clingo.Symbol (or noclingo.Symbol) objects. RawField unifies with all symbols as it doesn’t try to access any of the underlying structure of the symbol object. Instead the symbol object is wrapped in a Raw object. To access the underlying clingo.Symbol object simply access the read-only symbol property.

property symbol

Access the underlying clingo.Symbol object``.

class clorm.RawField(default: ~typing.Any = <clorm.orm.core._MISSING_TYPE object>, index: ~typing.Any = <clorm.orm.core._MISSING_TYPE object>)

A field that unifies with any raw symbol.

RawField unifies with all symbols as it doesn’t try to access any of the underlying structure of the symbol object. Instead the symbol object is wrapped in a Raw object. To access the underlying clingo.Symbol object simply access the read-only symbol property of the Raw object.

Finally, there are a number of function generators that can be used to define some special cases; refining or combining existing fields or allowing for a complicated pattern of fields. While Clorm doesn’t explicitly allow recursive terms to be defined it does provide a number of encodings of list like terms. Note, it is sometimes possible to avoid the explicit use of these functions and instead to rely on some predefined type annotation mappings.

clorm.refine_field(field_class: Type[_BF], values: Iterable[_T] | Callable[[_T], bool], *, name: str | None = None) Type[_BF]

Factory function that returns a field sub-class with restricted values.

A helper factory function to define a sub-class of a BaseField (or sub-class) that restricts the allowable values. For example, if you have a constant in a predicate that is restricted to the days of the week (“monday”, …, “sunday”), you then want the Python code to respect that restriction and throw an error if the user enters the wrong value (e.g. a spelling error such as “wednsday”). Restrictions are also useful for unification if you want to unify based on some specific value.

Example

 WorkDayField = refine_field(ConstantField,
    ["monday", "tuesday", "wednesday", "thursday", "friday"])

class WorksOn(Predicate):
    employee = ConstantField()
    workday = WorkdDayField()

Instead of a passing a list of values the second parameter can also be a function/functor. If is parameter is callable then it is treated as a function that takes a field value and returns true if it is a valid value.

Example

PosIntField = refine_field(NumberField,lambda x : x >= 0)

The function must be called using positional arguments with either 2 or 3 arguments. For the 3 argument case a class name is specified for the name of the new field. For the 2 argument case an anonymous field class name is automatically generated.

Example

WorkDayField = refine_field(ConstantField,
   ["monday", "tuesday", "wednesday", "thursday", "friday"])

Positional argument:

field_class: the field that is being sub-classed

values|functor: a list of values or a functor to determine validity

Optional keyword-only arguments:

name: name for new class (default: anonymously generated).

clorm.define_enum_field(parent_field: Type[BaseField], enum_class: Type[Enum], *, name: str = '') Type[BaseField]

Factory function that returns a BaseField sub-class for an Enum

Enums are part of the standard library since Python 3.4. This method provides an alternative to using refine_field() to provide a restricted set of allowable values.

Example

class IO(ConstantStr,Enum):
    IN="in"
    OUT="out"

# A field that unifies against ASP constants "in" and "out"
IOField = define_enum_field(ConstantField,IO)

# Note, when specified within a Predicate it is possible to avoid calling this
# function directly and the predicate class should simply reference the ``IO`` type
# annotation.

class X(Predicate):
   x: IO

Positional argument:

field_class: the field that is being sub-classed

enum_class: the Enum class

Optional keyword-only arguments:

name: name for new class (default: anonymously generated).

clorm.combine_fields(fields: Sequence[Type[BaseField]], *, name: str = '') Type[BaseField]

Factory function that returns a field sub-class that combines other fields

A helper factory function to define a sub-class of BaseField that combines other BaseField subclasses. The subclass is defined such that it’s pytocl() (respectively cltopy()) function tries to return the value returned by the underlying sub-field’s pytocl() ( (respectively cltopy()) function. If the first sub-field fails then the second is called, and so on until there are no matching sub-fields. If there is no match then a TypeError is raised.

Example

MixedField = combine_fields([ConstantField,IntegerField])

Positional args:

field_subclasses: the fields to combine

Optional keyword-only arguments:

name: name for new class (default: anonymously generated).

clorm.define_nested_list_field(element_field: Type[BaseField], *, headlist: bool = True, reverse: bool = False, name: str = '') Type[BaseField]

Factory function that returns a BaseField sub-class for nested lists

This function is a helper factory function to define a sub-class of BaseField that can covert a list of elements to/from ASP.

ASP doesn’t have an explicit notion of a sequence or list, but sometimes it is useful to encode a list as a series of nested pairs. There are two basic ways to do this, with each way having two sub-forms:

(head,list) - the list is encoded recursively with a first head element and a second element representing the remainder of the list. The end of the list is indicated by an empty tuple.

Example:

(1,(2,(3,())))         % Encodes a sequence (1,2,3)

The sub-form is for the list to be treated as reversed in the ASP encoding.

Example:

(3,(2,(1,())))         % Encodes a sequence (1,2,3)

(list,tail) - the list is encoded recursively as a sub-list first element and a second tail element. The empty sub-list is indicated by an empty tuple.

Example:

((((),1),2),3)         % Encodes a sequence (1,2,3)

Again the sub-form version is to reverse the list.

((((),3),2),1)         % Encodes a sequence (1,2,3)

The choice of nested list encodings will depend on how it is used within the ASP code. However, the head-list-pair approach in non-reverse order is also used in lisp and prolog so for this reason it is set as the default approach here.

Note: the fields of facts should be immutable. This means that you must use a tuple and not a list object when creating the sequence.

Example

# Unifies against a nested sequence of constants
NestedListField = define_nested_list_field(ConstantField,name="NLField")

Positional args:

element_field: the field type for each sequence element

Optional keyword-only arguments:

name: name for new class (default: anonymously generated).

headlist: use head-list encoding (default: True)

reverse: use the reverse order for the list (default: False)

clorm.define_flat_list_field(element_field: Type[BaseField], *, name: str = '') Type[BaseField]

Factory function that returns a BaseField sub-class for flat lists

This function is a helper factory function to define a sub-class of BaseField to can covert a list/tuple of elements to and from arbitrary length ASP tuples.

Note: this is different to defining a fixed-length tuple in Clorm as a sub-class of clorm.Predicate. The elements of a predicate can be can be part of a query search. In contrast the variable length tuple defined by this function provide a more straightforward mapping but doesn’t allow for individual elements of the tuple to be referenced in a query.

Example

# Unifies against a flat sequence of constants
FlatListField = define_flat_list_field(ConstantField)

Positional args:

element_field: the field type for each sequence element

Optional keyword-only arguments:

name: name for new class (default: anonymously generated).

Predicates and complex terms

In logical terminology predicates and terms are both considered non logical symbols; where the logical symbols are the operator symbols for conjunction, negation, implication, etc. While simple terms (constants, strings, and integers) are handled by Clorm as special cases, complex terms and predicates are both encapsulated in the Predicate class, with ComplexTerm simply being an alias to this class.

class clorm.Predicate(*args, **kwargs)

Encapsulates an ASP predicate or complex term in an easy to access object.

This is the heart of the ORM model for defining the mapping of a complex term or predicate to a Python object. ComplexTerm is simply an alias for Predicate.

Example

class Booking(Predicate):
    date: str
    time: str
    name: str = field(StringField, default="relax")

b1 = Booking("20190101", "10:00")
b2 = Booking("20190101", "11:00", "Dinner")

Field names can be any valid Python variable name subject to the following restrictions:

  • it cannot start with a “_”, or

  • it cannot be be one of the following reserved words: “meta”, “raw”, “clone”, or “Field”.

The constructor creates a predicate instance (i.e., a fact) or complex term.

Note: Using the raw parameter is no longer supported. You should use the unify() function or Unifier class instead.

Parameters:

**kwargs

  • if a single named parameter raw is specified then it will try to unify the parameter with the specification, or

  • named parameters corresponding to the field names.

Field

A BaseField sub-class corresponding to a field definition for this class.

meta

The meta data (definitional information) for the Predicate. It contains:

name

The name of the ASP predicate/complex-term. Empty if it is a tuple.

is_tuple

Is the ASP predicate/complex-term a tuple.

arity

Arity of the predicate/complex-term.

clorm.ComplexTerm

alias of Predicate

clorm.simple_predicate(predicate_name: str, arity: int, *, name: str = '', module: str = '') Type[Predicate]

Factory function to define a predicate with only RawField arguments.

A helper factory function that takes a name and an arity and returns a predicate class that is suitable for unifying with predicate instances of that name and arity. It’s parameters are all specified as RawFields.

This function is useful for debugging ASP programs. There may be some auxillary predicates that you aren’t interested in extracting their values but instead you simply want to print them to the screen in some order.

The function must be called using positional arguments with either 2 or 3 arguments. For the 3 argument case a class name is specified for the name of the new predicate. For the 2 argument case an anonymous predicate class name is automatically generated.

Positional argument:

predicate_name: the name of the ASP predicate to match against

arity: the arity for the ASP predicate

Optional keyword-only arguments:

name: name for new class (default: anonymously generated).

Fact Bases and Queries

Predicate instances correspond to facts. A FactBase provides a container for storing facts. It allows predicate fields to be indexed and provides a basic query mechanism for accessing elements.

class clorm.FactBase(facts: Iterable[Predicate] | Callable[[], Iterable[Predicate]] | None = None, indexes: Iterable[PredicatePath] | None = None)

A fact base is a container for facts (i.e., Predicate sub-class instances)

FactBase can be behave like a specialised set object, but can also behave like a minimalist database. It stores facts for Predicate types (where a predicate type loosely corresponds to a table in a database) and allows for certain fields to be indexed in order to perform more efficient queries.

The initaliser can be given a collection of predicates. If it is passed another FactBase then it simply makes a copy (including the indexed fields).

FactBase also has a special mode when it is passed a functor instead of a collection. In this case it performs a delayed initialisation. This means that the internal data structures are only populated when the FactBase is actually used. This mode is particularly useful when extracting facts from models. Often a program will only want to keep the data from the final model (for example, with optimisation we often want the best model before a timeout). Delayed initialisation is useful will save computation as only the last model will be properly initialised.

Parameters:
  • facts ([Predicate]|FactBase|callable) – a list of facts (predicate instances), a fact base, or a functor that generates a list of facts. If a functor is passed then the fact base performs a delayed initialisation. If a fact base is passed and no index is specified then an index will be created matching in input fact base.

  • indexes (Field) – a list of fields that are to be indexed.

add(arg: Predicate | Iterable[Predicate]) None

Add a single fact or a collection of facts.

Because a FactBase can only hold Predicate sub-class instances this member function has been overloaded to take either a single Predicate sub-class instance or a collection of Predicate sub-class instances.

Parameters:

arg – a single fact or a collection of facts.

asp_str(*, width: int = 0, commented: bool = False, sorted: bool = False) str

Return a ASP string representation of the fact base.

The generated ASP string representation is syntactically correct ASP code so is suitable for adding as the input to to an ASP program (or writing to a file for later use in an ASP program).

By default the order of the facts in the string is arbitrary. Because FactBase is built on a OrderedDict (which preserves insertion order) the order of the facts will be deterministic between runs of the same program. However two FactBases containing the same facts but constructed in different ways will not produce the same output string. In order to guarantee the same output the sorted flag can be specified.

Parameters:
  • width – tries to fill to a given width by putting more than one fact on a line if necessary (default: 0).

  • commented – produces commented ASP code by adding a predicate signature and turning the Predicate sub-class docstring into a ASP comments (default: False).

  • sorted – sort the output facts, first by predicates (name,arity) and then by the natural order of the instances for that predicate (default :False).

clear()

Clear the fact base of all facts.

copy() FactBase

Implements the set copy() function

difference(*others: Iterable[Predicate] | Callable[[], Iterable[Predicate]]) FactBase

Implements the set difference() function

difference_update(*others: Iterable[Predicate] | Callable[[], Iterable[Predicate]]) None

Implements the set difference_update() function

discard(arg: Predicate) None

Remove a fact from the fact base.

facts() List[Predicate]

Return all facts.

intersection(*others: Iterable[Predicate] | Callable[[], Iterable[Predicate]]) FactBase

Implements the set intersection() function

intersection_update(*others: Iterable[Predicate] | Callable[[], Iterable[Predicate]]) None

Implements the set intersection_update() function

pop() Predicate

Pop an element from the FactBase.

query(__ent0: Type[_T0]) UnGroupedQuery[_T0]
query(__ent0: Type[_T0], __ent1: Type[_T1]) UnGroupedQuery[Tuple[_T0, _T1]]
query(__ent0: Type[_T0], __ent1: Type[_T1], __ent2: Type[_T2]) UnGroupedQuery[Tuple[_T0, _T1, _T2]]
query(__ent0: Type[_T0], __ent1: Type[_T1], __ent2: Type[_T2], __ent3: Type[_T3]) UnGroupedQuery[Tuple[_T0, _T1, _T2, _T3]]
query(__ent0: Type[_T0], __ent1: Type[_T1], __ent2: Type[_T2], __ent3: Type[_T3], __ent4: Type[_T4]) UnGroupedQuery[Tuple[_T0, _T1, _T2, _T3, _T4]]
query(*roots: Any) UnGroupedQuery[Any]

Define a query using the new Query API Query.

The parameters consist of a predicates (or aliases) to query (like an SQL FROM clause).

Parameters:

*predicates – predicate or predicate aliases

Returns:

Returns a Query object for specifying a query.

remove(arg: Predicate) None

Remove a fact from the fact base (raises an exception if no fact).

select(root)

Define a select query using the old Query API.

Note

This interface will eventually be deprecated when the new Query API is finalised. The entry point to this Query API is through the FactBase.query() method.

Parameters:

predicate – The predicate to query.

Returns:

Returns a Select query object for specifying a query.

symmetric_difference(other: Iterable[Predicate] | Callable[[], Iterable[Predicate]]) FactBase

Implements the set symmetric_difference() function

symmetric_difference_update(other: Iterable[Predicate] | Callable[[], Iterable[Predicate]]) None

Implements the set symmetric_difference_update() function

union(*others: Iterable[Predicate] | Callable[[], Iterable[Predicate]]) FactBase

Implements the set union() function

update(*others: Iterable[Predicate] | Callable[[], Iterable[Predicate]]) None

Implements the set update() function

property predicates: Tuple[Type[Predicate], ...]

Return the list of predicate types that this fact base contains.

A FactBase can generate formatted ASP facts using the function FactBase.add(). This string of facts can be passed to the solver or written to a file to be read. Mirroring this functionality an ASP string or file containing facts can also be read directly into a FactBase (without the indirect process of having to create a clingo.Control object).

clorm.parse_fact_string(aspstr: str, unifier: Iterable[Type[Predicate]], *, factbase: FactBase | None = None, raise_nomatch: bool = False, raise_nonfact: bool = False) FactBase

Parse a string of ASP facts into a FactBase

Facts must be of a simple form that can correspond to clorm predicate instances. Rules that are NOT simple facts include: any rule with a body, a disjunctive fact, a choice rule, a theory atom, a literal with an external @-function reference, a literal that requires some mathematical calculation (eg., “p(1+1).”)

NOTE: Currently, this function is not safe when running in NOCLINGO mode and will raise a NotImplementedError if called.

Parameters:
  • aspstr – an ASP string containing the facts

  • factbase – if no factbase is specified then create a new one

  • unifier – a list of clorm.Predicate classes to unify against

  • raise_nomatch – raise UnifierNoMatchError on a fact that cannot unify

  • raise_nonfact – raise FactParserError on any non simple fact (eg. complex rules)

clorm.parse_fact_files(files: Sequence[str], unifier: Iterable[Type[Predicate]], *, factbase: FactBase | None = None, raise_nomatch: bool = False, raise_nonfact: bool = False) FactBase

Parse the facts from a list of files into a FactBase

Facts must be of a simple form that can correspond to clorm predicate instances. Rules that are NOT simple facts include: any rule with a body, a disjunctive fact, a choice rule, a theory atom, a literal with an external @-function reference, a literal that requires some mathematical calculation (eg., “p(1+1).”)

NOTE: Currently, this function is not safe when running in NOCLINGO mode and will raise a NotImplementedError if called.

Parameters:
  • files – a list of ASP files containing the facts

  • factbase – if no factbase is specified then create a new one

  • unifier – a list of clorm.Predicate classes to unify against

  • raise_nomatch – raise UnifierNoMatchError on a fact that cannot unify

  • raise_nonfact – raise FactParserError on any non simple fact (eg. complex rules)

One of the more important features of a FactBase is its ability to be queried. There are a number of classes and functions to support the specification of fact base queries.

class clorm.Placeholder

An abstract class for defining parameterised queries.

Currently, Clorm supports 4 placeholders: ph1_, ph2_, ph3_, ph4_. These correspond to the positional arguments of the query execute function call.

class clorm.Select

An abstract class that defines the interface to original Query API.

Note

This interface will eventually be deprecated when the new Query API is finalised.

Select query objects cannot be constructed directly. Instead a Select object is returned by the FactBase.select() function. Given a FactBase object fb, a specification is of the form:

query = fb.select(<predicate>).where(<expression>).order_by(<ordering>)

where <predicate> specifies the predicate type to search for, <expression> specifies the search criteria and <ordering> specifies a sort order when returning the results. The where() and order_by() clauses are omitted when not required.

abstract where(*expressions)

Set the select statement’s where clause.

The where clause consists of a set of boolean and comparison expressions. This expression specifies a search criteria for matching facts within the corresponding FactBase.

Boolean expression are built from other boolean expression or a comparison expression. Comparison expressions are of the form:

<PredicatePath> <compop>  <value>

where <compop> is a comparison operator such as ==, !=, or <= and <value> is either a Python value or another predicate path object refering to a field of the same predicate or a placeholder.

A placeholder is a special value that issubstituted when the query is actually executed. These placeholders are named ph1_, ph2_, ph3_, and ph4_ and correspond to the 1st to 4th arguments of the get, get_unique or count function call.

Args:

expressions: one or more comparison expressions.

Returns:

Returns a reference to itself.

abstract order_by(*fieldorder)

Provide an ordering over the results.

Parameters:

fieldorder – an ordering over fields

Returns:

Returns a reference to itself.

abstract get(*args, **kwargs)

Return all matching entries.

get_unique(*args, **kwargs)

Return the unique matching entry (or raise an exception)

count(*args, **kwargs)

Return the number of matches.

class clorm.Delete

An abstract class that defines the interface to a original delete query API.

Note

This interface will eventually be deprecated when the new Query API is finalised.

Delete query objects cannot be constructed directly. Instead a Delete object is returned by the FactBase.delete() function. Given a FactBase object fb, a specification is of the form:

query = fb.delete(<predicate>).where(<expression>)

where <predicate> specifies the predicate type to search for, <expression> specifies the search criteria. The where() clause can be omitted in which case all predicates of that type will be deleted.

abstract where(*expressions)

Set the select statement’s where clause.

See the documentation for Select.where() for further details.

abstract execute(*args, **kwargs)

Function to execute the delete query

class clorm.Query

An abstract class that defines the interface to the Clorm Query API v2.

Note

This new Query API replaces the old Select/Delete mechanism and offers many more features than the old API, especially allowing joins similar to an SQL join between tables.

This interface is complete and unlikely to change - however it is being left open for the moment in case there is strong user feedback.

Query objects cannot be constructed directly.

Instead a Query object is returned by the FactBase.query() function. Queries can take a number of different forms but contain many of the components of a traditional SQL query. A predicate definition (as opposed to a predicate instance or fact) can be viewed as an SQL table and the parameters of a predicate can be viewed as the fields of the table.

The simplest query must at least specify the predicate(s) to search for. This is specified as parameters to the FactBase.query() function. Relating this to a traditional SQL query, the query clause can be viewed as an SQL FROM specification.

The query is typicaly executed by iterating over the generator returned by the Query.all() end-point.

from clorm import FactBase, Predicate, IntegerField, StringField

class Option(Predicate):
    oid = IntegerField
    name = StringField
    cost = IntegerField
    cat = StringField

class Chosen(Predicate):
    oid = IntegerField

fb=FactBase([Option(1,"Do A",200,"foo"),Option(2,"Do B",300,"bar"),
             Option(3,"Do C",400,"foo"),Option(4,"Do D",300,"bar"),
             Option(5,"Do E",200,"foo"),Option(6,"Do F",500,"bar"),
             Chosen(1),Chosen(3),Chosen(4),Chosen(6)])

q1 = fb.query(Chosen)     # Select all Chosen instances
result = set(q1.all())
assert result == set([Chosen(1),Chosen(3),Chosen(4),Chosen(6)])

If there are multiple predicates involved in the search then the query must also contain a Query.join() clause to specify the predicates parameters/fields to join.

q2 = fb.query(Option,Chosen).join(Option.oid == Chosen.oid)

Note

As an aside, while a query clause typically consists of predicates, it can also contain predicate aliases created through the alias() function. This allows for queries with self joins to be specified.

When a query contains multiple predicates the result will consist of tuples, where each tuple contains the facts matching the signature of predicates in the query clause. Mathematically the tuples are a subset of the cross-product over instances of the predicates; where the subset is determined by the join clause.

result = set(q2.all())

assert result == set([(Option(1,"Do A",200,"foo"),Chosen(1)),
                      (Option(3,"Do C",400,"foo"),Chosen(3)),
                      (Option(4,"Do D",300,"bar"),Chosen(4)),
                      (Option(6,"Do F",500,"bar"),Chosen(6))])

A query can also contain a where clause as well as an order_by clause. When the order_by clause contains a predicate path then by default it is ordered in ascending order. However, this can be changed to descending order with the desc() function modifier.

from clorm import desc

q3 = q2.where(Option.cost > 200).order_by(desc(Option.cost))

result = list(q3.all())
assert result == [(Option(6,"Do F",500,"bar"),Chosen(6)),
                  (Option(3,"Do C",400,"foo"),Chosen(3)),
                  (Option(4,"Do D",300,"bar"),Chosen(4))]

The above code snippet highlights a feature of the query construction process. Namely, that these query construction functions can be chained and can also be used as the starting point for another query. Each construction function returns a modified copy of its parent. So in this example query q3 is a modified version of query q2.

Returning tuples of facts is often not the most convenient output format and instead you may only be interested in specific predicates or parameters within each fact tuple. For example, in this running example it is unnecessary to return the Chosen facts. To provide the output in a more useful format a query can also contain a select clause that specifies the items to return. Essentially, this specifies a _projection_ over the elements of the result tuple.

q4 = q3.select(Option)

result = list(q4.all())
assert result == [Option(6,"Do F",500,"bar"),
                  Option(3,"Do C",400,"foo"),
                  Option(4,"Do D",300,"bar")]

A second mechanism for accessing the data in a more convenient format is to use a group_by clause. In this example, we may want to aggregate all the chosen options, for example to sum the costs, based on their membership of the "foo" and "bar" categories. The Clorm query API doesn’t directly support aggregation functions, as you could do in SQL, so some additional Python code is required.

q5 = q2.group_by(Option.cat).select(Option.cost)

result = [(cat, sum(list(it))) for cat, it in q5.all()]
assert result == [("bar",800), ("foo", 600)]

The above are not the only options for a query. Some other query modifies include: Query.distinct() to return distinct elements, and Query.bind() to bind the value of any placeholders in the where clause to specific values.

A query is executed using a number of end-point functions. As already shown the main end-point is Query.all() to return a generator for iterating over the results.

Alternatively, if there is at least one element then to return the first result only (throwing an exception only if there are no elements) use the Query.first() method.

Or if there must be exactly one element (and to throw an exception otherwise) use Query.singleton().

To count the elements of the result there is Query.count().

Finally to delete all matching facts from the underlying FactBase use Query.delete().

abstract join(*expressions)

Specifying how the predicate/tables in the query are to be joined.

Joins are expressions that connect the predicates/tables of the query. They range from a pure SQL-like inner-join through to an unrestricted cross-product. The standard form is:

<PredicatePath> <compop> <PredicatePath>

with the full cross-product expressed using a function:

cross(<PredicatePath>,<PredicatePath>)

Every predicate/table in the query must be reachable to every other predicate/table through some form of join. For example, given predicate definitions F, G, H, each with a field anum:

query = fb.query(F,G,H).join(F.anum == G.anum,cross(F,H))

generates an inner join between F and G, but a full cross-product between F and H.

Finally, it is possible to perform self joins using the function alias that generates an alias for the predicate/table. For .. rubric:: Example

from clorm import alias

FA=alias(F) query = fb.query(F,G,FA).join(F.anum == FA.anum,cross(F,G))

generates an inner join between F and itself, and a full cross-product between F and G.

Parameters:

expressions – one or more join expressions.

Returns:

Returns the modified copy of the query.

abstract where(*expressions)

Sets a list of query conditions.

The where clause consists of a single (or list) of simple/complex boolean and comparison expressions. This expression specifies a search criteria for matching facts within the corresponding FactBase.

Boolean expression are built from other boolean expression or a comparison expression. Comparison expressions are of the form:

<PredicatePath> <compop>  <value>

where <compop> is a comparison operator such as ==, !=, or <= and <value> is either a Python value or another predicate path object refering to a field of the same predicate or a placeholder.

A placeholder is a special value that allows queries to be parameterised. A value can be bound to each placeholder. These placeholders are named ph1_, ph2_, ph3_, and ph4_ and correspond to the 1st to 4th arguments when the bind() function is called. Placeholders also allow for named arguments using the “ph_(“<name>”) function.

Args:

expressions: one or more comparison expressions.

Returns:

Returns the modified copy of the query.

abstract order_by(*expressions)

Specify an ordering over the results.

Parameters:

field_order – an ordering over fields

Returns:

Returns the modified copy of the query.

abstract group_by(*expressions)

Specify a grouping over the results.

The grouping specification is similar to an ordering specification but it modifies the behaviour of the query to return a pair of elements, where the first element of the pair is the group identifier (based on the specification) and the second element is an iterator over the matching elements.

When both a group_by and order_by clause is provided the order_by clause is used to sort the elements within each matching group.

Parameters:

field_order – an ordering over fields to group by

Returns:

Returns the modified copy of the query.

abstract select(*outsig)

Provides a projection over the query result tuples.

Mathematically the result tuples of a query are the cross-product over instances of the predicates. However, returning tuples of facts is often not the most convenient output format and instead you may only be interested in specific parameters/fields within each tuple of facts. The select clause specifies a _projection_ over each query result tuple.

Each query result tuple is guaranteed to be distinct, since the query is a filtering over the cross-product of the predicate instances. However, the specification of a projection can result in information being discarded and can therefore cause the projected query results to no longer be distinct. To enforce uniqueness the Query.distinct() flag can be specified. Essentially this is the same as an SQL SELECT DISTINCT ... statement.

Note: when Query.select() is used with the Query.delete() end-point the select signature must specify predicates and not parameter/fields within the predicates.

Finally, instead of a projection specification, a single Python callable object can be specified with input parameters matching the query signature. This callable object will then be called on each query tuple and the results will make up the modified query result. This provides the greatest flexibility in controlling the output of the query.

Parameters:

output_signature – the signature that defines the projection or a callable object.

Returns:

Returns the modified copy of the query.

abstract distinct()

Return only distinct elements in the query.

This flag is only meaningful when combined with a Query.select() clause that removes distinguishing elements from the tuples.

Returns:

Returns the modified copy of the query.

abstract bind(*args, **kwargs)

Bind placeholders to specific values.

If the where clause has placeholders then these placeholders must be bound to actual values before the query can be executed.

Parameters:
  • *args – positional arguments corresponding to positional placeholders

  • **kwargs – named arguments corresponding to named placeholders

Returns:

Returns the modified copy of the query.

abstract tuple()

Force returning a tuple even for singleton elements.

In the general case the output signature of a query is a tuple; consisting either of a tuple of facts or a tuple of parameters/fields if a select projection has been specified.

However, if the output signature is a singleton tuple then by default the API changes its behaviour and removes the tuple, returning only the element itself. This typically provides a much more useful and intutive interface. For example, if you want to perform a sum aggregation over the results of a query, aggregating over the value of a specific parameter/field, then specifying just that parameter in the select clause allows you to simply pass the query generator to the standard Python sum() function without needing to perform a list comprehension to extract the value to be aggregated.

If there is a case where this default behaviour is not wanted then specifying the tuple flag forces the query to always return a tuple of elements even if the output signature is a singleton tuple.

Returns:

Returns the modified copy of the query.

abstract heuristic(join_order)

Allows the query engine’s query plan to be modified.

This is an advanced option that can be used if the query is not performing as expected. For multi-predicate queries the order in which the joins are performed can affect performance. By default the Query API will try to optimise this join order based on the join expressions; with predicates with more restricted joins being higher up in the join order.

This join order can be controlled explicitly by the fixed_join_order heuristic function. Assuming predicate definitions F and G the query:

from clorm import fixed_join_order

query=fb.query(F,G).heuristic(fixed_join_order(G,F)).join(...)

forces the join order to first be the G predicate followed by the F predicate.

Parameters:

join_order – the join order heuristic

Returns:

Returns the modified copy of the query.

abstract all()

Returns a generator that iteratively executes the query.

Note. This call doesn’t execute the query itself. The query is executed when iterating over the elements from the generator.

Returns:

Returns a generator that executes the query.

abstract singleton()

Return the single matching element.

An exception is thrown if there is not exactly one matching element or a group_by() clause has been specified.

Returns:

Returns the single matching element (or throws an exception)

abstract count()

Return the number of matching element.

Typically the number of elements consist of the number of tuples produced by the cross-product of the predicates that match the criteria of the join() and where() clauses.

However, if a select() projection and unique() flag is specified then the count() will reflect the modified the number of unique elements based on the projection of the query.

Furthermore, if a group_by() clause is specified then count() returns a generator that iterates over pairs where the first element of the pair is the group identifier and the second element is the number of matching elements within that group.

Returns:

Returns the number of matching elements

abstract first()

Return the first matching element.

An exception is thrown if there are no one matching element or a group_by() clause has been specified.

Returns:

Returns the first matching element (or throws an exception)

abstract delete()

Delete matching facts from the FactBase().

In the simple case of a query with no joins then delete() simply deletes the matching facts. If there is a join then the matches consist of tuples of facts. In this case delete() will remove all facts from the tuple. This behaviour can be modified by using a select() projection clause that selects only specific predicates. Note: when combined with select() the output signature must specify predicates and not parameter/fields within predicates.

An exception is thrown if a group_by() clause has been specified.

Returns:

Returns the number of facts deleted.

abstract modify(fn)

Modify matching facts in a FactBase().

Clorm facts are immutable, so in order to simulate something like an SQL UPDATE operation, the modify() query end-point provides a convenient way to replace or modify matching facts in a query with some (related) facts.

This call operates in the same way as the delete() end-point but the matching facts are first passed to the parameter function fn. This function must return a pair consisting of 1) the facts to delete from the factbase, 2) the facts to add to the fact base. These two sets of facts are maintained until the end of the query and the delete set of facts are removed followed by the add set being added.

Note, this behaviour could also achieved by iterating over the results of the query normally and maintaining separate “delete” and “add” lists which are then acted upon at the end of the query. The advantage of the modify() call is to provide a simple and declarative way to do it which can be convenient especially when chaining multiple modifications of a factbase.

The function fn must have the same input signature as the query output. If the output of fn must be a pair consisting of the elements to delete and element to add. For flexibility, each set can be None or a single clorm fact or an iterator over clorm facts.

An exception is thrown if a group_by() or ``uclause has been specified.

Example assuming a FactBase fb consisting of F and G predicate facts:

def mod_fn(f: F, g: G):

return ({f, g}, {f.clone(a=10), g.clone(a=10)})

fb.query(F,G).join(F.a == G.a).where(F.a == 2).modify(mod_fn)

fb.query(F,G).join(F.a == G.a).where(F.a == 10).select(F).modify(lambda f: (None, {f.clone(a=20)}))

Returns:

Returns a (delete_count, add_count) pair indicating the total number of facts deleted and added to the factbase.

abstract replace(fn)

Replace matching facts in a FactBase().

This function is a convenient special case of the more general modify() function.

While the modify() parameter function must return a del-add pair, the replace() parameter function returns only an add entry, since all matching facts will be deleted.

Returns:

Returns a (delete_count, add_count) pair indicating the total number of facts deleted and added to the factbase.

abstract query_plan(*args, **kwargs)

Return a query plan object outlining the query execution.

A query plan outlines the query will be executed; the order of table joins, the searches based on indexing, and how the sorting is performed. This is useful for debugging if the query is not behaving as expected.

Currently, there is no fixed specification for the query plan object. All the user can do is display it for reading and debugging purposes.

Returns:

Returns a query plan object that can be stringified.

class clorm.PredicatePath(pathseq: List[PathIdentity | str])

PredicatePath implements the intuitive query syntax.

Every defined Predicate sub-class has a corresponding PredicatePath sub-class that mirrors its field definitions. This allows it to be used when specifying the components of a query; such as the sign and the fields or sub-fields of a predicate (eg., Pred.sign, Pred.a.b or Pred.a[0]).

When the API user refers to a field (or sign) of a Predicate sub-class they are redirected to the corresponding PredicatePath object of that predicate sub-class.

While instances of this class (and sub-classes) are externally exposed through the API, users should not explicitly instantiate instances themselves.

Predicate path subclasses provide attributes and indexed items for refering to sub-paths. When a user specifies Pred.a.b.c the Predicate sub-class Pred seemlessly passes off to an associated PredicatePath object, which then returns a path corresponding to the specifications.

Fields can be specified either by name through a chain of attributes or using the array indexes. This is implemented in the overloaded __getitem__ function which allows for name or positional argument specifications.

The most important aspect of a predicate path object is that it overloads the boolean operators to return a comparison condition. This is what allows for query specifications such as Pred.a.b == 2 or Pred.a.b == ph1_.

Finally, because the name meta is a Clorm keyword and can’t be used as a field name it is used as a property referring to an internal class with functions for use by the internals of the library. API users should not use this property.

Query Support Functions

The following functions support the query specification.

clorm.path(arg, exception=True)

Returns the PredicatePath corresponding to some component.

This function is useful for users for the special case of referring to the PredicatePath that corresponding to a Predicate object. For example to specify a comparison in a query to match a specific instance to some placeholder you need to reference the predicate using a path.

Example:

from clorm import FactBase, Predicate, ConstantField, path

class F(Predicate):
   a = ConstantField

fb = FactBase([F("foo"),F("bar")])

qBad=fb.query(F).where(F == F("bar"))    # This won't do what you expect

qGood=fb.query(F).where(path(F) == F("bar"))

Note

The technical reason for not supporting the more intuitive syntax above is that it would require overloading the comparison operators of the predicate class itself; which would break the behaviour of Python in many other contexts.

Returns:

Returns a PredicatePath object corresponding to the input specification.

clorm.alias(predicate: Type[_P], name: str = '') Type[_P]
clorm.alias(predicate: PredicatePath | Hashable, name: str = '') Type[Predicate]

Return an alias PredicatePath instance for a Predicate sub-class.

A predicate alias can be used to support self joins in queries. The alias has all the same fields (and sub-fields) as the “normal” path associated with the predicate.

For example, consider a simple (and not properly normalised) friend fact base with a predicate that uniquely identifies people and friends, by a id number, and you want to output the friend connections in an intuitive manner.

Example

 from clorm import FactBase, Predicate, IntegerField, StringField, alias

 class F(Predicate):
     pid = IntegerField
     name = StringField
     fid = IntegerField

fb=FactBase([F(1,"Adam",3),F(2,"Betty",4),F(3,"Carol",1),F(4,"Dan",2)])

FA = alias(F)
q=fb.query(F,FA).join(F.pid == FA.fid).select(F.name,FA.name)

for p,f in q.all():
    print("Person {} => Friend {}".format(p,f))
Returns:

Returns an alias PredicatePath for the predicate.

clorm.cross(*args)

Return a cross-product join condition

clorm.ph_(value, *args, **kwargs)

A function for building new placeholders, either named or positional.

clorm.not_(*conditions)

Return a boolean condition that is the negation of the input condition

clorm.and_(*conditions)

Return a the conjunction of two of more conditions

clorm.or_(*conditions)

Return the disjunction of two of more conditions

clorm.in_(path, seq)

Return a query operator to test membership of an item in a collection

clorm.notin_(path, seq)

Return a query operator to test non-membership of an item in a collection

Calling Python From an ASP Program

Clorm provides a number of decorators that can make it easier to call Python from within an ASP program. The basic idea is that Clorm provides all the information required to convert data between native Python types and clingo.Symbol objects. Therefore functions can be written by only dealing with Python data and the Clorm decorators will wrap these functions with the appropriate data conversions based on a given signature.

clorm.make_function_asp_callable(*args: Any) Callable[[...], Any]

A decorator for making a function callable from within an ASP program.

Can be called in a number of ways. Can be called as a decorator with or without arguments. If called with arguments then the arguments must correspond to a type cast signature.

A type cast signature specifies the type conversions required between a python function that is called from within an ASP program and a set of corresponding Python types.

A type cast signature is specified in terms of the fields that are used to define a predicate. It is a list of elements where the first n-1 elements correspond to type conversions for a functions inputs and the last element corresponds to the type conversion for a functions output.

Parameters:
  • sigs (*sigs) – A list of function signature elements.

  • [ (- Inputs. Match the sub-elements) – -1] define the input signature while the last element defines the output signature. Each input must be a a BaseField (or sub-class).

  • Output (-) – Must be BaseField (or sub-class) or a singleton list containing a BaseField (or sub-class).

If no arguments are provided then the function signature is derived from the function annotations. The function annotations must conform to the signature above.

If called as a normal function with arguments then the last element must be the function to be wrapped and the previous elements conform to the signature profile.

clorm.make_method_asp_callable(*args: Any) Callable[[...], Any]

A decorator for making a member function callable from within an ASP program.

See make_function_asp_callable for details. The only difference is that the first element of the function is ignore as it is assumed to be the self or cls parameter.

It may also be useful to deal with a predeclared type cast signature.

class clorm.TypeCastSignature(*sigs: Any, module: str | None = None)

Defines a signature for converting to/from Clingo data types.

Args:

module: Name of the module where the signature is defined sigs(*sigs): A list of signature elements.

  • Inputs. Match the sub-elements [:-1] define the input signature while the last element defines the output signature. Each input must be a BaseField (or sub-class).

  • Output: Must be BaseField (or sub-class) or a singleton list containing a BaseField (or sub-class).

Example

import datetime

class DateField(StringField):
          pytocl = lambda dt: dt.strftime("%Y%m%d")
          cltopy = lambda s: datetime.datetime.strptime(s,"%Y%m%d").date()

drsig = TypeCastSignature(DateField, DateField, [DateField], module = "__main__")

@drsig.wrap_function
def date_range(start, end):
    return [ start + timedelta(days=x) for x in range(0,end-start) ]

The function date_range that takes a start and end date and returns the list of dates within that range.

When decorated with the signature it provides the conversion code so that the decorated function expects a start and end date encoded as Clingo.String objects (matching YYYYMMDD format) and returns a list of Clingo.String objects corresponding to the dates in that range.

static is_return_element(se: Any) bool

An output element must be an output field or a singleton iterable containing an output fields; where an output field is a BaseField sub-class or tuple that recursively reduces to a BaseField sub-class.

wrap_function(fn)

Function wrapper that adds data type conversions for wrapped function.

Parameters:

fn – A function satisfing the inputs and output defined by the TypeCastSignature.

wrap_method(fn)

Member function wrapper that adds data type conversions for wrapped member functions.

Parameters:

fn – A function satisfing the inputs and output defined by the TypeCastSignature.

From Clingo 5.4 onwards, the Clingo grounding function allows a context parameter to be specified. This parameter defines a context object for the methods that are called by ASP using the @-syntax.

class clorm.ContextBuilder

Context builder simplifies the task of building grounding context for clingo. This is a new clingo feature for Clingo 5.4 where a context can be provided to the grounding function. The context encapsulates the external Python functions that can be called from within an ASP program.

ContextBuilder allows arbitrary functions to be captured within a context and assigned a conversion signature. It also allows the function to be given a different name when called from within the context.

The context builder’s register and register_name member functions can be called as decorators or as normal functions. A useful feature of these functions is that when called as decorators they do not wrap the original function but instead return the original function and only wrap the function when called from within the context. This is unlike the make_function_asp_callable and make_method_asp_callable functions which when called as decorators will replace the original function with the wrapped version.

Example:

The following nonsense ASP program contains embedded python with functions registered with the context builder (highlighting different ways the register functions can be called). A context object is then created by the context builder and used during grounding. It will produce the answer set:

f(5), g(6), h("abcd").
f(@addi(1,4)).
g(@addi_alt(2,4)).
h(@adds("ab","cd")).

#script(python).

from clorm import IntegerField,StringField,ContextBuilder

IF=IntegerField
SF=StringField
cb=ContextBuilder()

# Uses the function annotation to define the conversion signature
@cb.register
def addi(a : IF, b : IF) -> IF : return a+b

# Register with a different name
@cb.register_name("addi_alt")
def add2(a : IF, b : IF) -> IF : return a+b

# Register with a different name and override the signature in the
# function annotation
cb.register_name("adds", SF, SF, SF, addi)

ctx=cb.make_context()

def main(prg):
    prg.ground([("base",[])],context=ctx)
    prg.solve()

#end.
make_context(cls_name='Context')

Return a context object that encapsulates the registered functions

register(*args)

Register a function with the context builder.

Parameters:

*args – the last argument must be the function to be registered. If there is more than one argument then the earlier arguments define the data conversion signature. If there are no earlier arguments then the signature is extracted from the function annotations.

register_name(func_name, *args)

Register a function with assigning it a new name witin the context.

Parameters:
  • func_name – the new name for the function within the context.

  • *args – the last argument must be the function to be registered. If there is more than one argument then the earlier arguments define the data conversion signature. If there are no earlier arguments then the signature is extracted from the function annotations.

Integration with the Solver

Clorm provides some helper functions to get clorm facts into and out of the solver (ie a clingo.Control object).

clorm.control_add_facts(ctrl: Control, facts: Iterable[Predicate | Symbol]) None

Assert a collection of facts to the solver

Provides a flexible approach to asserting facts to the solver. The facts can be either clingo.Symbol objects or clorm facts and can be in any type of be in any collection (including a clorm.FactBase).

Parameters:
  • ctrl – a clingo.Control object

  • facts – the collection of facts to be asserted into the solver

clorm.symbolic_atoms_to_facts(symbolic_atoms: SymbolicAtoms, unifier: Iterable[Type[Predicate]], *, facts_only: bool = False, factbase: FactBase | None = None) FactBase

Extract clorm.FactBase from clingo.SymbolicAtoms

A clingo.SymbolicAtoms object is returned from the clingo.Control.symbolic_atoms property. This property is a view into the internal atoms within the solver and can be examined at anytime (ie. before/after the grounding/solving). Some of the atoms are trivially true (as determined by the grounder) while others may only be true in some models.

Parameters:
  • symbolic_atoms – a clingo.SymbolicAtoms object

  • unifier – a list of Clorm Predicate sub-classes to unify against

  • facts_only (default False) – return facts only or include contingent literals

  • factbase (default None) – add to existing FactBase or return a new FactBase

clorm.unify(unifier: Iterable[Type[Predicate]] | SymbolPredicateUnifier, symbols: Iterable[Symbol | NoSymbol], ordered: Literal[True]) List[Predicate]
clorm.unify(unifier: Iterable[Type[Predicate]] | SymbolPredicateUnifier, symbols: Iterable[Symbol | NoSymbol]) FactBase

Unify raw symbols against a list of predicates or a SymbolPredicateUnifier.

Symbols are tested against each predicate unifier until a match is found. Since it is possible to define multiple predicate types that can unify with the same symbol, the order of the predicates in the unifier matters. With the ordered option set to True a list is returned that preserves the order of the input symbols.

Parameters:
  • unifier – a list of predicate classes or a SymbolPredicateUnifier object.

  • symbols – the symbols to unify.

  • (default (ordered) – False): optional to return a list rather than a FactBase.

Returns:

a FactBase containing the unified facts, indexed by any specified indexes,

or a list if the ordered option is specified

To further simplify the interaction with the solver, Clorm provides a clingo replacement module that offers better integration with Clorm facts and fact bases. This module simply wraps and extends a few key Clingo classes.

Instead of:

import clingo

use:

import clorm.clingo

For convenience the clingo.Control class can also be monkey patched so that it can used seemlessly with existing code bases.

from clorm import monkey; monkey.patch()
import clingo

Here we document only the extended classes and the user is referred to the Clingo API documentation for more details.

class clorm.clingo.Control(*args: Any, **kwargs: Any)

Control object for the grounding/solving process.

Behaves like clingo.Control but with modifications to deal with Clorm facts and fact bases.

Adds an additional parameter unifier to specify how any generated clingo models will be unified with the clorm Predicate definitions. The unifier can be specified as a list of predicates or as a SymbolPredicateUnifier object.

An existing clingo.Control object can be passed using the control_ parameter.

Control object for the grounding/solving process.

Parameters:
  • arguments – Arguments to the grounder and solver.

  • logger – Function to intercept messages normally printed to standard error.

  • message_limit – The maximum number of messages passed to the logger.

Notes

Note that only gringo options (without –text) and clasp’s search options are supported. Furthermore, you must not call any functions of a Control object while a solve call is active.

add(*args, **kwargs) None

Extend the logic program with the given non-ground logic program in string form.

This function provides two overloads:

```python def add(self, name: str, parameters: Sequence[str], program: str) -> None:

def add(self, program: str) -> None:

return self.add(“base”, [], program)

```

Parameters:
  • name – The name of program block to add.

  • parameters – The parameters of the program block to add.

  • program – The non-ground program in string form.

See also

Control.ground

add_facts(facts: Iterable[Predicate | Symbol]) None

Add facts to the control object. Note: facts must be added before grounding.

This function can take an arbitrary collection containing a mixture of clorm.Predicate and clingo.Symbol objects. A clorm.FactBase is also a valid collection but it can only contain clorm.Predicate instances.

Parameters:

facts – a collection of clorm.Predicate or clingo.Symbol objects

assign_external(external: Iterable[Predicate | Symbol | int], truth: bool | None) None

Assign a truth value to an external fact (or collection of facts)

A fact can be a raw clingo.Symbol object, a clorm.Predicate instance, or a program literal (an int). If the external is a collection then the truth value is assigned to all elements in the collection.

This function extends clingo.Control.release_external.

Assign a truth value to an external atom.

Parameters:
  • external – A symbol or program literal representing the external atom.

  • truth – A Boolean fixes the external to the respective truth value; and None leaves its truth value open.

See also

Control.release_external, clingo.solving.SolveControl.symbolic_atoms, clingo.symbolic_atoms.SymbolicAtom.is_external

Notes

The truth value of an external atom can be changed before each solve call. An atom is treated as external if it has been declared using an #external directive, and has not been released by calling Control.release_external or defined in a logic program with some rule. If the given atom is not external, then the function has no effect.

For convenience, the truth assigned to atoms over negative program literals is inverted.

backend() Backend

Returns a Backend object providing a low level interface to extend a logic program.

See also

clingo.backend

cleanup() None

Cleanup the domain used for grounding by incorporating information from the solver.

This function cleans up the domain used for grounding. This is done by first simplifying the current program representation (falsifying released external atoms). Afterwards, the top-level implications are used to either remove atoms from the domain or mark them as facts.

Notes

Any atoms falsified are completely removed from the logic program. Hence, a definition for such an atom in a successive step introduces a fresh atom.

With the current implementation, the function only has an effect if called after solving and before any function is called that starts a new step.

Typically, it is not necessary to call this function manually because automatic cleanups are enabled by default.

get_const(name: str) Symbol | None

Return the symbol for a constant definition of form:

#const name = symbol.

Parameters:

name – The name of the constant to retrieve.

Return type:

The function returns None if no matching constant definition exists.

ground(parts: Sequence[Tuple[str, Sequence[Symbol]]] = (('base', ()),), context: Any = None) None

Ground the given list of program parts specified by tuples of names and arguments.

Parameters:
  • parts – List of tuples of program names and program arguments to ground.

  • context – A context object whose methods are called during grounding using the @-syntax (if omitted, those from the main module are used).

Notes

Note that parts of a logic program without an explicit #program specification are by default put into a program called base without arguments.

interrupt() None

Interrupt the active solve call.

Notes

This function is thread-safe and can be called from a signal handler. If no search is active, the subsequent call to Control.solve is interrupted. The result of the Control.solve method can be used to query if the search was interrupted.

load(path: str) None

Extend the logic program with a (non-ground) logic program in a file.

Parameters:

path – The path of the file to load.

register_observer(observer: Observer, replace: bool = False) None

Registers the given observer to inspect the produced grounding.

Parameters:
  • observer – The observer to register. See below for a description of the requirede interface.

  • replace – If set to true, the output is just passed to the observer and nolonger to the underlying solver (or any previously registered observers).

See also

clingo.backend

register_propagator(propagator: Propagator) None

Registers the given propagator with all solvers.

Parameters:

propagator – The propagator to register.

See also

clingo.propagator

release_external(external: Iterable[Predicate | Symbol | int]) None

Release an external fact (or collection of facts)

A fact can be a raw clingo.Symbol object, a clorm.Predicate instance, or a program literal (an int). If the external is a collection then the truth value is assigned to all elements in the collection.

This function extends clingo.Control.release_external.

Release an external atom represented by the given symbol or program literal.

This function causes the corresponding atom to become permanently false if there is no definition for the atom in the program. Otherwise, the function has no effect.

Parameters:

external – The symbolic atom or program atom to release.

Notes

If the program literal is negative, the corresponding atom is released.

Examples

The following example shows the effect of assigning and releasing and external atom.

>>> from clingo.symbol import Function
>>> from clingo.control import Control
>>>
>>> ctl = Control()
>>> ctl.add("base", [], "a. #external b.")
>>> ctl.ground([("base", [])])
>>> ctl.assign_external(Function("b"), True)
>>> print(ctl.solve(on_model=print))
b a
SAT
>>> ctl.release_external(Function("b"))
>>> print(ctl.solve(on_model=print))
a
SAT
solve(*args: Any, **kwargs: Any) SolveHandle | SolveResult

Run the clingo solver.

This function extends clingo.Control.solve() in two ways:

1) The assumptions argument is generalised so that in the list of argument-boolean pairs the argument can be be a clingo symbol, or clorm predicate instance, or a collection of clingo symbols or clorm predicates.

2) It produces either a clorm.clingo.SolveHandle wrapper object or a clorm.clingo.Model wrapper objects as appropriate (depending on the yield_, async_, and on_model parameters).

Starts a search.

Parameters:
  • assumptions – List of (atom, boolean) tuples or program literals (see clingo.symbolic_atoms.SymbolicAtom.literal) that serve as assumptions for the solve call, e.g., solving under assumptions [(Function(“a”), True)] only admits answer sets that contain atom a.

  • on_model – Optional callback for intercepting models. A clingo.solving.Model object is passed to the callback. The search can be interruped from the model callback by returning False.

  • on_unsat – Optional callback to intercept lower bounds during optimization.

  • on_statistics – Optional callback to update statistics. The step and accumulated statistics are passed as arguments.

  • on_finish – Optional callback called once search has finished. A clingo.solving.SolveResult also indicating whether the solve call has been intrrupted is passed to the callback.

  • on_core – Optional callback called with the assumptions that made a problem unsatisfiable.

  • yield – The resulting clingo.solving.SolveHandle is iterable yielding clingo.solving.Model objects.

  • async – The solve call and the method clingo.solving.SolveHandle.resume of the returned handle are non-blocking.

Returns:

  • The return value depends on the parameters. If either yield_ or

  • async_ is true, then a handle is returned. Otherwise, a

  • clingo.solving.SolveResult is returned.

See also

clingo.solving

Notes

If neither yield_ nor async_ is set, the function returns a clingo.solving.SolveResult right away.

In gringo or in clingo with lparse or text output enabled, this function just grounds and returns a clingo.solving.SolveResult where clingo.solving.SolveResult.unknown is true.

If this function is used in embedded Python code, you might want to start clingo using the –outf=3 option to disable all output from clingo.

Asynchronous solving is only available in clingo with thread support enabled. Furthermore, the on_model and on_finish callbacks are called from another thread. To ensure that the methods can be called, make sure to not use any functions that block Python’s GIL indefinitely.

This function as well as blocking functions on the clingo.solving.SolveHandle release the GIL but are not thread-safe.

property configuration

Object to change the configuration.

property control_: Control

Returns the underlying clingo.Control object.

property enable_cleanup

Whether to enable automatic calls to Control.cleanup.

property enable_enumeration_assumption

Whether do discard or keep learnt information from enumeration modes.

If the enumeration assumption is enabled, then all information learnt from clasp’s various enumeration modes is removed after a solve call. This includes enumeration of cautious or brave consequences, enumeration of answer sets with or without projection, or finding optimal models; as well as clauses added with clingo.solving.SolveControl.add_clause.

Notes

Initially the enumeration assumption is enabled.

In general, the enumeration assumption should be enabled whenever there are multiple calls to solve. Otherwise, the behavior of the solver will be unpredictable because there are no guarantees which information exactly is kept. There might be small speed benefits when disabling the enumeration assumption for single shot solving.

property is_conflicting

Whether the internal program representation is conflicting.

If this (read-only) property is true, solve calls return immediately with an unsatisfiable solve result.

Notes

Conflicts first have to be detected, e.g., initial unit propagation results in an empty clause, or later if an empty clause is resolved during solving. Hence, the property might be false even if the problem is unsatisfiable.

property statistics

A dict containing solve statistics of the last solve call.

See also

clingo.statistics

Notes

The statistics correspond to the –stats output of clingo. The detail of the statistics depends on what level is requested on the command line. Furthermore, there are some functions like Control.release_external that start a new solving step resetting the current step statistics. It is best to access the statistics right after solving.

This property is only available in clingo.

property symbolic_atoms

An object to inspect the symbolic atoms.

See also

clingo.symbolic_atoms

property theory_atoms

An iterator over the theory atoms in a program.

See also

clingo.theory_atoms

property unifier: SymbolPredicateUnifier | None

Get/set the unifier.

Unifier can be specified as a SymbolPredicateUnifier or a collection of Predicates. Always returns a SymbolPredicateUnifier (or None).

class clorm.clingo.Model(model: Model, unifier: List[Type[Predicate]] | SymbolPredicateUnifier | None = None)

Provides access to a model during a solve call.

Objects mustn’t be created manually. Instead they are returned by clorm.clingo.Control.solve callbacks.

Behaves like clingo.Model but offers better integration with clorm facts and fact bases.

Provides access to a model during a solve call and provides a SolveContext object to influence the running search.

Notes

The string representation of a model object is similar to the output of models by clingo using the default output.

Model objects cannot be constructed from Python. Instead they are obained during solving (see Control.solve). Furthermore, the lifetime of a model object is limited to the scope of the callback it was passed to or until the search for the next model is started. They must not be stored for later use.

contains(fact: Predicate | Symbol) bool

Return whether the fact or symbol is contained in the model. Extends clingo.Model.contains to allow for clorm facts as well as a clingo symbols.

Efficiently check if an atom is contained in the model.

Parameters:

atom – The atom to lookup.

Return type:

Whether the given atom is contained in the model.

Notes

The atom must be represented using a function symbol.

extend(symbols: Sequence[Symbol]) None

Extend a model with the given symbols.

Parameters:

symbols – The symbols to add to the model.

Notes

This only has an effect if there is an underlying clingo application, which will print the added symbols.

facts(*args: Any, **kwargs: Any) FactBase

Returns a FactBase containing the facts in the model that unify with the SymbolPredicateUnifier.

This function provides a wrapper around the clingo.Model.symbols functions, but instead of returning a list of symbols it returns a FactBase containing the facts represented as clorm.Predicate sub-class instances.

Parameters:
  • unifier (list | SymbolPredicateUnifier) – used to unify and instantiate FactBase (Default: passed via the constructor if specified in the clorm.clingo.Control object)

  • atoms – select all atoms in the model (Default: False)

  • terms – select all terms displayed with #show statements (Default: False)

  • shown – select all atoms and terms (Default: False)

  • theory – select atoms added with Model.extend() (Default: False)

  • complement – return the complement of the answer set w.r.t. to the atoms known to the grounder. (Default: False)

  • raise_on_empty – raise a ValueError if the resulting FactBase is empty (Default: False)

is_consequence(literal: int) bool | None

Check if the given program literal is a consequence.

The function returns True, False, or None if the literal is a consequence, not a consequence, or it is not yet known whether it is a consequence, respectively.

While enumerating cautious or brave consequences, there is partial information about which literals are consequences. The current state of a literal can be requested using this function. If this function is used during normal model enumeration, the function just returns whether a literal is true of false in the current model.

Parameters:

literal – The given program literal.

Return type:

Whether the given program literal is a consequence.

is_true(literal: int) bool

Check if the given program literal is true.

Parameters:

literal – The given program literal.

Return type:

Whether the given program literal is true.

symbols(atoms: bool = False, terms: bool = False, shown: bool = False, theory: bool = False, complement: bool = False) Sequence[Symbol]

Return the list of atoms, terms, or CSP assignments in the model.

Parameters:
  • atoms – Select all atoms in the model (independent of #show statements).

  • terms – Select all terms displayed with #show statements in the model.

  • shown – Select all atoms and terms as outputted by clingo.

  • theory – Select atoms added with Model.extend.

  • complement – Return the complement of the answer set w.r.t. to the atoms known to the grounder.

Return type:

The selected symbols.

Notes

Atoms are represented using functions (Symbol objects), and CSP assignments are represented using functions with name “$” where the first argument is the name of the CSP variable and the second its value.

property context

Object that allows for controlling the running search.

property cost

Return the list of integer cost values of the model.

The return values correspond to clasp’s cost output.

property model_: Model

Returns the underlying clingo.Model object.

property number

The running number of the model.

property optimality_proven

Whether the optimality of the model has been proven.

property priority

Return the priorities of the model’s cost values.

property thread_id

The id of the thread which found the model.

property type

The type of the model.

class clorm.clingo.SolveHandle(handle: SolveHandle, unifier: List[Type[Predicate]] | SymbolPredicateUnifier | None = None)

Handle for solve calls.

Objects mustn’t be created manually. Instead they are returned by clorm.clingo.Control.solve.

Behaves like clingo.SolveHandle but iterates over clorm.clingo.Model objects.

Handle for solve calls.

They can be used to control solving, like, retrieving models or cancelling a search.

See also

Control.solve

Notes

A SolveHandle is a context manager and must be used with Python’s with statement.

Blocking functions in this object release the GIL. They are not thread-safe though.

cancel() None

Cancel the running search.

See also

clingo.control.Control.interrupt

core() List[int]

The subset of assumptions that made the problem unsatisfiable.

get() SolveResult

Get the result of a solve call.

If the search is not completed yet, the function blocks until the result is ready.

model() Model | None

Get the current model if there is any.

resume() None

Discards the last model and starts searching for the next one.

Notes

If the search has been started asynchronously, this function starts the search in the background.

wait(timeout: float | None = None) bool

Wait for solve call to finish or the next result with an optional timeout.

If a timeout is given, the behavior of the function changes depending on the sign of the timeout. If a postive timeout is given, the function blocks for the given amount time or until a result is ready. If the timeout is negative, the function will block until a result is ready, which also corresponds to the behavior of the function if no timeout is given. A timeout of zero can be used to poll if a result is ready.

Parameters:

timeout – If a timeout is given, the function blocks for at most timeout seconds.

Return type:

Indicates whether the solve call has finished or the next result is ready.

property solvehandle_: SolveHandle

Access the underlying clingo.SolveHandle object.