cnfgen.formula.mapping module¶
CNF encoding of mapping
The module defines functionality to conviniently represent mapping, - in unary encoding - in binary encoding - in sparse unary encoding
The module implements the CNFMapping
object, which is
supposed to be inherited from the VariablesManager
object.
Copyright (C) 2019-2021 Massimo Lauria <lauria.massimo@gmail.com> https://github.com/MassimoLauria/cnfgen.git
-
class
BinaryMappingVariables
(formula, n, m, labelfmt='v({}, {})')¶ Bases:
cnfgen.formula.variables.BaseVariableGroup
A group of variables representing a mapping to bitstrings
Given a domain \([n]\) and a range \([m]\), this group of variables represent a mapping.
Variables are \(v(i,k-1)...v(i,0)\) for \(i \in D\). Each \(v(i,k-1)...v(i,0)\) is a string of \(k\) bits, and represents the image of \(i \in [m]\). The value \(k\) is set so that
Methods
__call__
(*index)Convert the index of a variable into its ID. domain
()The domain of the mapping forbid
(i, j)The clause that forbids i–>j indices
(*pattern)Implementation of :py:classmethod:`BaseVariableGroup.indices` label
(*pattern)Convert the index of a variable into its label. parent_formula
()The formula associated to the variable group range
()The range of the mapping to_index
(lit)Convert a literal to the corresponding pair (i,b) bits to_dict -
bits
()¶
-
domain
()¶ The domain of the mapping
If v is None it returns the domain of the mapping. Otherwise it returns the sequence of elements which is possible to map to v.
Examples
>>> F = CNFMapping() >>> f = BinaryMappingVariables(F,4,6) >>> f.domain() == range(1,5) True >>> F = CNFMapping() >>> f = BinaryMappingVariables(F,20,6) >>> f.domain() == range(1,21) True
-
forbid
(i, j)¶ The clause that forbids i–>j
Create the unique clause that is false if and only if i is mapped to the bit string corresponding to j
Examples
>>> F = CNFMapping() >>> V = BinaryMappingVariables(F,4,6) >>> V.forbid(2,0) [4, 5, 6] >>> V.forbid(2,7) [-4, -5, -6] >>> V.forbid(4,3) [10, -11, -12]
-
indices
(*pattern)¶ Implementation of :py:classmethod:`BaseVariableGroup.indices`
Parameters: - pattern : sequences(positive integers or None)
the pattern of the indices
Returns: - a tuple or an itertools.product object
Examples
>>> F = CNFMapping() >>> f = BinaryMappingVariables(F,5,12) >>> print(*f.indices(3,None)) (3, 3) (3, 2) (3, 1) (3, 0) >>> print(*f.indices(None,1)) (1, 1) (2, 1) (3, 1) (4, 1) (5, 1)
-
range
()¶ The range of the mapping
If u is None it returns the range of the mapping. Otherwise it returns the sequence of all elements to which u can be mapped.
Examples
>>> F = CNFMapping() >>> f = BinaryMappingVariables(F,5,12) >>> f.range() == range(0,12) True >>> len(f) 20 >>> F = CNFMapping() >>> f = BinaryMappingVariables(F,5,15) >>> f.range() == range(0,15) True >>> len(f) 20
-
to_index
(lit)¶ Convert a literal to the corresponding pair (i,b)
Parameters: - lit : positive or negative literal
-ID or +ID for the ID of the variable
Returns: - pair of integers
Raises: - ValueError
when lit is not within the appropriate intervals
Examples
>>> F = CNFMapping() >>> F.update_variable_number(10) >>> V = BinaryMappingVariables(F,10, 13, labelfmt='v({},{})') >>> len(V) 40 >>> V.to_index(11) (1, 3) >>> V.to_index(16) (2, 2) >>> V.to_index(-18) (2, 0) >>> V.to_index(48) (10, 2)
-
-
class
CNFMapping
(clauses=None, description=None)¶ Bases:
cnfgen.formula.variables.VariablesManager
CNF with a variable manager
A CNF formula needs to keep track on variables. A
VariableManager
allows to do that, while providing a nice interface that allows to focus on variable meaning.Examples
>>> F=CNFMapping() >>> f = F.new_mapping(2,3,label='f_{{{},{}}}') >>> F.number_of_variables() 6 >>> B = BipartiteGraph(4,4) >>> B.add_edges_from([(1,2), (1,4), (2,3), (4,2), (4,3)]) >>> g = F.new_sparse_mapping(B, label='g_{{{},{}}}') >>> F.number_of_variables() 11 >>> print(*f.label()) f_{1,1} f_{1,2} f_{1,3} f_{2,1} f_{2,2} f_{2,3} >>> print(*g.label()) g_{1,2} g_{1,4} g_{2,3} g_{4,2} g_{4,3}
Attributes: - name : dict
associate a variable / literal to its label
Methods
new_mapping(n, m, label): add the variables representing a mapping (in unary) new_sparse_mapping(B, label): add the variables representing a sparse mapping -
force_complete_mapping
(f)¶ Enforce the mapping f to be complete
Add the clauses that make the mapping f complete. Namely that all elements in the domain are mapped to some element in the range. These clauses do not exclude the possibility that an element from the domain is mapped to multiple elements in the range (indeed that may be the case for unary representation).
(See py:classmethod:CNFMapping.force_functional_mapping)
Examples
>>> C = CNFMapping() >>> f = C.new_mapping(10,5) >>> C.force_complete_mapping(f) >>> C[2] [11, 12, 13, 14, 15] >>> len(C) 10 >>> g = C.new_binary_mapping(4,14) >>> C.force_complete_mapping(g) >>> len(C) 18 >>> C[10] [-51, -52, -53, 54] >>> C[11] [-51, -52, -53, -54]
-
force_functional_mapping
(f)¶ Enforce the mapping f to be functional
Add the clauses that enforce the mapping f to be a partial function. Namely that every element in the domain can be mapped to at most one element in the range.
Together with :py:classmethod:`CNFMapping.force_complete_mapping`, this enforces the mapping to be a total function.
Examples
>>> C = CNFMapping() >>> f = C.new_mapping(10,5) >>> C.force_functional_mapping(f) >>> len(C) 100 >>> C.number_of_variables() 50 >>> max(len(cls) for cls in C) 2 >>> C[7] [-3, -4] >>> len(C) 100
-
force_injective_mapping
(f)¶ Enforce the mapping f to be injective
Add the clauses that make the mapping f injective. Namely that all elements in the range have at most one element in the domain mapped to it.
Examples
>>> C = CNFMapping() >>> f = C.new_mapping(10,5) >>> C.force_injective_mapping(f) >>> C[0] [-1, -6] >>> C[1] [-1, -11] >>> C[45] [-2, -7] >>> len(C) 225
-
force_nondecreasing_mapping
(f)¶ Enforce the mapping f to be non decreasing
Add the clauses that make the mapping f injective. Namely that all elements in the range have at most one element in the domain mapped to it.
Examples
>>> C = CNFMapping() >>> B = BipartiteGraph(2,3) >>> B.add_edge(1,2) >>> B.add_edge(1,3) >>> B.add_edge(2,1) >>> B.add_edge(2,3) >>> f = C.new_sparse_mapping(B) >>> C.force_nondecreasing_mapping(f) >>> len(C) 2 >>> C[0] [-1, -3] >>> C[1] [-2, -3] >>> g = C.new_binary_mapping(2,4) >>> C.force_nondecreasing_mapping(g) >>> len(C) 8
-
force_surjective_mapping
(f)¶ Enforce the mapping f to be surjective
Add the clauses that make the mapping f surjective. Namely that all elements in the range have at least one element in the domain mapped to it.
This method works only for mapping represented in unary.
Examples
>>> C = CNFMapping() >>> f = C.new_mapping(10,5) >>> C.force_surjective_mapping(f) >>> C[1] [2, 7, 12, 17, 22, 27, 32, 37, 42, 47] >>> len(C) 5
-
new_binary_mapping
(n, m, label='v({}, {})')¶ Adds variables for a mapping from n to m encoded in binary
Creates a group of variables representing a mapping from \(\{1,\ldots,n}\) to \(\{0,\ldots,m-1\}\).
The mapping is represented as a sequence of \(n\) binary strings of length \(k\), where \(k\) is the smallest integer so that \(m \leq 2^k\).
The element mapped to \(i\) is represented using \(k\) boolean variables \(v(i,k-1) \ldots v(i,0)\).
Parameters: - n : int
size of the domain
- m : int
size of the range
- label : str, optional
string representation of the variables
Returns: - BinaryMappingVariables, the new variable group
Examples
>>> F = CNFMapping() >>> f = F.new_binary_mapping(4,14) >>> F.number_of_variables() 16 >>> f(2,3) 5 >>> f(4,0) 16
-
new_mapping
(n, m, label='f({})={}')¶ Adds variables for a mapping from n to m
Creates a group of variables for a mapping from \(n\) elements to \(m\) elements represented as boolean variables \(f_{i,j}\) for \(i in [n]\) and \(j in [m]\).
Parameters: - n : int
size of the domain
- m : int
size of the range
- label : str, optional
string representation of the variables
Returns: - UnaryMappingVariables, the new variable group
Examples
>>> F = CNFMapping() >>> f = F.new_mapping(4,10) >>> f(2,1) 11 >>> f(1,8) 8 >>> F.number_of_variables() 40 >>> f.label(3,8) 'f(3)=8'
-
new_sparse_mapping
(B, label='f({})={}')¶ Adds variables for a sparse mapping
Creates a group of variables representing a mapping. The representation is sparse in the sense that the domain and range are the two sides of a bipartite graph \(B\). The map \(u \mapsto v\) is available if and only if the edge \((u,v) \in E(B)\).
Parameters: - B : BipartiteGraph
sparse representation of the mapping
- label : str, optional
string representation of the variables
Returns: - UnaryMappingVariables, the new variable group
Examples
>>> B = BipartiteGraph(5,3) >>> B.add_edge(2,1) >>> B.add_edge(1,3) >>> B.add_edge(2,2) >>> B.add_edge(3,3) >>> B.add_edge(4,3) >>> B.add_edge(4,2) >>> B.add_edge(5,1) >>> F = CNFMapping() >>> f = F.new_sparse_mapping(B) >>> f(2,2) 3 >>> f(4,3) 6 >>> F.number_of_variables() 7 >>> f.label(4,2) 'f(4)=2'
-
class
UnaryMappingVariables
(formula, G, labelfmt)¶ Bases:
cnfgen.formula.variables.BipartiteEdgesVariables
A group of variables representing a mapping
The mapping is represented in unary, where variables \(f_{i,j}\) represent atoms \(f(i)=j\).
Assuming \(i \in D\) and \(j \in R\), to all pairs \(D \times R\) are necessarily available. The ones that are possible are specified by a bipartite graph \(G=(D,R,E)\).
Methods
__call__
(*index)Convert the index of a variable into its ID. domain
([v])The domain of the mapping indices
(*pattern)Print the label of the edge label
(*pattern)Convert the index of a variable into its label. parent_formula
()The formula associated to the variable group range
([u])The range of the mapping to_index
(lit)Convert a literal to the corresponding edge to_dict -
domain
(v=None)¶ The domain of the mapping
If v is None it returns the domain of the mapping. Otherwise it returns the sequence of elements which is possible to map to v.
-
range
(u=None)¶ The range of the mapping
If u is None it returns the range of the mapping. Otherwise it returns the sequence of all elements to which u can be mapped.
-