convexengineering / gpkit

Geometric programming for engineers
http://gpkit.readthedocs.org
MIT License
206 stars 40 forks source link

as_view seems to break with nested Vectorization and Vectorize(1) #1464

Closed pgkirsch closed 4 years ago

pgkirsch commented 4 years ago

Yes, it seems weird to do Vectorize(1) but it would be nice if a Vectorize-able model can also work when only being used for point-design.

MWE:

In [1]: from gpkit import Model, VectorVariable, Vectorize                                                                              

In [2]: class Test(Model): 
   ...:     def setup(self): 
   ...:         self.x = x = VectorVariable(25, "x") 
   ...:         constraints = [x >= 1] 
   ...:         return constraints 
   ...:                                                                                                                                 

In [3]: with Vectorize(2): 
   ...:     with Vectorize(2): 
   ...:         t = Test() 
   ...:     y = t.as_view()[1].x 
   ...:                                                                                                                                 

In [4]: with Vectorize(1): 
   ...:     with Vectorize(2): 
   ...:         t = Test() 
   ...:     y = t.as_view()[1].x 
   ...:                                                                                                                                 
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-4-b1004cf03886> in <module>
      2     with Vectorize(2):
      3         t = Test()
----> 4     y = t.as_view()[1].x
      5 

~/Documents/Optimization/gpkit/gpkit/constraints/set.py in __getattr__(self, attr)
    380             if newdims > 0:  # indexes are put last to match Vectorize
    381                 index = (slice(None),)*newdims + index
--> 382             return value[index]
    383         else:
    384             raise AttributeError("the underlying ConstraintSet does not have"

~/Documents/Optimization/gpkit/gpkit/nomials/array.py in __getitem__(self, idxs)
    118 
    119     def __getitem__(self, idxs):
--> 120         out = np.ndarray.__getitem__(self, idxs)
    121         if not getattr(out, "shape", None):
    122             return out

IndexError: index 1 is out of bounds for axis 2 with size 1
pgkirsch commented 4 years ago

Whoops, I submitted the wrong MWE! Fixing...

pgkirsch commented 4 years ago

Corrected the example. It might just be user error, i.e. that I need to index differently, but from what I can tell as_view doesn't handle nested vectorizing?

pgkirsch commented 4 years ago

The following works (unexpectedly) fine:

In [5]: with Vectorize(4): 
   ...:     with Vectorize(2): 
   ...:         t = Test() 
   ...:     y = t.as_view()[3].x 
   ...:   
bqpd commented 4 years ago

It does handle nested vectorization! But to match vectorization, it indexes a little funny. Your first (leftmost) vectorization is indexed first/from the right, like so:

from gpkit import *

class Test(Model):
    def setup(self):
        self.x = Variable("x")

with Vectorize(4):
    with Vectorize(2):
        t = Test()
    y = t.as_view()[3][1].x

print(y)

outputs

Test.x[:,3]
Test.x[1,3]
bqpd commented 4 years ago

I did this for a bit of a reason, but an actual usecase beats that any day.

bqpd commented 4 years ago
In [4]: with Vectorize(1): 
   ...:     with Vectorize(2): 
   ...:         t = Test() 
   ...:     y = t.as_view()[1].x 

I think what you were going for with this example was something like this?

with Vectorize(1):
    with Vectorize(2):
        t = Test()
    y = t.as_view()[1,:].x

print(y)

outputting

Test1.x[1,:]
pgkirsch commented 4 years ago

Ah perfect thank you, user error as always!

Interesting side effect: this seems to require a substitution to change shape to (2,1).

with

'fixedvar': [1, 2.2] # previously worked

I get

ValueError: cannot substitute array of shape (2,) for variable fixedvar[1,0] of shape (2, 1).

and with

'fixedvar': [[1, 2.2]]*numberofoutervectorizations # what I was thinking I'd use

I get

ValueError: cannot substitute array of shape (1, 2) for variable fixedvar[1,0] of shape (2, 1).

so

'fixedvar': np.array([[1], [2.2]]),

it is.

bqpd commented 4 years ago

huh, that's not ideal.