cnfgen.formula.variables module¶
Keep tracks of the variable of a formula.
The module defines a variable manager, that formulas could either use of specialize. It allows to generates - single variables - variables for some tuples of indices - variables for the edges of a bipartite/direct/simple graph
The module implements the VariablesManager
object, which
is supposed to be inherited from the CNF
object.
Copyright (C) 2019-2021 Massimo Lauria <lauria.massimo@gmail.com> https://github.com/MassimoLauria/cnfgen.git
-
class
BaseVariableGroup
(formula, N, labelfmt=None)¶ Bases:
object
Base object for variable groups
This object is meant to the base class for the actual variable groups, all to be used internally by
VariablesManager
.In general a variable group is a mapping between some set of indices and the corresponding sequential variable IDs (as seen in a DIMACS file, for example).
Methods
__call__
(*index)Convert the index of a variable into its ID. indices
(*pattern)Outputs all the indices matching the given pattern label
(*pattern)Convert the index of a variable into its label. parent_formula
()The formula associated to the variable group to_index
(lit)Convert a literal of the index sequence corresponding to the variable to_dict -
indices
(*pattern)¶ Outputs all the indices matching the given pattern
-
label
(*pattern)¶ Convert the index of a variable into its label.
If the pattern is contains None values, these will be considered as “don’t care” values. The implementation should return a generator enumerating all the IDs compatible with the given pattern.
-
parent_formula
()¶ The formula associated to the variable group
Examples
>>> F1 = BaseCNF() >>> F2 = BaseCNF() >>> G = BaseVariableGroup(F1,10) >>> G.parent_formula() == F1 True >>> G.parent_formula() == F2 False
-
to_dict
()¶
-
to_index
(lit)¶ Convert a literal of the index sequence corresponding to the variable
-
-
class
BipartiteEdgesVariables
(formula, G, labelfmt='e_{{{}, {}}}')¶ Bases:
cnfgen.formula.variables.BaseVariableGroup
A group of variables matching the edges of a bipartite graph
This objects represents groups of variables corresponding to the edges of a bipartite graph.
Given a bipartite graph \(G=(U,V,E)\) represented by an object of the class
BaseBipartiteGraph
, we have variables \(e_{u,v}\) for \(u in U\) and \(v in U\).Warning: if the object representing \(G\) gets modified, the behavior of this object may be inconsistent.
Examples
>>> G = BipartiteGraph(2,3) >>> G.add_edge(2,1) >>> G.add_edge(1,3) >>> G.add_edge(2,2) >>> F = VariablesManager() >>> F.update_variable_number(11) >>> e = BipartiteEdgesVariables(F, G, labelfmt='E[{},{}]') >>> print(*[e.label(u,v) for u,v in e.indices()]) E[1,3] E[2,1] E[2,2] >>> print(e(2,1)) 13 >>> print(e(1,3)) 12 >>> 14 in e True >>> 10 in e False >>> print(len(e)) 3 >>> print(e.label(1,3)) E[1,3] >>> print(*e.label(2,None)) E[2,1] E[2,2] >>> X = BipartiteEdgesVariables(F, G, labelfmt='X[{},{}]') >>> W = BipartiteEdgesVariables(F, G, labelfmt='W[{},{}]') >>> print(X.label(2,1)) X[2,1] >>> print(W.label(1,3)) W[1,3] >>> [X.label(u,3) for u in G.left_neighbors(3)] ['X[1,3]'] >>> print(*X.label(None,3)) X[1,3] >>> print(*X.label(1,None)) X[1,3] >>> print(*X.label(None,None)) X[1,3] X[2,1] X[2,2]
Methods
__call__
(*index)Convert the index of a variable into its ID. 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 to_index
(lit)Convert a literal to the corresponding edge to_dict -
indices
(*pattern)¶ Print the label of the edge
Examples
>>> G = BipartiteGraph(2,3) >>> G.add_edge(2,1) >>> G.add_edge(1,3) >>> G.add_edge(2,2) >>> F = VariablesManager() >>> V = BipartiteEdgesVariables(F, G, labelfmt='X[{},{}]') >>> print(*V.indices(None,1)) (2, 1) >>> print(*V.indices(None,2)) (2, 2) >>> print(*V.indices(None,3)) (1, 3) >>> print(*V.indices(1,None)) (1, 3) >>> print(*V.indices(2,None)) (2, 1) (2, 2) >>> print(*V.indices(None,None)) (1, 3) (2, 1) (2, 2) >>> print(*V.indices(2,1)) (2, 1)
-
to_index
(lit)¶ Convert a literal to the corresponding edge
Parameters: - lit : positive or negative literal
-ID or +ID for the ID of the variable
Returns: - pair of positive integer
Raises: - ValueError
when lit is not within the appropriate intervals
Examples
>>> G = BipartiteGraph(2,3) >>> G.add_edge(2,1) >>> G.add_edge(1,3) >>> G.add_edge(2,2) >>> F = VariablesManager() >>> F.update_variable_number(100) >>> V = BipartiteEdgesVariables(F, G, labelfmt='e[{},{}]') >>> V.to_index(102) (2, 1) >>> V.to_index(101) (1, 3) >>> V.to_index(103) (2, 2)
-
-
class
BlockOfVariables
(formula, ranges, labelfmt=None)¶ Bases:
cnfgen.formula.variables.BaseVariableGroup
Group of variables, indexed by a cartesian product.
This objects represents groups of variables that are indexed by some tuples of integers. For example we can have variables \(p_{i,j}\) for \(i in [10]\) and \(j in [7]\).
A group can have an arbitrary number of indices, each ranging independently between \(1\) and some arbitrary integer.
This object is meant to be used internally by
VariablesManager
.Examples
>>> F = VariablesManager() >>> G = BlockOfVariables(F,[2,3],'G[{},{}]') >>> print(*G.label()) G[1,1] G[1,2] G[1,3] G[2,1] G[2,2] G[2,3] >>> print(*G.indices()) (1, 1) (1, 2) (1, 3) (2, 1) (2, 2) (2, 3) >>> G(2,1) 4 >>> V = VariablesManager() >>> p = V.new_block(10,5,label='p({},{})') >>> q = V.new_block(3,3,label='q({},{})') >>> isinstance(p,BlockOfVariables) True >>> print(len(p)) 50 >>> print(len(q)) 9 >>> print(p.to_index(23)) [5, 3] >>> print(q.to_index(54)) [2, 1] >>> print(list(q.indices())) [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)] >>> print(p(2,3)) 8 >>> print(list(p(None,3))) [3, 8, 13, 18, 23, 28, 33, 38, 43, 48] >>> print(q(1,1)) 51 >>> 52 in q True >>> 12 in q False >>> print(q.label(1,1)) q(1,1) >>> print(*q.label(2,None)) q(2,1) q(2,2) q(2,3) >>> print(p.label(4,2)) p(4,2) >>> print(list(p.indices(3,None))) [(3, 1), (3, 2), (3, 3), (3, 4), (3, 5)] >>> print(p.to_index(p(4,3))) [4, 3]
Methods
__call__
(*index)Convert the index of a variable into its ID. 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 to_index
(lit)Convert a literal to the index sequence corresponding to the variable to_dict -
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
-
to_index
(lit)¶ Convert a literal to the index sequence corresponding to the variable
A variable is identified by an integer id, but an associate index in the variable group. This function convert the variable id into such index. If a negative literal is given, the function returns the index of the corresponding variable.
Parameters: - lit : positive or negative literal
-ID or +ID for the ID of the variable
Returns: - sequence(positive integers)
Raises: - ValueError
when lit is not within the appropriate intervals
Examples
>>> V = VariablesManager() >>> VG = BlockOfVariables(V,[3,5,4,3]) >>> VG.to_index(1) [1, 1, 1, 1] >>> VG.to_index(-5) [1, 1, 2, 2] >>> VG.to_index(179) [3, 5, 4, 2] >>> VG.to_index(180) [3, 5, 4, 3]
-
-
class
DiGraphEdgesVariables
(formula, D, labelfmt='e_{{{}, {}}}', sortby='pred')¶ Bases:
cnfgen.formula.variables.BaseVariableGroup
A variable groups for the edges of a graph.
Examples
>>> G = DirectedGraph(5) >>> G.add_edge(1,2) >>> G.add_edge(2,3) >>> G.add_edge(3,4) >>> G.add_edge(4,5) >>> G.add_edge(5,1) >>> F = VariablesManager() >>> F.update_variable_number(100) >>> a = DiGraphEdgesVariables(F, G, labelfmt='a({},{})') >>> a.to_index(101) (1, 2) >>> a.to_index(104) (4, 5) >>> a(5,1) 105 >>> print(*a(4,None)) 104 >>> print(*a()) 101 102 103 104 105 >>> print(*a.label()) a(1,2) a(2,3) a(3,4) a(4,5) a(5,1) >>> H = DirectedGraph(5) >>> H.add_edge(1,2) >>> H.add_edge(1,3) >>> H.add_edge(2,3) >>> H.add_edge(2,4) >>> H.add_edge(5,1) >>> F = VariablesManager() >>> F.update_variable_number(11) >>> b = DiGraphEdgesVariables(F,H,labelfmt='b({},{})',sortby='succ') >>> b(1,3) 14 >>> b.to_index(12) (5, 1) >>> b.to_index(12) (5, 1) >>> print(*b.indices()) (5, 1) (1, 2) (1, 3) (2, 3) (2, 4) >>> print(*b.label()) b(5,1) b(1,2) b(1,3) b(2,3) b(2,4) >>> print(*b.indices(None,3)) (1, 3) (2, 3)
Methods
__call__
(*index)Convert the index of a variable into its ID. indices
(*pattern)>>> H = DirectedGraph(5)
label
(*pattern)Convert the index of a variable into its label. parent_formula
()The formula associated to the variable group to_index
(lit)Convert a literal of the index sequence corresponding to the variable to_dict -
indices
(*pattern)¶ >>> H = DirectedGraph(5) >>> H.add_edge(1,2) >>> H.add_edge(1,3) >>> H.add_edge(2,3) >>> H.add_edge(2,4) >>> H.add_edge(5,1) >>> F = VariablesManager() >>> F.update_variable_number(11) >>> b = DiGraphEdgesVariables(F,H,labelfmt='b({},{})',sortby='succ') >>> print(*b.indices()) (5, 1) (1, 2) (1, 3) (2, 3) (2, 4) >>> print(*b.label()) b(5,1) b(1,2) b(1,3) b(2,3) b(2,4) >>> print(*b.indices(None,3)) (1, 3) (2, 3) >>> print(*b.indices(2,None)) (2, 3) (2, 4)
-
to_index
(lit)¶ Convert a literal of the index sequence corresponding to the variable
-
-
class
GraphEdgesVariables
(formula, G, labelfmt='e_{{{}{}}}')¶ Bases:
cnfgen.formula.variables.BipartiteEdgesVariables
A group of variables matching the edges of a simple graph
This objects represents groups of variables corresponding to the edges of a simple graph.
Given a simple graph \(G=(V,E)\) represented by an object of the class
cnfgen.graphs.Graph
, we have variables \(e_{u,v}\) for \(\{u,v\} in E\).Warning: if the object representing \(G\) gets modified, the behavior of this object may be inconsistent.
Examples
>>> G = Graph(4) >>> G.add_edge(2,1) >>> G.add_edge(3,2) >>> G.add_edge(1,3) >>> G.add_edge(4,2) >>> F = VariablesManager() >>> V = GraphEdgesVariables(F, G, labelfmt='E[{},{}]') >>> print(*[V.label(u,v) for u,v in V.indices()]) E[1,2] E[1,3] E[2,3] E[2,4] >>> print(V(2,1)) 1 >>> print(V(1,3)) 2 >>> 4 in V True >>> 10 in V False >>> print(len(V)) 4 >>> print(V.label(3,1)) E[1,3] >>> print(*V.label(2,None)) E[1,2] E[2,3] E[2,4] >>> print(*V.label(None,2)) E[1,2] E[2,3] E[2,4] >>> print(*V.label()) E[1,2] E[1,3] E[2,3] E[2,4] >>> print(*V.indices(None,2)) (1, 2) (2, 3) (2, 4)
Methods
__call__
(*index)Convert the index of a variable into its ID. 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 to_index
(lit)Convert a literal to the corresponding edge to_dict -
indices
(*pattern)¶ Print the label of the edge
Examples
>>> G = Graph(3) >>> G.add_edge(2,1) >>> G.add_edge(1,3) >>> F = VariablesManager() >>> V = GraphEdgesVariables(F, G, labelfmt='X[{},{}]') >>> print(*V.indices(None,1)) (1, 2) (1, 3) >>> print(*V.indices(None,2)) (1, 2) >>> print(*V.indices(None,3)) (1, 3) >>> print(*V.indices(1,None)) (1, 2) (1, 3) >>> print(*V.indices(2,None)) (1, 2) >>> print(*V.indices(None,None)) (1, 2) (1, 3) >>> print(*V.indices(2,1)) (1, 2)
-
to_index
(lit)¶ Convert a literal to the corresponding edge
Parameters: - lit : positive or negative literal
-ID or +ID for the ID of the variable
Returns: - pair of positive integer
Raises: - ValueError
when lit is not within the appropriate intervals
Examples
>>> G = Graph(4) >>> G.add_edge(2,1) >>> G.add_edge(3,2) >>> G.add_edge(1,3) >>> G.add_edge(4,2) >>> F = VariablesManager() >>> F.update_variable_number(100) >>> V = GraphEdgesVariables(F, G) >>> V.to_index(102) (1, 3) >>> V.to_index(101) (1, 2) >>> V.to_index(104) (2, 4)
-
-
class
SingletonVariableGroup
(formula, name)¶ Bases:
cnfgen.formula.variables.BaseVariableGroup
A group made by a single variable
Examples
>>> c = BaseCNF() >>> c.update_variable_number(11) >>> X1 = SingletonVariableGroup(c,'X') >>> c.update_variable_number(22) >>> X2 = SingletonVariableGroup(c,'Y') >>> print(X1.label()) X >>> print(*X1.indices()) () >>> X1() 12 >>> X2() 23 >>> print(X2.label()) Y >>> print(X2.to_index(23)) ()
Methods
__call__
()Convert the index of a variable into its ID. indices
(*pattern)Outputs all the indices matching the given pattern label
()Convert the index of a variable into its label. parent_formula
()The formula associated to the variable group to_index
(lit)Convert a literal of the corresponding variable index to_dict -
indices
(*pattern)¶ Outputs all the indices matching the given pattern
-
label
()¶ Convert the index of a variable into its label.
If the pattern is contains None values, these will be considered as “don’t care” values. The implementation should return a generator enumerating all the IDs compatible with the given pattern.
-
to_index
(lit)¶ Convert a literal of the corresponding variable index
-
-
class
VariablesManager
(clauses=None, description=None)¶ Bases:
cnfgen.formula.linear.CNFLinear
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
>>> V=VariablesManager() >>> X = V.new_variable(label="X") >>> Y = V.new_variable(label="Y") >>> Zs = V.new_block(2,3,label='z_{{{},{}}}') >>> V.number_of_variables() 8 >>> len(Zs) 6 >>> print(*V.all_variable_labels()) X Y z_{1,1} z_{1,2} z_{1,3} z_{2,1} z_{2,2} z_{2,3}
Attributes: - name : dict
associate a variable / literal to its label
Methods
new_variable(label=’’): add a new variable new_block(*ranges,label=’’): add variables with one or more indices -
all_variable_labels
(default_label_format='x{}')¶ Produces the labels of all the variables
Variable belonging to special variable groups are translated accordingly. The others get a standard variable name as defined by the argument default_label_format (e.g. ‘x{}’).
-
new_bipartite_edges
(G, label='e({}, {})')¶ Create a new group variables from the edges of a bipartite graph
Parameters: - G : cnfgen.graphs.BaseBipartiteGraph
a bipartite graph
- label : str, optional
string representation of the variables
Returns: - BipartiteEdgesVariables, the new variable group
Examples
>>> V=VariablesManager() >>> V.new_variable(label='X') 1 >>> V.number_of_variables() 1 >>> V.new_variable(label='Y') 2 >>> G = BipartiteGraph(5,3) >>> G.add_edge(2,1) >>> G.add_edge(1,3) >>> G.add_edge(2,2) >>> G.add_edge(3,3) >>> G.add_edge(4,3) >>> G.add_edge(4,2) >>> G.add_edge(5,1) >>> e = V.new_bipartite_edges(G,label='X[{},{}]') >>> V.number_of_variables() 9 >>> e.to_index(4) (2, 1) >>> e(3,3) 6 >>> e.to_index(8) (4, 3) >>> e(5,1) 9
-
new_block
(*ranges, label=None)¶ Create a new group of indexed variables
Parameters: - ranges : iterable(positive integer)
the range of the variable indices
- label : str, optional
string representation of the variables
Returns: - BlockOfVariables, the new variable group
Examples
>>> V=VariablesManager() >>> V.new_variable(label='X') 1 >>> V.number_of_variables() 1 >>> V.new_variable(label='Y') 2 >>> V.new_variable(label='Z') 3 >>> V.number_of_variables() 3 >>> v = V.new_block(3,5,4,3,label='v({},{},{},{})') >>> v.to_index(4) [1, 1, 1, 1] >>> v(1,1,1,1) 4 >>> v.to_index(8) [1, 1, 2, 2] >>> v(1,1,2,2) 8 >>> v.to_index(182) [3, 5, 4, 2] >>> v(3,5,4,2) 182 >>> v.to_index(183) [3, 5, 4, 3] >>> v(3,5,4,3) 183
-
new_combinations
(n, k, label='p_{{{}}}')¶ Create a new group of variables indexed by k-subsets of [n]
-
new_combinations_with_replacement
(n, k, label='p_{{{}}}')¶ Create a new group of variables indexed by k-subsets of [n]
-
new_digraph_edges
(G, label='e({}, {})', sortby='pred')¶ Create a new group variables from the edges of a bipartite graph
Parameters: - G : DirectedGraph
a directed graph
- label : str, optional
string representation of the variables
- sortby : ‘pred’ or ‘succ’
sort the edge veriables either by predecessor (default) or by successor
Returns: - DiGraphEdgesVariables, the new variable group
Examples
>>> V=VariablesManager() >>> V.new_variable(label='X') 1 >>> V.number_of_variables() 1 >>> V.new_variable(label='Y') 2 >>> G = DirectedGraph(6) >>> G.add_edge(2,1) >>> G.add_edge(1,3) >>> G.add_edge(2,6) >>> G.add_edge(2,3) >>> G.add_edge(4,3) >>> G.add_edge(4,2) >>> a = V.new_digraph_edges(G,sortby='succ') >>> V.new_variable(label='Y') 9 >>> print(*a()) 3 4 5 6 7 8 >>> print(*a.indices()) (2, 1) (4, 2) (1, 3) (2, 3) (4, 3) (2, 6) >>> a.to_index(4) (4, 2) >>> a(2,6) 8 >>> a.to_index(7) (4, 3) >>> a(2,1) 3
-
new_graph_edges
(G, label='e({}, {})')¶ Create a new group variables from the edges of a bipartite graph
Parameters: - G : cnfgen.graphs.Graph
a directed graph
- label : str, optional
string representation of the variables
Returns: - GraphEdgesVariables, the new variable group
Examples
>>> V=VariablesManager() >>> V.new_variable(label='X') 1 >>> V.number_of_variables() 1 >>> V.new_variable(label='Y') 2 >>> G = Graph(6) >>> G.add_edge(2,1) >>> G.add_edge(1,3) >>> G.add_edge(2,6) >>> G.add_edge(2,3) >>> G.add_edge(4,3) >>> G.add_edge(4,2) >>> a = V.new_graph_edges(G) >>> V.new_variable(label='Y') 9 >>> print(*a()) 3 4 5 6 7 8 >>> print(*a.indices()) (1, 2) (1, 3) (2, 3) (2, 4) (2, 6) (3, 4) >>> a.to_index(4) (1, 3) >>> a(2,6) 7 >>> a.to_index(8) (3, 4) >>> a(2,1) 3
-
new_permutations
(n, k=None, label='p_{{{}}}')¶ Create a new group of variables indexed by k-permutations of [n]
-
new_variable
(label=None)¶ Create a new variable
Parameters: - label : str, optional
string representation of the variables
Returns: - int, the new variable
Examples
>>> V=VariablesManager() >>> V.new_variable(label='X') 1 >>> V.number_of_variables() 1 >>> V.new_variable(label='Y') 2 >>> V.new_variable(label='Z') 3 >>> V.number_of_variables() 3 >>> V.add_clause([1,3,-4]) >>> V.number_of_variables() 4
-
new_words
(n, k, label='p_{{{}}}')¶ Create a new group of variables indexed by sequences [n]^k
-
class
WordOfIndicesVariables
(formula, n, k, labelfmt=None, wordtype='combinations')¶ Bases:
cnfgen.formula.variables.BaseVariableGroup
Group of variables corrisponding to fixed sequences of indices
This objects represents groups of variables that are indexed by some sequences of integers from a ground set \([n]\). For example we can have variables \(p_{S}\) for \(S in \binom{[n]}{k}[10]\) for a fixed \(k\).
Each set is identified by an index, which is just the sequence of it’s elements, sorted.
Three types of indices are supported: - combinations:
sorted tuples of length \(k\) with no repetitions- combinations_with_replacement:
- sorted tuples of length \(k\) with repetitions
- permutation:
- tuples of length \(k\) with no repetitions
- words:
- tuples of length \(k\) with repetitions
The latter is very similar to cartesian product variable group.
Examples
>>> F = VariablesManager() >>> G = WordOfIndicesVariables(F,4,2,'[{}]') >>> print(*G.label()) [1,2] [1,3] [1,4] [2,3] [2,4] [3,4] >>> print(*G.indices()) (1, 2) (1, 3) (1, 4) (2, 3) (2, 4) (3, 4) >>> G(2,3) 4 >>> V = VariablesManager() >>> p = V.new_combinations(5,3,label='p({})') >>> q = V.new_combinations(3,3,label='q({})') >>> print(len(p)) 10 >>> print(len(q)) 1 >>> print(p.to_index(4)) (1, 3, 4) >>> print(q.to_index(11)) (1, 2, 3) >>> print(list(p.indices())) [(1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5), (1, 4, 5), (2, 3, 4), (2, 3, 5), (2, 4, 5), (3, 4, 5)] >>> print(p(2,3,4)) 7 >>> print(list(p())) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> print(q(1,2,3)) 11 >>> 11 in q True >>> 12 in q False >>> print(q.label(1,2,3)) q(1,2,3) >>> print(*q.label()) q(1,2,3) >>> print(p.label(1,2,5)) p(1,2,5)
Methods
__call__
(*pattern)Convert the index of a variable into its ID. 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 to_index
(lit)Convert a literal to the index sequence corresponding to the variable to_dict -
indices
(*pattern)¶ Implementation of :py:classmethod:`BaseVariableGroup.indices`
Returns: - all the variable indices
-
label
(*pattern)¶ Convert the index of a variable into its label.
If the pattern is contains None values, these will be considered as “don’t care” values. The implementation should return a generator enumerating all the IDs compatible with the given pattern.
-
to_index
(lit)¶ Convert a literal to the index sequence corresponding to the variable
A variable is identified by an integer id, but an associate index in the variable group. This function convert the variable id into such index. If a negative literal is given, the function returns the index of the corresponding variable.
Parameters: - lit : positive or negative literal
-ID or +ID for the ID of the variable
Returns: - sequence(positive integers)
Raises: - ValueError
when lit is not within the appropriate intervals
Examples
>>> V = VariablesManager() >>> VG = BlockOfVariables(V,[3,5,4,3]) >>> VG.to_index(1) [1, 1, 1, 1] >>> VG.to_index(-5) [1, 1, 2, 2] >>> VG.to_index(179) [3, 5, 4, 2] >>> VG.to_index(180) [3, 5, 4, 3]