def imp_ineq(self,r,index=None): """ Generate the set of inequalities cost functions improved by this weighted operation must satisfy. This method returns a matrix A representing the set of cost function of arity r improved by this weighted operation. The method imp uses the double description method to compute the set of extreme rays of the polyhedron Ax <= 0, which correspond to a minimal set of cost functions that can be used to generate the set of cost functions improved by this weighted operation. :param r: The arity of the cost functions to be generated :type r: integer :param index: Dictionary mapping tuples to their index, in lexicographic order. :type index: :py:class:`dict`, Optional :returns: The inequality matrix. :rtype: :py:func:`list` of :py:func:`list` of integer """ if index is None: # Compute an index for the tuples index = dict() i = 0 for x in it.product(range(self.dom),repeat=r): index[x] = i i += 1 # The inequalities Ax <= 0 will define the cone of cost functions A = [] # Iterate over the tableaux # For each such X, we compute the tableau # obtained by applying the operations to X # We then generate the constraint this imposes # on a cost function, and add this to our matrix, # as long as it is non-zero D = range(self.dom) for X in it.combinations_with_replacement( it.product(D,repeat=r),self.arity): row = [0 for _ in range(self.dom**r)] for f in self.get_support(): y = f.apply_to_tableau(X) row[index[y]] += self.get_weight(f) #Y = [f.apply_to_tableau(X) for f in self.ops] #for i in range(len(Y)): # row[index[Y[i]]] += self.weights[i] if max([i != 0 for i in row]): if len(A) == 0: A = [row] else: i = binary_search(A,row) if i == len(A) or A[i] != row: A.insert(i,row) return A
def translations(self,arity,clone=None): """ Return the set of translations by elements of a clone. :param clone: The clone we want to translate by. :type clone: :class:`Clone`, Optional :returns: The matrix of translations, with columns index by the clone. Each row corresponds to a single translation, storing the weight assigned to the i-th operation in the clone at the i-th location. :rtype: :class:`cdd.Matrix` .. note:: If no clone is passed as input, we use the smallest clone containing all the elements of self.ops. """ if clone is None: clone = Clone.generate(self.ops,arity) N = len(clone) # Each tuple of terms in the clone gives rise to a generator A = [] for t in it.product(range(N),repeat=self.arity): F = [clone[i] for i in t] row = [0 for _ in range(N)] for (f,w) in self.weight_iter():#zip(self.ops,self.weights): try: row[clone.get_index(f.compose(F))] += w except KeyError: raise KeyError # Add non-zero rows if they are are not already in A. # We keep A sorted to make this check more efficient if min(row) != 0: if len(A) == 0: A = [row] else: i = binary_search(A,row) if i == len(A) or A[i] != row: A.insert(i,row) return A
def wpol_ineq(self,arity,clone=None): """ Return the set of inequalities the weighted polymorphisms must satisfy. This method returns a matrix A, such that the set of weighted operations satisfying Aw <= 0 are the weighted polymorphisms of this cost function. :param arity: The arity of the weighted polymorphisms. :type arity: integer :param clone: The supporting clone. :type clone: :class:`Clone`, Optional :returns: A set of inequalities defining the weighted polymorphisms. :rtype: :class:`cdd.Matrix` ..note:: We implicity assume that clone is a subset of the set of feasibility polymorphisms. If no clone is passed as an argument, then we use the clone containing all operations. """ if clone is None: clone = Clone.all_operations(arity,self.dom) # N is the number of operations in the clone. We will need a # variable for each of these N = len(clone) A = [] # Divide the tuples into sets of zero and non-zero cost r = self.arity D = range(self.dom) T = [[],[]] neg,pos = False,False for t in it.product(D,repeat=r): if self[t] == 0: T[0].append(t) else: T[1].append(t) if self[t] > 0: pos = True elif self[t] < 0: neg = True # Tableaus containing at least one non-zero tuple for comb in it.product([0,1],repeat=arity): if sum(comb) > 0: for X in it.product(*[T[i] for i in comb]): row = [0 for _ in range(N+1)] for i in xrange(0,N): row[i+1] = self[clone[i].apply_to_tableau(X)] # Insert row if not already in A # We keep A sorted to make this check more efficient if len(A) == 0: A = [row] else: i = binary_search(A,row) if i == len(A) or A[i] != row: A.insert(i,row) # We only need tableaus with all zero tuples if there are some # positive weighted tuples if pos: for X in it.product(T[0],repeat=arity): row = [0 for _ in range(N+1)] trivial = True for i in xrange(0,N): row[i+1] = self[clone[i].apply_to_tableau(X)] if row[i+1] != 0: trivial = False if not trivial: if len(A) == 0: A = [row] else: i = binary_search(A,row) if i == len(A) or A[i] != row: A.insert(i,row) return A