Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation bug fixes and Sphinx refactor (replace stray Python/.txt with ..literalinclude) #1508

Closed
wants to merge 11 commits into from
108 changes: 8 additions & 100 deletions docs/source/advancedcommands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,7 @@ For example, air density, viscosity, and temperature are functions of altitude.
These can be represented by a substitution or value that is a one-argument function
accepting ``model.substitutions`` (for details, see `Substitutions`_ below).

.. code-block:: python

# code from t_GPSubs.test_calcconst in tests/t_sub.py
x = Variable("x", "hours")
t_day = Variable("t_{day}", 12, "hours")
t_night = Variable("t_{night}", lambda c: 24 - c[t_day], "hours")
# note that t_night has a function as its value
m = Model(x, [x >= t_day, x >= t_night])
sol = m.solve(verbosity=0)
self.assertAlmostEqual(sol(t_night)/gpkit.ureg.hours, 12)
m.substitutions.update({t_day: ("sweep", [8, 12, 16])})
sol = m.solve(verbosity=0)
self.assertEqual(len(sol["cost"]), 3)
npt.assert_allclose(sol(t_day) + sol(t_night), 24)

.. literalinclude:: examples/evaluated_fixed_variables.py

These functions are automatically differentiated with the `ad <https://pypi.org/project/ad/>`_ package to provide more accurate sensitivities. In some cases may require using functions from the ``ad.admath`` instead of their python or numpy equivalents; the `ad documentation <https://pypi.org/project/ad/>`_ contains details on how to do this.

Expand All @@ -40,16 +26,7 @@ variable, but :math:`(1-\nu)` is a valid GP variable, then :math:`\nu` can be ca
These evaluated free variables can be represented by a ``Variable`` with ``evalfn`` metadata.
Note that this variable should not be used in constructing your model!

.. code-block:: python

# code from t_constraints.test_evalfn in tests/t_sub.py
x = Variable("x")
x2 = Variable("x^2", evalfn=lambda v: v[x]**2)
m = Model(x, [x >= 2])
m.unique_varkeys = set([x2.key])
sol = m.solve(verbosity=0)
self.assertAlmostEqual(sol(x2), sol(x)**2)

.. literalinclude:: examples/evaluated_free_variables.py

For evaluated variables that can be used during a solution, see :ref:`sgp`.

Expand Down Expand Up @@ -94,18 +71,7 @@ tight (that is, the right side does not equal the left side) after solving. This
is useful when you know that a constraint *should* be tight for a given model,
but representing it as an equality would be non-convex.

.. code-block:: python

from gpkit import Variable, Model
from gpkit.constraints.tight import Tight

Tight.reltol = 1e-2 # set the global tolerance of Tight
x = Variable('x')
x_min = Variable('x_{min}', 2)
m = Model(x, [Tight([x >= 1], reltol=1e-3), # set the specific tolerance
x >= x_min])
m.solve(verbosity=0) # prints warning

.. literalinclude:: examples/tight_constraintsets.py

Loose ConstraintSets
====================
Expand All @@ -115,18 +81,7 @@ not loose (that is, their sensitivity is above some threshold after solving). Th
is useful when you want a constraint to be inactive for a given model because
it represents an important model assumption (such as a fit only valid over a particular interval).

.. code-block:: python

from gpkit import Variable, Model
from gpkit.constraints.tight import Loose

Tight.reltol = 1e-4 # set the global tolerance of Tight
x = Variable('x')
x_min = Variable('x_{min}', 1)
m = Model(x, [Loose([x >= 2], senstol=1e-4), # set the specific tolerance
x >= x_min])
m.solve(verbosity=0) # prints warning

.. literalinclude:: examples/loose_constraintsets.py

Substitutions
=============
Expand All @@ -138,31 +93,14 @@ Substituting into Posynomials, NomialArrays, and GPs

The examples below all use Posynomials and NomialArrays, but the syntax is identical for GPs (except when it comes to sweep variables).

.. code-block:: python

