The qecc package provides a class Predicate to represent a predicate function; that is, a function which returns a bool.
Class representing a predicate function on one or more arguments.
>>> from qecc import Predicate
>>> p = Predicate(lambda x: x > 0)
>>> p(1)
True
>>> p(-1)
False
Instances can also be constructed by logical operations on existing Predicate instances:
>>> q = Predicate(lambda x: x < 3)
>>> (p & q)(1)
True
>>> (p | q)(-1)
True
>>> (~p)(2)
False
Returns a new Predicate that combines this predicate with another predicate using a given function to combine the results.
>>> gt_2 = Predicate(lambda x: x > 2)
>>> even = Predicate(lambda x: x % 2 == 0)
>>> nand = lambda x, y: not (x and y)
>>> r = gt_2.combine(even, nand)
>>> map(r, range(1,5))
[True, True, True, False]
Several useful predefined predicates are provided by qecc.
Given an iterable S, constructs a predicate that returns True if and only if its argument is in S.
>>> from qecc import SetMembershipPredicate
>>> p = SetMembershipPredicate(range(4))
>>> map(p, range(-1, 5))
[False, True, True, True, True, False]
Given a set S of Pauli operators represented as qecc.Pauli instances, constructs a predicate that returns True for a Pauli P if and only if P is in S.
If the keyword argument ignore_phase is True, then the comparison to determine whether P is in S only considers the operator part of P.
In addition, utility functions are provided for constructing predicates based on commutation properties of the Pauli group.
Returns a predicate that checks whether a Pauli P commutes with each of a given list of Pauli operators.
Returns a predicate that selects Pauli operators in the group generated by a given list of generators.
Predicate functions can be used to quickly generate collections of qecc.Pauli operators having a given set of properties.
>>> from qecc import commutes_with, in_group_generated_by, pauli_group
>>> print filter(
... commutes_with('XX', 'ZZ') & ~in_group_generated_by('XX'),
... pauli_group(2)
... )
[i^0 YY, i^0 ZZ]
Since searching in this way requires examining every element of a given iterator, it can be significantly faster to instead use constraint solvers such as those documented in Constraint Solvers.