Skip to content
9 changes: 5 additions & 4 deletions gpkit/constraints/costed.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ def subinplace(self, subs):
self.cost = self.cost.sub(subs)
ConstraintSet.subinplace(self, subs)

@property
def varkeys(self):
"return all Varkeys present in this ConstraintSet"
return ConstraintSet._varkeys(self, self.cost.varlocs)
def reset_varkeys(self, init_dict=None):
"Resets varkeys to what is in the cost and constraints"
ConstraintSet.reset_varkeys(self, self.cost.varlocs)
if init_dict is not None:
self.varkeys.update(init_dict)

def rootconstr_str(self, excluded=None):
"The appearance of a ConstraintSet in addition to its contents"
Expand Down
11 changes: 7 additions & 4 deletions gpkit/constraints/linked.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,18 @@ class LinkedConstraintSet(ConstraintSet):
"""
def __init__(self, constraints, include_only=None, exclude=None):
ConstraintSet.__init__(self, constraints)
varkeys = self.varkeys
linkable = set()
for varkey in varkeys:
for varkey in self.varkeys:
name_without_model = varkey.str_without(["models"])
if len(varkeys[name_without_model]) > 1:
if len(self.varkeys[name_without_model]) > 1:
linkable.add(name_without_model)
if include_only:
linkable &= set(include_only)
if exclude:
linkable -= set(exclude)
self.linked, self.reverselinks = {}, {}
for name in linkable:
vks = varkeys[name]
vks = self.varkeys[name]
sub, subbed_vk = None, None
for vk in vks:
if vk in self.substitutions:
Expand All @@ -66,6 +65,10 @@ def __init__(self, constraints, include_only=None, exclude=None):
self.reverselinks[newvk] = vks
with SignomialsEnabled(): # since we're just substituting varkeys.
self.subinplace(self.linked)
for constraint in self:
if hasattr(constraint, "reset_varkeys"):
constraint.reset_varkeys()
self.reset_varkeys()

def process_result(self, result):
super(LinkedConstraintSet, self).process_result(result)
Expand Down
9 changes: 5 additions & 4 deletions gpkit/constraints/prog_factories.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
"Scripts for generating, solving and sweeping programs"
from time import time
import numpy as np
from ..nomials.substitution import parse_subs
from ..solution_array import SolutionArray
from ..keydict import KeyDict
from ..varkey import VarKey

try:
from ipyparallel import Client
Expand All @@ -16,6 +12,11 @@
except (ImportError, IOError, AssertionError):
POOL = None

from ..nomials.substitution import parse_subs
from ..solution_array import SolutionArray
from ..keydict import KeyDict
from ..varkey import VarKey


def _progify_fctry(program, return_attr=None):
"Generates function that returns a program() and optionally an attribute."
Expand Down
37 changes: 25 additions & 12 deletions gpkit/constraints/set.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def __init__(self, constraints, substitutions=None, recursesubs=True):
constraints = [constraints]
list.__init__(self, constraints)
subs = substitutions if substitutions else {}
self.unused_variables = None
if not isinstance(constraints, ConstraintSet):
# constraintsetify everything
for i, constraint in enumerate(self):
Expand All @@ -28,6 +29,7 @@ def __init__(self, constraints, substitutions=None, recursesubs=True):
# grab the substitutions dict from the top constraintset
subs.update(constraints.substitutions) # pylint: disable=no-member
if recursesubs:
self.reset_varkeys()
self.substitutions = KeyDict.with_keys(self.varkeys,
self._iter_subs(subs))
else:
Expand All @@ -47,6 +49,10 @@ def __getitem__(self, key):
variables.sort(key=_var_sort_key)
return variables

def __setitem__(self, key, value):
list.__setitem__(self, key, value)
self.reset_varkeys()

__str__ = _str
__repr__ = _repr
_repr_latex_ = _repr_latex_
Expand Down Expand Up @@ -126,20 +132,27 @@ def subinplace(self, subs):
"Substitutes in place."
for constraint in self:
constraint.subinplace(subs)

@property
def varkeys(self):
"return all Varkeys present in this ConstraintSet"
return self._varkeys()

def _varkeys(self, init_dict=None):
"return all Varkeys present in this ConstraintSet"
init_dict = {} if init_dict is None else init_dict
out = KeySet(init_dict)
if self.unused_variables is not None:
unused_vars = []
for var in self.unused_variables:
if var.key in subs:
unused_vars.append(subs[var.key])
else:
unused_vars.append(var.key)
self.unused_variables = unused_vars
self.reset_varkeys()

def reset_varkeys(self, init_dict=None):
"Goes through constraints and collects their varkeys."
varkeys = KeySet()
if init_dict is not None:
varkeys.update(init_dict)
for constraint in self:
if hasattr(constraint, "varkeys"):
out.update(constraint.varkeys)
return out
varkeys.update(constraint.varkeys)
if self.unused_variables is not None:
varkeys.update(self.unused_variables)
self.varkeys = varkeys
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have an external model that now fails on this branch -- the failure occurs on this line by raising an AttributeError: can't set attribute. Here's a relevant portion of the traceback (note lc here is a LinkedConstraintSet):

--> 375         Model.__init__(self, None, lc, **kwargs)
    376
    377     @property

/Users/whoburg/MIT/dev/gpkit/gpkit/constraints/model.pyc in __init__(self, cost, constraints, substitutions, name)
     56         cost = cost if cost else Monomial(1)
     57         constraints = constraints if constraints else []
---> 58         CostedConstraintSet.__init__(self, cost, constraints, substitutions)
     59         if self.__class__.__name__ != "Model" and not name:
     60             name = self.__class__.__name__

/Users/whoburg/MIT/dev/gpkit/gpkit/constraints/costed.pyc in __init__(self, cost, constraints, substitutions)
     18         if substitutions:
     19             subs.update(substitutions)
---> 20         ConstraintSet.__init__(self, constraints, subs)
     21
     22     def subinplace(self, subs, value=None):

/Users/whoburg/MIT/dev/gpkit/gpkit/constraints/set.pyc in __init__(self, constraints, substitutions, recursesubs)
     29             subs.update(constraints.substitutions)  # pylint: disable=no-member
     30         if recursesubs:
---> 31             self.reset_varkeys()
     32             self.substitutions = KeyDict.with_keys(self.varkeys,
     33                                                    self._iter_subs(subs))

/Users/whoburg/MIT/dev/gpkit/gpkit/constraints/costed.pyc in reset_varkeys(self, init_dict)
     30         if init_dict is not None:
     31             costkeys.update(init_dict)
---> 32         ConstraintSet.reset_varkeys(self, costkeys)
     33
     34     def rootconstr_str(self, excluded=None):

/Users/whoburg/MIT/dev/gpkit/gpkit/constraints/set.pyc in reset_varkeys(self, init_dict)
    139             # else:
    140             #     print type(constraint) # getting numpy bools...
--> 141         self.varkeys = varkeys
    142
    143     def as_posyslt1(self):

AttributeError: can't set attribute

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you email me the code? Something that inherits from ConstraintSet seems to still have varkeys as a property, but I'm certain that's not the case on this branch...maybe you have two different gpkit instances colliding?

Copy link
Collaborator

@whoburg whoburg Aug 4, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sadly cannot e-mail this. Yes, turns out this was caused by the following hack (which can be removed):

    @property
    def varkeys(self):
        # local speedy varkey access -- this is temporary until we
        # implement this more generally in gpkit
        if self._fastvks:
            return self._fastvks
        # pylint:disable=no-member
        self._fastvks = Model.varkeys.fget(self)
        return self._fastvks

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Next issue on this branch is with SummingConstraintSet, implemented as follows:

class SummingConstraintSet(ConstraintSet):
    def __init__(self, lhs, varname, models=[], variables=[], **kwargs):
        summedvars = set([v.key for v in variables])
        alreadysummed = set()
        for model in models:
            mvars = model[varname]
            if not hasattr(mvars, "__len__"):
                mvars = [mvars]
            # next line makes the recursion stop at depth one
            # for safety to avoid double counting
            mvars = [v for v in mvars if v.key.models[0] == model.name]
            assert len(mvars) == 1
            summedvars = summedvars.union([v.key for v in mvars])
            for constraint in model.flat():
                if hasattr(constraint, "summedvars"):
                    alreadysummed = alreadysummed.union(constraint.summedvars)
        summedvars = summedvars.difference(alreadysummed)
        ConstraintSet.__init__(self, [lhs >= sum(Variable(**vk.descr)
                                                 for vk in summedvars)],
                               **kwargs)

When trying to initialize a SCS, get the following traceback:

     12             # next line makes the recursion stop at depth one
     13             # for safety to avoid double counting
---> 14             mvars = [v for v in mvars if v.key.models[0] == model.name]
     15             assert len(mvars) == 1
     16             summedvars = summedvars.union([v.key for v in mvars])

TypeError: 'NoneType' object has no attribute '__getitem__'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error occurred because there was a variable without a model, perhaps fixed by my latest commit.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, looks like model names are not getting appended to all varkeys on this branch. That's at least partially responsible for the error I'm seeing in the external model.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and that appears to be true even as of the latest merge commit

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try the new d8, just pushed.

On Thu, Aug 4, 2016 at 2:07 PM, Warren Hoburg notifications@github.com
wrote:

In gpkit/constraints/set.py
#787 (comment):

     for constraint in self:
         if hasattr(constraint, "varkeys"):
  •            out.update(constraint.varkeys)
    
  •    return out
    
  •            varkeys.update(constraint.varkeys)
    
  •        # else:
    
  •        #     print type(constraint) # getting numpy bools...
    
  •    self.varkeys = varkeys
    

and that appears to be true even as of the latest merge commit


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/hoburg/gpkit/pull/787/files/0f425f6e3ba7a2bf56b596de7ca9452334bb1947#r73602863,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABagGNeJA8l4i8ReNpE1dsufFf3bVPgxks5qclR3gaJpZM4Jcvdl
.


def as_posyslt1(self):
"Returns list of posynomials which must be kept <= 1"
Expand Down
13 changes: 13 additions & 0 deletions gpkit/keydict.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,19 @@ class KeySet(KeyDict):
"KeySets are KeyDicts without values, serving only to filter and map keys"
collapse_arrays = False

def add(self, item):
"Adds an item to the keyset"
self[item] = None

def update(self, *args, **kwargs):
"Iterates through the dictionary created by args and kwargs"
if len(args) == 1:
for item in args[0]:
self.add(item)
else:
for k, v in dict(*args, **kwargs).items():
self[k] = v

def __getitem__(self, key):
"Gets the keys corresponding to a particular key."
key, _ = self.parse_and_index(key)
Expand Down
19 changes: 18 additions & 1 deletion gpkit/tests/t_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,24 @@ def test_cvxopt_kwargs(self):
self.assertAlmostEqual(sol["cost"], 12., NDIGS["cvxopt"])


TESTS = [TestModelSolverSpecific]
class Thing(Model):
"a thing, for model testing"
def __init__(self, n, **kwargs):
a = VectorVariable(n, "a", "g/m")
b = VectorVariable(n, "b", "m")
c = Variable("c", 17/4., "g")
Model.__init__(self, None, [a >= c/b], **kwargs)


class TestModelNoSolve(unittest.TestCase):
"""model tests that don't require a solver"""
def test_modelname_added(self):
t = Thing(2)
for vk in t.varkeys:
self.assertEqual(vk.models, ["Thing"])


TESTS = [TestModelSolverSpecific, TestModelNoSolve]
MULTI_SOLVER_TESTS = [TestGP, TestSP]

for testcase in MULTI_SOLVER_TESTS:
Expand Down