# adapted from t_sub.py / t_NomialSubs / test_Basic
from gpkit import Variable
x = Variable("x")
p = x**2
assert p.sub(x, 3) == 9
assert p.sub(x.varkeys["x"], 3) == 9
assert p.sub("x", 3) == 9
.. literalinclude:: examples/substitutions.py

Here the variable ``x`` is being replaced with ``3`` in three ways: first by substituting for ``x`` directly, then by substituting for the ``VarKey("x")``, then by substituting the string "x". In all cases the substitution is understood as being with the VarKey: when a variable is passed in the VarKey is pulled out of it, and when a string is passed in it is used as an argument to the Posynomial's ``varkeys`` dictionary.

Substituting multiple values
----------------------------

.. code-block:: python

# adapted from t_sub.py / t_NomialSubs / test_Vector
from gpkit import Variable, VectorVariable
x = Variable("x")
y = Variable("y")
z = VectorVariable(2, "z")
p = x*y*z
assert all(p.sub({x: 1, "y": 2}) == 2*z)
assert all(p.sub({x: 1, y: 2, "z": [1, 2]}) == z.sub(z, [2, 4]))
.. literalinclude:: examples/substituting_multiple_values.py

To substitute in multiple variables, pass them in as a dictionary where the keys are what will be replaced and values are what it will be replaced with. Note that you can also substitute for VectorVariables by their name or by their NomialArray.

Expand All @@ -171,28 +109,7 @@ Substituting with nonnumeric values

You can also substitute in sweep variables (see Sweeps_), strings, and monomials:

.. code-block:: python

# adapted from t_sub.py / t_NomialSubs
from gpkit import Variable
from gpkit.small_scripts import mag

x = Variable("x", "m")
xvk = x.varkeys.values()[0]
descr_before = x.exp.keys()[0].descr
y = Variable("y", "km")
yvk = y.varkeys.values()[0]
for x_ in ["x", xvk, x]:
for y_ in ["y", yvk, y]:
if not isinstance(y_, str) and type(xvk.units) != str:
expected = 0.001
else:
expected = 1.0
assert abs(expected - mag(x.sub(x_, y_).c)) < 1e-6
if type(xvk.units) != str:
# this means units are enabled
z = Variable("z", "s")
# y.sub(y, z) will raise ValueError due to unit mismatch
.. literalinclude:: examples/substituting_nonnumeric_values.py

Note that units are preserved, and that the value can be either a string (in which case it just renames the variable), a varkey (in which case it changes its description, including the name) or a Monomial (in which case it substitutes for the variable with a new monomial).

Expand All @@ -219,16 +136,7 @@ Freeing Fixed Variables

After creating a Model, it may be useful to "free" a fixed variable and resolve. This can be done using the command ``del m.substitutions["x"]``, where ``m`` is a Model. An example of how to do this is shown below.

.. code-block:: python

from gpkit import Variable, Model
x = Variable("x")
y = Variable("y", 3) # fix value to 3
m = Model(x, [x >= 1 + y, y >= 1])
_ = m.solve() # optimal cost is 4; y appears in sol["constants"]

del m.substitutions["y"]
_ = m.solve() # optimal cost is 2; y appears in Free Variables
.. literalinclude:: examples/freeing_fixed_variables.py

Note that ``del m.substitutions["y"]`` affects ``m`` but not ``y.key``.
``y.value`` will still be 3, and if ``y`` is used in a new model,
Expand Down
6 changes: 3 additions & 3 deletions docs/source/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Say we had a fixed mass of water we wanted to contain within a tank, but also wa

.. literalinclude:: examples/water_tank.py

The output is
The output is:

.. literalinclude:: examples/water_tank_output.txt

