Exemple #1
0
    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
Exemple #2
0
    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
Exemple #3
0
    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
Exemple #4
0
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