def wpol(self,arity,clone=None,multimorphisms=False): """ Return the weighted polymorphisms. This method obtains the matrix of inequalities defining the weighted polymorphisms and uses CDD to compute a set of generators for the cone defined by these inequalities. :param arity: The arity. :type arity: integer :param clone: The supporting clone. :type clone: :class:`Clone`, Optional :param multimorphisms: Flag to request we only generate multimorphisms. :type multimorphisms: boolean, optional .. note:: We implicitly assume that any clone passed in to the function is a subset of the set of feasibility polymorphisms. .. note:: The part of the code which automatically computes the clone of feasibility polymorphisms is not yet implemented, so a user will have to compute the clone separately and pass it as input. """ if clone is None: clone = Clone.all_operations(arity,self.dom) N = len(clone) A = self.wop_ineq(arity,clone) # Get the weighted polymorphism inequalities for row in self.wpol_ineq(arity,clone): if not row in A: A.append(row) poly = cdd.Polyhedron(cdd.Matrix(A)) ray_mat = poly.get_generators() W = [] for i in range(ray_mat.row_size): weights = [] ops = [] for j in range(N): rval = round(ray_mat[i][j+1],self.dom) if rval != 0: weights.append(-rval) ops.append(clone[j]) W.append(wpolyanna.wop.WeightedOperation(arity, self.dom, ops, weights)) return W
def wpol_separate(self,Gamma,arity,clone=None): """ Test if this cost function can be expressed over a set of cost functions. :param Gamma: the other cost functions :returns: A separating weighted polymorphism if it exists and false otherwise. """ if clone is None: clone = Clone.all_operations(arity,self.dom) N = len(clone) A = self.wop_ineq(arity,clone) for gamma in Gamma: for a in gamma.wpol_ineq(arity,clone): if not a in A: A.append(a) # For each wpol inequality of this cost function, check if # there exists a wpol of Gamma violating it for c in self.wpol_ineq(arity,clone): prob = pulp.LpProblem() # One variable for each operation in the clone y = pulp.LpVariable.dicts("y",xrange(N)) # Must satisfy all inequalities in A for a in A: prob += sum(y[i]*a[i+1] for i in xrange(N)) <= 0 # Must violate c prob += sum(y[i]*c[i+1] for i in range(N)) >= 1 prob.solve() if pulp.LpStatus[prob.status] == 'Optimal': op = [] w = [] for i in xrange(N): yval = round(pulp.value(y[i]),self.dom) if yval != 0: op.append(clone[i]) w.append(yval) return wpolyanna.wop.WeightedOperation(arity,self.dom,op,w) # Return false if we couldn't find a separating wop return False
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
def wpol(cost_functions,arity,clone=None,multimorphisms=False): """ Return the weighted polymorphisms. This method obtains the matrix of inequalities defining the weighted polymorphisms and uses CDD to compute a set of generators for the cone defined by these inequalities. :param arity: The arity. :type arity: integer :param clone: The supporting clone. :type clone: :class:`Clone`, optional :param multimorphisms: Flag to request we only generate multimorphisms. :type multimorphisms: boolean, optional .. note:: We implicitly assume that any clone passed in to the function is a subset of the set of feasibility polymorphisms. .. note:: The part of the code which automatically computes the clone of feasibility polymorphisms is not yet implemented, so a user will have to compute the clone separately and pass it as input. """ if len(cost_functions) == 0: return [] d = cost_functions[0].dom if clone is None: clone = Clone.all_operations(arity,d) N = len(clone) A = cost_functions[0].wop_ineq(arity,clone) # If we are only looking for multimorphisms, then we # have all projections with weight exactly 1 if multimorphisms: for i in range(arity): row = [1] + [0 for _ in range(N)] row[i+1] = 1 A.append(row) row = [-1] + [0 for _ in range(N)] row[i+1] = -1 A.append(row) # Get the weighted polymorphism inequalities for each # cost function for cf in cost_functions: # Get the weighted polymorphism inequalities for row in cf.wpol_ineq(arity,clone): if not row in A: A.append(row) poly = cdd.Polyhedron(cdd.Matrix(A)) ray_mat = poly.get_generators() W = [] for i in range(ray_mat.row_size): weights = [] ops = [] for j in range(N): rval = round(ray_mat[i][j+1],d) if rval != 0: weights.append(-rval) ops.append(clone[j]) W.append(wpolyanna.wop.WeightedOperation(arity,d,ops,weights)) return W