Expand All @@ -44,7 +44,7 @@ This example comes from Section 3 of `Geometric Programming for Aircraft Design

.. literalinclude:: examples/simpleflight.py

The output is
The output is:

.. literalinclude:: examples/simpleflight_output.txt

Expand All @@ -54,7 +54,7 @@ In this example we consider a beam subjected to a uniformly distributed transver

.. literalinclude:: examples/beam.py

The output is
The output is:

.. literalinclude:: examples/beam_output.txt

Expand Down
29 changes: 29 additions & 0 deletions docs/source/examples/checking_result_changes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import pickle
from gpkit import Model, Variable

# build model (dummy)
# decision variable
x = Variable("x")
y = Variable("y")

# objective and constraints
objective = 0.23 + x/y # minimize x and y
constraints = [x + y <= 5, x >= 1, y >= 2]

# create model
m = Model(objective, constraints)

# solve the model
sol = m.solve()
Copy link
Contributor

Choose a reason for hiding this comment

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

hmm, should probably create a dummy model here

Copy link
Author

@mtwichan mtwichan Jul 20, 2020

Choose a reason for hiding this comment

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

Added a dummy model here: 33588b9

I noticed when running last_verified_sol = pickle.load(open("last_verified.sol")) here: https://github.com/convexengineering/gpkit/pull/1508/files#diff-79562c84e117012e71221b6d88dd595bR23

I was getting this error:

Traceback (most recent call last):
  File "checking_result_changes.py", line 23, in <module>
    last_verified_sol = pickle.load(open("last_verified.sol"))
  File "/usr/lib/python3.6/codecs.py", line 321, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 330: invalid start byte

so I changed the code to: last_verified_sol = pickle.load(open("last_verified.sol", mode="rb")) and it worked successfully.

Not sure if this is a bug or not.


# save the current state of the model
sol.save("last_verified.sol")

# uncomment the line below to verify a new model
last_verified_sol = pickle.load(open("last_verified.sol", mode="rb"))
if not sol.almost_equal(last_verified_sol, reltol=1e-3):
print(last_verified_sol.diff(sol))

# Note you can replace the last three lines above with
# print(sol.diff("last_verified.sol"))
# if you don't mind doing the diff in that direction.
8 changes: 8 additions & 0 deletions docs/source/examples/creating_monomials.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from gpkit import Variable

# create a Monomial term xy^2/z
x = Variable("x")
Copy link
Contributor

Choose a reason for hiding this comment

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

needs to import from gpkit

y = Variable("y")
z = Variable("z")
m = x * y**2 / z
print(type(m)) # gpkit.nomials.Monomial
7 changes: 7 additions & 0 deletions docs/source/examples/creating_posynomials.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from gpkit import Variable

# create a Posynomial expression x + xy^2
x = Variable("x")
Copy link
Contributor

Choose a reason for hiding this comment

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

needs to import from gpkit

y = Variable("y")
p = x + x * y**2
print(type(p)) # gpkit.nomials.Posynomial
10 changes: 10 additions & 0 deletions docs/source/examples/declaring_constraints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from gpkit import Variable

# consider a block with dimensions x, y, z less than 1
# constrain surface area less than 1.0 m^2
x = Variable("x", "m")
Copy link
Contributor

Choose a reason for hiding this comment

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

needs to import from gpkit

y = Variable("y", "m")
z = Variable("z", "m")
S = Variable("S", 1.0, "m^2")
c = (2*x*y + 2*x*z + 2*y*z <= S)
print(type(c)) # gpkit.nomials.PosynomialInequality
15 changes: 15 additions & 0 deletions docs/source/examples/evaluated_fixed_variables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import gpkit
from gpkit import Variable, Model

# code from t_GPSubs.test_calcconst in tests/t_sub.py
Copy link
Contributor

Choose a reason for hiding this comment

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

needs imports

Copy link
Author

Choose a reason for hiding this comment

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

I removed lines 8, 11, and 12 here: ba46ab0#diff-9847f1403832c7286b52e60d7fe3313fR8-R12

I wasn't quite sure how they were relevant to the code. They may be artifacts from the test/t_sub.py code.

x = Variable("x", "hours")
t_day = Variable("t_{day}", 12, "hours")
t_night = Variable("t_{night}", lambda c: 24 - c[t_day], "hours")

# note that t_night has a function as its value
m = Model(x, [x >= t_day, x >= t_night])
sol = m.solve(verbosity=0)

# call substitutions
m.substitutions.update({t_day: ("sweep", [8, 12, 16])})
sol = m.solve(verbosity=0)
8 changes: 8 additions & 0 deletions docs/source/examples/evaluated_free_variables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from gpkit import Variable, Model

# code from t_constraints.test_evalfn in tests/t_sub.py
Copy link
Contributor

Choose a reason for hiding this comment

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

needs imports

Copy link
Author

Choose a reason for hiding this comment

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

x = Variable("x")
x2 = Variable("x^2", evalfn=lambda v: v[x]**2)
m = Model(x, [x >= 2])
m.unique_varkeys = set([x2.key])
sol = m.solve(verbosity=0)
5 changes: 5 additions & 0 deletions docs/source/examples/fixed_variables_1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from gpkit import Variable

# Declare \rho equal to 1.225 kg/m^3.
# NOTE: in python string literals, backslashes must be doubled
rho = Variable("\\rho", 1.225, "kg/m^3", "Density of air at sea level")
Copy link
Contributor

Choose a reason for hiding this comment

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

needs to import from GPkit

4 changes: 4 additions & 0 deletions docs/source/examples/fixed_variables_2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from gpkit import Variable

#Declare pi equal to 3.14
pi = Variable("\\pi", 3.14)
Copy link
Contributor

Choose a reason for hiding this comment

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

needs to import, should probably add constant=True to the declaration and also use this an example of that syntax?

Copy link
Author

Choose a reason for hiding this comment

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

I don't see anything in the docs about constant=True, but I can still add it. I didn't see anything in the glossary that pointed to this as an option (or I'm blind) either.

10 changes: 10 additions & 0 deletions docs/source/examples/formulating_a_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from gpkit import Variable, Model

x = Variable("x")
y = Variable("y")
z = Variable("z")
S = 200
objective = 1/(x*y*z)
Copy link
Contributor

Choose a reason for hiding this comment

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

needs to import and declare variables

constraints = [2*x*y + 2*x*z + 2*y*z <= S,
x >= 2*y]
m = Model(objective, constraints)
10 changes: 10 additions & 0 deletions docs/source/examples/free_variables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from gpkit import Variable

# Declare a variable, x
x = Variable("x")
Copy link
Contributor

Choose a reason for hiding this comment

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

needs to import


# Declare a variable, y, with units of meters
y = Variable("y", "m")

# Declare a variable, z, with units of meters, and a description
z = Variable("z", "m", "A variable called z with units of meters")
8 changes: 8 additions & 0 deletions docs/source/examples/freeing_fixed_variables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from gpkit import Variable, Model
x = Variable("x")
y = Variable("y", 3) # fix value to 3
m = Model(x, [x >= 1 + y, y >= 1])
_ = m.solve() # optimal cost is 4; y appears in sol["constants"]

del m.substitutions["y"]
_ = m.solve() # optimal cost is 2; y appears in Free Variables
1 change: 1 addition & 0 deletions docs/source/examples/getting_started.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from gpkit import Variable, VectorVariable, Model
Copy link
Contributor

Choose a reason for hiding this comment

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

this should be part of a larger file. this particular line can be excerpted as part of the literalquote syntax

Copy link
Author

@mtwichan mtwichan Jul 20, 2020

Choose a reason for hiding this comment

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

What is the literalquote syntax? I searched it up in Sphinx but had no luck. Alternatively, how do you feel about keeping trivial lines of code like this one inline?

Binary file added docs/source/examples/last_verified.pkl
Binary file not shown.
Binary file added docs/source/examples/last_verified.sol
Binary file not shown.
9 changes: 9 additions & 0 deletions docs/source/examples/loose_constraintsets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from gpkit import Variable, Model
from gpkit.constraints.loose import Loose

Loose.reltol = 1e-4 # set the global tolerance of Tight
x = Variable('x')
x_min = Variable('x_{min}', 1)
m = Model(x, [Loose([x >= 2], senstol=1e-4), # set the specific tolerance
x >= x_min])
m.solve(verbosity=0) # prints warning
7 changes: 7 additions & 0 deletions docs/source/examples/relaxation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"Relaxation examples"

from gpkit import Variable, Model

x = Variable("x")
x_min = Variable("x_min", 2)
x_max = Variable("x_max", 1)
Expand All @@ -13,7 +14,9 @@

print("With constraints relaxed equally")
print("================================")

from gpkit.constraints.relax import ConstraintsRelaxedEqually

allrelaxed = ConstraintsRelaxedEqually(m)
mr1 = Model(allrelaxed.relaxvar, allrelaxed)
print(mr1)
Expand All @@ -22,7 +25,9 @@

print("With constraints relaxed individually")
print("=====================================")

from gpkit.constraints.relax import ConstraintsRelaxed

constraintsrelaxed = ConstraintsRelaxed(m)
mr2 = Model(constraintsrelaxed.relaxvars.prod() * m.cost**0.01,
# add a bit of the original cost in
Expand All @@ -33,7 +38,9 @@

print("With constants relaxed individually")
print("===================================")

from gpkit.constraints.relax import ConstantsRelaxed

constantsrelaxed = ConstantsRelaxed(m)
mr3 = Model(constantsrelaxed.relaxvars.prod() * m.cost**0.01,
# add a bit of the original cost in
Expand Down
1 change: 1 addition & 0 deletions docs/source/examples/solving_the_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sol = m.solve(verbosity=0)
8 changes: 8 additions & 0 deletions docs/source/examples/substituting_multiple_values.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# adapted from t_sub.py / t_NomialSubs / test_Vector
from gpkit import Variable, VectorVariable
x = Variable("x")
y = Variable("y")
z = VectorVariable(2, "z")
p = x*y*z
assert all(p.sub({x: 1, "y": 2}) == 2*z)
assert all(p.sub({x: 1, y: 2, "z": [1, 2]}) == z.sub(z, [2, 4]))
Copy link
Author

Choose a reason for hiding this comment

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

This line is throwing this error:

Traceback (most recent call last):
  File "substituting_multiple_values.py", line 9, in <module>
    sub_two = p.sub({x: 1, y: 2, "z": [1, 2]}).any() == z.sub(z, [2, 4]).any() 
  File "/home/matthew/.local/lib/python3.6/site-packages/gpkit/nomials/array.py", line 182, in sub
    return self.vectorize(lambda nom: nom.sub(subs, require_positive))
  File "/home/matthew/.local/lib/python3.6/site-packages/gpkit/nomials/array.py", line 178, in vectorize
    return vec_recurse(self, function, *args, **kwargs)
  File "/home/matthew/.local/lib/python3.6/site-packages/numpy/lib/function_base.py", line 1972, in __call__
    return self._vectorize_call(func=func, args=vargs)
  File "/home/matthew/.local/lib/python3.6/site-packages/numpy/lib/function_base.py", line 2042, in _vectorize_call
    ufunc, otypes = self._get_ufunc_and_otypes(func=func, args=args)
  File "/home/matthew/.local/lib/python3.6/site-packages/numpy/lib/function_base.py", line 2002, in _get_ufunc_and_otypes
    outputs = func(*inputs)
  File "/home/matthew/.local/lib/python3.6/site-packages/gpkit/nomials/array.py", line 24, in vec_recurse
    return function(element, *args, **kwargs)
  File "/home/matthew/.local/lib/python3.6/site-packages/gpkit/nomials/array.py", line 182, in <lambda>
    return self.vectorize(lambda nom: nom.sub(subs, require_positive))
  File "/home/matthew/.local/lib/python3.6/site-packages/gpkit/nomials/variables.py", line 83, in sub
    return Monomial.sub(self, *args, **kwargs)
  File "/home/matthew/.local/lib/python3.6/site-packages/gpkit/nomials/math.py", line 171, in sub
    return Signomial(self.hmap.sub(substitutions, self.varkeys),
  File "/home/matthew/.local/lib/python3.6/site-packages/gpkit/nomials/map.py", line 104, in sub
    if parsedsubs or not substitutions:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Haven't quite been able to fix it.

Loading