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]