Changeset 1881

Show
Ignore:
Timestamp:
08/09/07 00:37:01 (1 year ago)
Author:
arj..@yirdis.nl
Message:

Fixed Solver.constraints_with_variable to work well with projections. Also it can take multiple variables to match.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • gaphas/trunk/gaphas/solver.py

    r1794 r1881  
    312312    e.g. from Canvas to Item space or visa versa. 
    313313 
    314     In order to be a Projection the 'value' and 'strength' properties should 
    315     be implemented and a method named variable() should be present. 
     314    In order to be a Projection the ``value`` and ``strength`` properties 
     315    should be implemented and a method named ``variable()`` should be present. 
    316316 
    317317    Projections should inherit from this class. 
    318318 
    319     For the sake of efficiency, Projections may not be nested. 
    320     """ 
    321  
    322     value = 0  
     319    Projections may be nested. 
     320 
     321    This default implementation projects a variable to it's own: 
     322 
     323    >>> v = Variable(4.0) 
     324    >>> v 
     325    Variable(4, 20) 
     326    >>> p = Projection(v) 
     327    >>> p.value 
     328    4.0 
     329    >>> p.value = -1 
     330    >>> p.value 
     331    -1.0 
     332    >>> v.value 
     333    -1.0 
     334    >>> p.strength 
     335    20 
     336    >>> p.variable() 
     337    Variable(-1, 20) 
     338    """ 
     339 
     340    def __init__(self, var): 
     341        self._var = var 
     342 
     343    def _set_value(self, value): 
     344        self._var.value = value 
     345 
     346    value = property(lambda s: s._var.value, _set_value) 
    323347 
    324348    strength = property(lambda s: s.variable().strength) 
     
    328352        Return the variable owned by the projection. 
    329353        """ 
    330         raise NotImplemented 
     354        return self._var 
    331355 
    332356    def __float__(self): 
    333357        return float(self.variable()._value) 
     358 
     359    def __str__(self): 
     360        return '%s(%s)' % (self.__class__.__name__, self.variable()) 
     361    __repr__ = __str__ 
    334362 
    335363 
     
    458486    reversible_pair(add_constraint, remove_constraint) 
    459487 
    460     def constraints_with_variable(self, variable): 
     488    def constraints_with_variable(self, *variables): 
    461489        """ 
    462490        Return an iterator of constraints that work with variable. 
     
    466494        >>> from constraint import EquationConstraint 
    467495        >>> s = Solver() 
    468         >>> a, b = Variable(), Variable(2.0) 
    469         >>> s.add_constraint(EquationConstraint(lambda a, b: a -b, a=a, b=b)) 
     496        >>> a, b, c = Variable(), Variable(2.0), Variable(4.0) 
     497        >>> eq_a_b = s.add_constraint(EquationConstraint(lambda a, b: a -b, a=a, b=b)) 
     498        >>> eq_a_b 
    470499        EquationConstraint(<lambda>, a=Variable(0, 20), b=Variable(2, 20)) 
    471         >>> s.add_constraint(EquationConstraint(lambda a, b: a -b, a=a, b=b)) 
    472         EquationConstraint(<lambda>, a=Variable(0, 20), b=Variable(2, 20)) 
    473         >>> len(s._constraints) 
    474         2 
    475         >>> for c in s.constraints_with_variable(a): print c 
    476         EquationConstraint(<lambda>, a=Variable(0, 20), b=Variable(2, 20)) 
    477         EquationConstraint(<lambda>, a=Variable(0, 20), b=Variable(2, 20)) 
     500        >>> eq_a_c = s.add_constraint(EquationConstraint(lambda a, b: a -b, a=a, b=c)) 
     501        >>> eq_a_c 
     502        EquationConstraint(<lambda>, a=Variable(0, 20), b=Variable(4, 20)) 
     503 
     504        And now for some testing: 
     505 
     506        >>> eq_a_b in s.constraints_with_variable(a) 
     507        True 
     508        >>> eq_a_c in s.constraints_with_variable(a) 
     509        True 
     510        >>> eq_a_b in s.constraints_with_variable(a, b) 
     511        True 
     512        >>> eq_a_c in s.constraints_with_variable(a, b) 
     513        False 
     514 
     515        Using another variable with the same value does not work: 
     516 
     517        >>> d = Variable(2.0) 
     518        >>> eq_a_b in s.constraints_with_variable(a, d) 
     519        False 
     520 
     521        This also works for projections: 
     522 
     523        >>> eq_pr_a_b = s.add_constraint(EquationConstraint(lambda a, b: a -b, a=Projection(a), b=Projection(b))) 
     524        >>> eq_pr_a_b   # doctest: +ELLIPSIS 
     525        EquationConstraint(<lambda>, a=Projection(Variable(0, 20)), b=Projection(Variable(2, 20))) 
     526 
     527        >>> eq_pr_a_b in s.constraints_with_variable(a, b) 
     528        True 
     529        >>> eq_pr_a_b in s.constraints_with_variable(a, c) 
     530        False 
     531        >>> eq_pr_a_b in s.constraints_with_variable(a, d) 
     532        False 
    478533        """ 
    479534        # use a copy of the original set, so constraints may be deleted in the 
    480535        # meantime. 
     536        variables = set(variables) 
    481537        for c in set(self._constraints): 
    482             if variable in c.variables(): 
     538            if variables.issubset(set(c.variables())): 
    483539                yield c 
    484             # TODO: walk through the constraints looking for Projections 
    485             #       which hold the variable 
     540            elif c._solver_has_projections: 
     541                found = True 
     542                for v in c.variables(): 
     543                    if v in variables: 
     544                        continue 
     545                    while isinstance(v, Projection): 
     546                        v = v.variable() 
     547                        if v in variables: 
     548                            break 
     549                    else: 
     550                        found = False 
     551                    if not found: 
     552                        break # quit for loop, variable not in constraint 
     553                else: 
     554                    # All iteration have completed succesfully, 
     555                    # so all variables are in the constraint 
     556                    yield c 
     557                     
    486558 
    487559    def solve(self):