├── .gitignore
├── .pylintrc
├── CODE_OF_CONDUCT.md
├── LICENSE
├── MANIFEST
├── README.md
├── docs
├── Makefile
├── apidoc.sh
├── make.bat
├── refresh_build.sh
└── source
│ ├── _static
│ └── css
│ │ └── custom.css
│ ├── acknowledgements.rst
│ ├── advancedcommands.rst
│ ├── autodoc
│ ├── gpkit.constraints.rst
│ ├── gpkit.interactive.rst
│ ├── gpkit.nomials.rst
│ ├── gpkit.rst
│ ├── gpkit.solvers.rst
│ ├── gpkit.tools.rst
│ └── modules.rst
│ ├── citinggpkit.rst
│ ├── conf.py
│ ├── debugging.rst
│ ├── examples.rst
│ ├── examples
│ ├── autosweep.py
│ ├── autosweep_output.txt
│ ├── beam.py
│ ├── beam.svg
│ ├── beam_output.txt
│ ├── boundschecking.py
│ ├── boundschecking_output.txt
│ ├── breakdowns.py
│ ├── breakdowns
│ │ └── solartest.py
│ ├── breakdowns_output.txt
│ ├── checking_result_changes.py
│ ├── checking_result_changes_output.txt
│ ├── debug.py
│ ├── debug_output.txt
│ ├── docstringparsing.py
│ ├── docstringparsing_output.txt
│ ├── evaluated_fixed_variables.py
│ ├── evaluated_fixed_variables_output.txt
│ ├── evaluated_free_variables.py
│ ├── evaluated_free_variables_output.txt
│ ├── external_constraint.py
│ ├── external_constraint_output.txt
│ ├── external_function.py
│ ├── external_function_output.txt
│ ├── external_sp.py
│ ├── external_sp_output.txt
│ ├── freeing_fixed_variables.py
│ ├── freeing_fixed_variables_output.txt
│ ├── gettingstarted.py
│ ├── gettingstarted_output.txt
│ ├── issue_1513.py
│ ├── issue_1513_output.txt
│ ├── issue_1522.py
│ ├── issue_1522_output.txt
│ ├── last_verified.pkl
│ ├── last_verified.sol
│ ├── loose_constraintsets.py
│ ├── loose_constraintsets_output.txt
│ ├── migp.py
│ ├── migp_output.txt
│ ├── model_var_access.py
│ ├── model_var_access_output.txt
│ ├── performance_modeling.py
│ ├── performance_modeling_output.txt
│ ├── plot_autosweep1d.png
│ ├── plot_sweep1d.png
│ ├── plot_sweep1d.py
│ ├── plot_sweep1d_output.txt
│ ├── primal_infeasible_ex1.py
│ ├── primal_infeasible_ex1_output.txt
│ ├── primal_infeasible_ex2.py
│ ├── primal_infeasible_ex2_output.txt
│ ├── relaxation.py
│ ├── relaxation_output.txt
│ ├── simple_box.py
│ ├── simple_box_output.txt
│ ├── simple_sp.py
│ ├── simple_sp_output.txt
│ ├── simpleflight.py
│ ├── simpleflight_output.txt
│ ├── sin_approx_example.py
│ ├── sin_approx_example_output.txt
│ ├── solar.p
│ ├── solar_10.p
│ ├── solar_12.p
│ ├── solar_13.p
│ ├── sp_to_gp_sweep.py
│ ├── sp_to_gp_sweep_output.txt
│ ├── sub_multi_values.py
│ ├── sub_multi_values_output.txt
│ ├── substitutions.py
│ ├── substitutions_output.txt
│ ├── tight_constraintsets.py
│ ├── tight_constraintsets_output.txt
│ ├── treemap.py
│ ├── treemap_output.txt
│ ├── unbounded.py
│ ├── unbounded_output.txt
│ ├── vectorization.py
│ ├── vectorization_output.txt
│ ├── vectorize.py
│ ├── vectorize_output.txt
│ ├── water_tank.py
│ ├── water_tank_output.txt
│ ├── x_greaterthan_1.py
│ └── x_greaterthan_1_output.txt
│ ├── figures
│ ├── Mission.gif
│ ├── documentation sankeys.ipynb
│ ├── performance_modeling.svg
│ ├── referencesplot.png
│ ├── sankey_autosaves
│ │ ├── Mission.png
│ │ ├── Mission.svg
│ │ ├── Model.png
│ │ ├── Model.svg
│ │ ├── SolarMission.png
│ │ ├── SolarMission.svg
│ │ ├── SolarMission_Aircraft.Wing.Planform.b.png
│ │ ├── SolarMission_Aircraft.Wing.Planform.b.svg
│ │ ├── SolarMission_CFRPFabric.tmin.png
│ │ ├── SolarMission_CFRPFabric.tmin.svg
│ │ ├── SolarMission_Nprop.png
│ │ ├── SolarMission_Nprop.svg
│ │ ├── SolarMission_Wtotal.png
│ │ └── SolarMission_Wtotal.svg
│ ├── sizedconstrainttreemap.png
│ ├── solartest.py
│ └── treemap.png
│ ├── gettingstarted.rst
│ ├── gp101.rst
│ ├── gplogo.png
│ ├── gplogo.svg
│ ├── index.rst
│ ├── installation.rst
│ ├── ipynb
│ ├── BEMT.ipynb
│ ├── Box
│ │ ├── Box.ipynb
│ │ ├── Box.rst
│ │ ├── Box_files
│ │ │ └── Box_34_0.png
│ │ ├── box-ractive.svg
│ │ ├── box.constraints
│ │ ├── box.gpkit
│ │ ├── box.html
│ │ ├── box.svg
│ │ └── boxlogo.svg
│ ├── Examples from Geometric Programming.ipynb
│ ├── Fuel
│ │ ├── Fuel.ipynb
│ │ ├── Fuel.rst
│ │ ├── Fuel_files
│ │ │ ├── Fuel_17_0.png
│ │ │ ├── Fuel_17_1.png
│ │ │ └── Fuel_17_2.png
│ │ ├── fuel-ractive.svg
│ │ ├── fuel.gpkit
│ │ ├── fuel.html
│ │ ├── fuel.svg
│ │ └── fuellogo.svg
│ ├── Wind.ipynb
│ └── maintenance optimization.ipynb
│ ├── modelbuilding.rst
│ ├── releasenotes.rst
│ ├── signomialprogramming.rst
│ └── visint.rst
├── fulltests.sh
├── gpkit
├── __init__.py
├── breakdowns.py
├── build.py
├── constraints
│ ├── __init__.py
│ ├── array.py
│ ├── bounded.py
│ ├── costed.py
│ ├── gp.py
│ ├── loose.py
│ ├── model.py
│ ├── prog_factories.py
│ ├── relax.py
│ ├── set.py
│ ├── sgp.py
│ ├── sigeq.py
│ ├── single_equation.py
│ └── tight.py
├── exceptions.py
├── globals.py
├── interactive
│ ├── __init__.py
│ ├── plot_sweep.py
│ ├── plotting.py
│ ├── references.py
│ ├── referencesplot.html
│ ├── sankey.py
│ └── widgets.py
├── keydict.py
├── nomials
│ ├── __init__.py
│ ├── array.py
│ ├── core.py
│ ├── data.py
│ ├── map.py
│ ├── math.py
│ ├── substitution.py
│ └── variables.py
├── repr_conventions.py
├── small_classes.py
├── small_scripts.py
├── solution_array.py
├── solution_ensemble.py
├── solvers
│ ├── __init__.py
│ ├── cvxopt.py
│ ├── mosek_cli.py
│ └── mosek_conif.py
├── tests
│ ├── __init__.py
│ ├── from_paths.py
│ ├── helpers.py
│ ├── run_tests.py
│ ├── t_constraints.py
│ ├── t_examples.py
│ ├── t_keydict.py
│ ├── t_model.py
│ ├── t_nomial_array.py
│ ├── t_nomials.py
│ ├── t_small.py
│ ├── t_solution_array.py
│ ├── t_sub.py
│ ├── t_tools.py
│ ├── t_vars.py
│ └── test_repo.py
├── tools
│ ├── __init__.py
│ ├── autosweep.py
│ ├── docstring.py
│ └── tools.py
├── units.py
└── varkey.py
├── linecount.sh
├── pylint.sh
├── rtd_requirements.txt
├── runtests.sh
└── setup.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # iPython checkpoint folders
2 | .ipynb_checkpoints/
3 |
4 | # Pickled solutions
5 | *.p
6 |
7 | # MOSEK CLI folder
8 | gpkit_tmp/
9 |
10 | # Byte-compiled / optimized / DLL files
11 | __pycache__/
12 | *.py[cod]
13 |
14 | # C extensions
15 | *.so
16 |
17 | # Distribution / packaging
18 | .Python
19 | env/
20 | bin/
21 | build/
22 | develop-eggs/
23 | dist/
24 | eggs/
25 | lib/
26 | lib64/
27 | parts/
28 | sdist/
29 | var/
30 | *.egg-info/
31 | .installed.cfg
32 | *.egg
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .cache
43 | nosetests.xml
44 | coverage.xml
45 |
46 | # Translations
47 | *.mo
48 |
49 | # Mr Developer
50 | .mr.developer.cfg
51 | .project
52 | .pydevproject
53 |
54 | # Rope
55 | .ropeproject
56 |
57 | # Django stuff:
58 | *.log
59 | *.pot
60 |
61 | # Sphinx documentation
62 | docs/_build/
63 |
64 | # MATLAB autosave
65 | *.asv
66 |
67 | # CI test xmloutput
68 | test_reports/
69 | test_reports_nounits/
70 |
71 | # MacOSX
72 | *.DS_Store
73 |
74 | # vim
75 | *.swp
76 |
77 | # OSX
78 | .DS_Store
79 |
80 | # Development environment
81 | .idea/
82 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at gpkit@mit.edu. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2022 Edward Burnell
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MANIFEST:
--------------------------------------------------------------------------------
1 | gpkit/constraints/__init__.py
2 | gpkit/constraints/array.py
3 | gpkit/constraints/bounded.py
4 | gpkit/constraints/costed.py
5 | gpkit/constraints/gp.py
6 | gpkit/constraints/loose.py
7 | gpkit/constraints/model.py
8 | gpkit/constraints/prog_factories.py
9 | gpkit/constraints/relax.py
10 | gpkit/constraints/set.py
11 | gpkit/constraints/sgp.py
12 | gpkit/constraints/sigeq.py
13 | gpkit/constraints/single_equation.py
14 | gpkit/constraints/tight.py
15 | gpkit/interactive/__init__.py
16 | gpkit/interactive/plot_sweep.py
17 | gpkit/interactive/plotting.py
18 | gpkit/interactive/references.py
19 | gpkit/interactive/referencesplot.html
20 | gpkit/interactive/sankey.py
21 | gpkit/interactive/widgets.py
22 | gpkit/nomials/__init__.py
23 | gpkit/nomials/array.py
24 | gpkit/nomials/data.py
25 | gpkit/nomials/core.py
26 | gpkit/nomials/math.py
27 | gpkit/nomials/map.py
28 | gpkit/nomials/substitution.py
29 | gpkit/nomials/variables.py
30 | gpkit/solvers/__init__.py
31 | gpkit/solvers/mosek_cli.py
32 | gpkit/solvers/cvxopt.py
33 | gpkit/solvers/mosek_conif.py
34 | gpkit/tests/__init__.py
35 | gpkit/tests/from_paths.py
36 | gpkit/tests/helpers.py
37 | gpkit/tests/run_tests.py
38 | gpkit/tests/t_constraints.py
39 | gpkit/tests/t_examples.py
40 | gpkit/tests/t_keydict.py
41 | gpkit/tests/t_model.py
42 | gpkit/tests/t_nomial_array.py
43 | gpkit/tests/t_nomials.py
44 | gpkit/tests/t_small.py
45 | gpkit/tests/t_solution_array.py
46 | gpkit/tests/t_sub.py
47 | gpkit/tests/t_tools.py
48 | gpkit/tests/t_vars.py
49 | gpkit/tests/test_repo.py
50 | gpkit/tools/__init__.py
51 | gpkit/tools/autosweep.py
52 | gpkit/tools/docstring.py
53 | gpkit/tools/tools.py
54 | gpkit/units.py
55 | gpkit/__init__.py
56 | gpkit/build.py
57 | gpkit/breakdowns.py
58 | gpkit/exceptions.py
59 | gpkit/globals.py
60 | gpkit/keydict.py
61 | gpkit/repr_conventions.py
62 | gpkit/small_classes.py
63 | gpkit/small_scripts.py
64 | gpkit/solution_array.py
65 | gpkit/varkey.py
66 | setup.py
67 | README.md
68 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [
](http://gpkit.readthedocs.org/)
2 |
3 | **[Documentation](http://gpkit.readthedocs.org/)** | [Install instructions](http://gpkit.readthedocs.org/en/latest/installation.html) | [Examples](http://gpkit.readthedocs.org/en/latest/examples.html) | [Glossary](https://gpkit.readthedocs.io/en/latest/autodoc/gpkit.html) | [Citing GPkit](http://gpkit.readthedocs.org/en/latest/citinggpkit.html)
4 |
5 | GPkit is a Python package for defining and manipulating
6 | geometric programming models,
7 | abstracting away the backend solver.
8 | Supported solvers are
9 | [mosek](http://mosek.com)
10 | and [cvxopt](http://cvxopt.org/).
11 |
12 | [](https://acdl.mit.edu/csi/view/convex%20engineering/job/CE_gpkit_Push_unit_tests/) Unit tests
13 |
14 | [](https://acdl.mit.edu/csi/view/convex%20engineering/job/CE_gpkit_Install/) pip install
15 |
16 | [](https://acdl.mit.edu/csi/view/convex%20engineering/job/CE_gpkit_Push_dependency_tests/) Dependencies
17 |
--------------------------------------------------------------------------------
/docs/apidoc.sh:
--------------------------------------------------------------------------------
1 | rm source/autodoc/*
2 | sphinx-apidoc ../gpkit -o source/autodoc
3 |
4 | # Delete first 3 lines
5 | tail -n+3 source/autodoc/gpkit.rst
6 |
7 | # Add header
8 | header=$'Glossary\n********\n\n*For an alphabetical listing of all commands, check out the* :ref:\`genindex\`\n'
9 | echo $header | cat - source/autodoc/gpkit.rst > gpkit.rst && mv gpkit.rst source/autodoc/gpkit.rst
10 |
--------------------------------------------------------------------------------
/docs/refresh_build.sh:
--------------------------------------------------------------------------------
1 | while true
2 | do
3 | sleep 10s
4 | git pull
5 | make html
6 | done
7 |
--------------------------------------------------------------------------------
/docs/source/_static/css/custom.css:
--------------------------------------------------------------------------------
1 | @import 'theme.css';
2 |
3 | div[class^='highlight-breakdowns'] pre {
4 | line-height: 1.15 !important;
5 | }
6 |
--------------------------------------------------------------------------------
/docs/source/acknowledgements.rst:
--------------------------------------------------------------------------------
1 | Acknowledgements
2 | ****************
3 |
4 | We thank the following contributors for helping to improve GPkit:
5 |
6 | * Marshall Galbraith for setting up continuous integration.
7 | * `Stephen Boyd`_ for inspiration and suggestions.
8 | * `Kirsten Bray`_ for designing the GPkit logo.
9 |
10 | .. _`Stephen Boyd`: http://stanford.edu/~boyd/
11 | .. _`Kirsten Bray`: mailto:kgbray@umich.edu
12 |
--------------------------------------------------------------------------------
/docs/source/autodoc/gpkit.constraints.rst:
--------------------------------------------------------------------------------
1 | gpkit.constraints package
2 | =========================
3 |
4 | Submodules
5 | ----------
6 |
7 | gpkit.constraints.array module
8 | ------------------------------
9 |
10 | .. automodule:: gpkit.constraints.array
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | gpkit.constraints.bounded module
16 | --------------------------------
17 |
18 | .. automodule:: gpkit.constraints.bounded
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 | gpkit.constraints.costed module
24 | -------------------------------
25 |
26 | .. automodule:: gpkit.constraints.costed
27 | :members:
28 | :undoc-members:
29 | :show-inheritance:
30 |
31 | gpkit.constraints.gp module
32 | ---------------------------
33 |
34 | .. automodule:: gpkit.constraints.gp
35 | :members:
36 | :undoc-members:
37 | :show-inheritance:
38 |
39 | gpkit.constraints.loose module
40 | ------------------------------
41 |
42 | .. automodule:: gpkit.constraints.loose
43 | :members:
44 | :undoc-members:
45 | :show-inheritance:
46 |
47 | gpkit.constraints.model module
48 | ------------------------------
49 |
50 | .. automodule:: gpkit.constraints.model
51 | :members:
52 | :undoc-members:
53 | :show-inheritance:
54 |
55 | gpkit.constraints.prog\_factories module
56 | ----------------------------------------
57 |
58 | .. automodule:: gpkit.constraints.prog_factories
59 | :members:
60 | :undoc-members:
61 | :show-inheritance:
62 |
63 | gpkit.constraints.relax module
64 | ------------------------------
65 |
66 | .. automodule:: gpkit.constraints.relax
67 | :members:
68 | :undoc-members:
69 | :show-inheritance:
70 |
71 | gpkit.constraints.set module
72 | ----------------------------
73 |
74 | .. automodule:: gpkit.constraints.set
75 | :members:
76 | :undoc-members:
77 | :show-inheritance:
78 |
79 | gpkit.constraints.sgp module
80 | ----------------------------
81 |
82 | .. automodule:: gpkit.constraints.sgp
83 | :members:
84 | :undoc-members:
85 | :show-inheritance:
86 |
87 | gpkit.constraints.sigeq module
88 | ------------------------------
89 |
90 | .. automodule:: gpkit.constraints.sigeq
91 | :members:
92 | :undoc-members:
93 | :show-inheritance:
94 |
95 | gpkit.constraints.single\_equation module
96 | -----------------------------------------
97 |
98 | .. automodule:: gpkit.constraints.single_equation
99 | :members:
100 | :undoc-members:
101 | :show-inheritance:
102 |
103 | gpkit.constraints.tight module
104 | ------------------------------
105 |
106 | .. automodule:: gpkit.constraints.tight
107 | :members:
108 | :undoc-members:
109 | :show-inheritance:
110 |
111 |
112 | Module contents
113 | ---------------
114 |
115 | .. automodule:: gpkit.constraints
116 | :members:
117 | :undoc-members:
118 | :show-inheritance:
119 |
--------------------------------------------------------------------------------
/docs/source/autodoc/gpkit.interactive.rst:
--------------------------------------------------------------------------------
1 | gpkit.interactive package
2 | =========================
3 |
4 | Submodules
5 | ----------
6 |
7 | gpkit.interactive.plot\_sweep module
8 | ------------------------------------
9 |
10 | .. automodule:: gpkit.interactive.plot_sweep
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | gpkit.interactive.plotting module
16 | ---------------------------------
17 |
18 | .. automodule:: gpkit.interactive.plotting
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 | gpkit.interactive.references module
24 | -----------------------------------
25 |
26 | .. automodule:: gpkit.interactive.references
27 | :members:
28 | :undoc-members:
29 | :show-inheritance:
30 |
31 | gpkit.interactive.sankey module
32 | -------------------------------
33 |
34 | .. automodule:: gpkit.interactive.sankey
35 | :members:
36 | :undoc-members:
37 | :show-inheritance:
38 |
39 | gpkit.interactive.widgets module
40 | --------------------------------
41 |
42 | .. automodule:: gpkit.interactive.widgets
43 | :members:
44 | :undoc-members:
45 | :show-inheritance:
46 |
47 |
48 | Module contents
49 | ---------------
50 |
51 | .. automodule:: gpkit.interactive
52 | :members:
53 | :undoc-members:
54 | :show-inheritance:
55 |
--------------------------------------------------------------------------------
/docs/source/autodoc/gpkit.nomials.rst:
--------------------------------------------------------------------------------
1 | gpkit.nomials package
2 | =====================
3 |
4 | Submodules
5 | ----------
6 |
7 | gpkit.nomials.array module
8 | --------------------------
9 |
10 | .. automodule:: gpkit.nomials.array
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | gpkit.nomials.core module
16 | -------------------------
17 |
18 | .. automodule:: gpkit.nomials.core
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 | gpkit.nomials.data module
24 | -------------------------
25 |
26 | .. automodule:: gpkit.nomials.data
27 | :members:
28 | :undoc-members:
29 | :show-inheritance:
30 |
31 | gpkit.nomials.map module
32 | ------------------------
33 |
34 | .. automodule:: gpkit.nomials.map
35 | :members:
36 | :undoc-members:
37 | :show-inheritance:
38 |
39 | gpkit.nomials.math module
40 | -------------------------
41 |
42 | .. automodule:: gpkit.nomials.math
43 | :members:
44 | :undoc-members:
45 | :show-inheritance:
46 |
47 | gpkit.nomials.substitution module
48 | ---------------------------------
49 |
50 | .. automodule:: gpkit.nomials.substitution
51 | :members:
52 | :undoc-members:
53 | :show-inheritance:
54 |
55 | gpkit.nomials.variables module
56 | ------------------------------
57 |
58 | .. automodule:: gpkit.nomials.variables
59 | :members:
60 | :undoc-members:
61 | :show-inheritance:
62 |
63 |
64 | Module contents
65 | ---------------
66 |
67 | .. automodule:: gpkit.nomials
68 | :members:
69 | :undoc-members:
70 | :show-inheritance:
71 |
--------------------------------------------------------------------------------
/docs/source/autodoc/gpkit.rst:
--------------------------------------------------------------------------------
1 | Glossary
2 | ********
3 |
4 | *For an alphabetical listing of all commands, check out the* :ref:`genindex`
5 |
6 | gpkit package
7 | =============
8 |
9 | Subpackages
10 | -----------
11 |
12 | .. toctree::
13 | :maxdepth: 4
14 |
15 | gpkit.constraints
16 | gpkit.interactive
17 | gpkit.nomials
18 | gpkit.solvers
19 | gpkit.tools
20 |
21 | Submodules
22 | ----------
23 |
24 | gpkit.build module
25 | ------------------
26 |
27 | .. automodule:: gpkit.build
28 | :members:
29 | :undoc-members:
30 | :show-inheritance:
31 |
32 | gpkit.exceptions module
33 | -----------------------
34 |
35 | .. automodule:: gpkit.exceptions
36 | :members:
37 | :undoc-members:
38 | :show-inheritance:
39 |
40 | gpkit.globals module
41 | --------------------
42 |
43 | .. automodule:: gpkit.globals
44 | :members:
45 | :undoc-members:
46 | :show-inheritance:
47 |
48 | gpkit.keydict module
49 | --------------------
50 |
51 | .. automodule:: gpkit.keydict
52 | :members:
53 | :undoc-members:
54 | :show-inheritance:
55 |
56 | gpkit.repr\_conventions module
57 | ------------------------------
58 |
59 | .. automodule:: gpkit.repr_conventions
60 | :members:
61 | :undoc-members:
62 | :show-inheritance:
63 |
64 | gpkit.small\_classes module
65 | ---------------------------
66 |
67 | .. automodule:: gpkit.small_classes
68 | :members:
69 | :undoc-members:
70 | :show-inheritance:
71 |
72 | gpkit.small\_scripts module
73 | ---------------------------
74 |
75 | .. automodule:: gpkit.small_scripts
76 | :members:
77 | :undoc-members:
78 | :show-inheritance:
79 |
80 | gpkit.solution\_array module
81 | ----------------------------
82 |
83 | .. automodule:: gpkit.solution_array
84 | :members:
85 | :undoc-members:
86 | :show-inheritance:
87 |
88 | gpkit.units module
89 | ------------------
90 |
91 | .. automodule:: gpkit.units
92 | :members:
93 | :undoc-members:
94 | :show-inheritance:
95 |
96 | gpkit.varkey module
97 | -------------------
98 |
99 | .. automodule:: gpkit.varkey
100 | :members:
101 | :undoc-members:
102 | :show-inheritance:
103 |
104 |
105 | Module contents
106 | ---------------
107 |
108 | .. automodule:: gpkit
109 | :members:
110 | :undoc-members:
111 | :show-inheritance:
112 |
--------------------------------------------------------------------------------
/docs/source/autodoc/gpkit.solvers.rst:
--------------------------------------------------------------------------------
1 | gpkit.solvers package
2 | =====================
3 |
4 | Submodules
5 | ----------
6 |
7 | gpkit.solvers.cvxopt module
8 | ---------------------------
9 |
10 | .. automodule:: gpkit.solvers.cvxopt
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | gpkit.solvers.mosek\_cli module
16 | -------------------------------
17 |
18 | .. automodule:: gpkit.solvers.mosek_cli
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 | gpkit.solvers.mosek\_conif module
24 | ---------------------------------
25 |
26 | .. automodule:: gpkit.solvers.mosek_conif
27 | :members:
28 | :undoc-members:
29 | :show-inheritance:
30 |
31 |
32 | Module contents
33 | ---------------
34 |
35 | .. automodule:: gpkit.solvers
36 | :members:
37 | :undoc-members:
38 | :show-inheritance:
39 |
--------------------------------------------------------------------------------
/docs/source/autodoc/gpkit.tools.rst:
--------------------------------------------------------------------------------
1 | gpkit.tools package
2 | ===================
3 |
4 | Submodules
5 | ----------
6 |
7 | gpkit.tools.autosweep module
8 | ----------------------------
9 |
10 | .. automodule:: gpkit.tools.autosweep
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | gpkit.tools.docstring module
16 | ----------------------------
17 |
18 | .. automodule:: gpkit.tools.docstring
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 | gpkit.tools.tools module
24 | ------------------------
25 |
26 | .. automodule:: gpkit.tools.tools
27 | :members:
28 | :undoc-members:
29 | :show-inheritance:
30 |
31 |
32 | Module contents
33 | ---------------
34 |
35 | .. automodule:: gpkit.tools
36 | :members:
37 | :undoc-members:
38 | :show-inheritance:
39 |
--------------------------------------------------------------------------------
/docs/source/autodoc/modules.rst:
--------------------------------------------------------------------------------
1 | gpkit
2 | =====
3 |
4 | .. toctree::
5 | :maxdepth: 4
6 |
7 | gpkit
8 |
--------------------------------------------------------------------------------
/docs/source/citinggpkit.rst:
--------------------------------------------------------------------------------
1 | Citing GPkit
2 | ************
3 |
4 | If you use GPkit please cite it with the following bibtex::
5 |
6 | @inproceedings{burnell2020gpkit,
7 | author={Burnell, Edward and Damen, Nicole B and Hoburg, Warren},
8 | title={\hbox{GPkit}: A Human-Centered Approach to Convex Optimization in Engineering Design},
9 | booktitle={Proceedings of the 2020 {CHI} Conference on Human Factors in Computing Systems},
10 | year={2020},
11 | doi={10.1145/3313831.3376412}
12 | }
13 |
14 | (and you can read that paper, which describes some of GPkit's design philosophy, `here. `_)
15 |
--------------------------------------------------------------------------------
/docs/source/examples.rst:
--------------------------------------------------------------------------------
1 | Examples
2 | ********
3 |
4 | iPython Notebook Examples
5 | =========================
6 |
7 | More examples, including some with in-depth explanations and interactive visualizations, can be seen `on nbviewer `_.
8 |
9 |
10 | A Trivial GP
11 | ============
12 | The most trivial GP we can think of:
13 | minimize :math:`x` subject to the constraint :math:`x \ge 1`.
14 |
15 | .. literalinclude:: examples/x_greaterthan_1.py
16 |
17 | Of course, the optimal value is 1. Output:
18 |
19 | .. literalinclude:: examples/x_greaterthan_1_output.txt
20 | :language: breakdowns
21 |
22 | Maximizing the Volume of a Box
23 | ==============================
24 | This example comes from Section 2.4 of the `GP tutorial `_, by S. Boyd et. al.
25 |
26 | .. literalinclude:: examples/simple_box.py
27 |
28 | The output is
29 |
30 | .. literalinclude:: examples/simple_box_output.txt
31 | :language: breakdowns
32 |
33 | Water Tank
34 | ==========
35 | Say we had a fixed mass of water we wanted to contain within a tank, but also wanted to minimize the cost of the material we had to purchase (i.e. the surface area of the tank):
36 |
37 | .. literalinclude:: examples/water_tank.py
38 |
39 | The output is:
40 |
41 | .. literalinclude:: examples/water_tank_output.txt
42 | :language: breakdowns
43 |
44 | Simple Wing
45 | ===========
46 | This example comes from Section 3 of `Geometric Programming for Aircraft Design Optimization `_, by W. Hoburg and P. Abbeel.
47 |
48 | .. literalinclude:: examples/simpleflight.py
49 |
50 | The output is:
51 |
52 | .. literalinclude:: examples/simpleflight_output.txt
53 | :language: breakdowns
54 |
55 | Simple Beam
56 | ===========
57 | In this example we consider a beam subjected to a uniformly distributed transverse force along its length. The beam has fixed geometry so we are not optimizing its shape, rather we are simply solving a discretization of the Euler-Bernoulli beam bending equations using GP.
58 |
59 | .. literalinclude:: examples/beam.py
60 |
61 | The output is:
62 |
63 | .. literalinclude:: examples/beam_output.txt
64 | :language: breakdowns
65 |
66 | By plotting the deflection, we can see that the agreement between the analytical solution and the GP solution is good.
67 |
68 | .. figure:: examples/beam.svg
69 | :width: 500 px
70 | :align: center
71 |
72 | .. Comments:
73 |
74 | ..
75 | .. literalinclude:: code/simple_box.py
76 | :language: python
77 | :emphasize-lines: 2-4, 6
78 | :lines: 1-7
79 |
--------------------------------------------------------------------------------
/docs/source/examples/autosweep.py:
--------------------------------------------------------------------------------
1 | "Show autosweep_1d functionality"
2 | import pickle
3 | import numpy as np
4 | import gpkit
5 | from gpkit import units, Variable, Model
6 | from gpkit.tools.autosweep import autosweep_1d
7 | from gpkit.small_scripts import mag
8 |
9 | A = Variable("A", "m**2")
10 | l = Variable("l", "m")
11 |
12 | m1 = Model(A**2, [A >= l**2 + units.m**2])
13 | tol1 = 1e-3
14 | bst1 = autosweep_1d(m1, tol1, l, [1, 10], verbosity=0)
15 | print("Solved after %2i passes, cost logtol +/-%.3g" % (bst1.nsols, bst1.tol))
16 | # autosweep solution accessing
17 | l_vals = np.linspace(1, 10, 10)
18 | sol1 = bst1.sample_at(l_vals)
19 | print("values of l: %s" % l_vals)
20 | print("values of A: [%s] %s" %
21 | (" ".join("% .1f" % n for n in sol1("A").magnitude), sol1("A").units))
22 | cost_estimate = sol1["cost"]
23 | cost_lb, cost_ub = sol1.cost_lb(), sol1.cost_ub()
24 | print("cost lower bound:\n%s\n" % cost_lb)
25 | print("cost estimate:\n%s\n" % cost_estimate)
26 | print("cost upper bound:\n%s\n" % cost_ub)
27 | # you can evaluate arbitrary posynomials
28 | np.testing.assert_allclose(mag(2*sol1(A)), mag(sol1(2*A)))
29 | assert (sol1["cost"] == sol1(A**2)).all()
30 | # the cost estimate is the logspace mean of its upper and lower bounds
31 | np.testing.assert_allclose((np.log(mag(cost_lb)) + np.log(mag(cost_ub)))/2,
32 | np.log(mag(cost_estimate)))
33 | # save autosweep to a file and retrieve it
34 | bst1.save("autosweep.pkl")
35 | bst1_loaded = pickle.load(open("autosweep.pkl", "rb"))
36 |
37 | # this problem is two intersecting lines in logspace
38 | m2 = Model(A**2, [A >= (l/3)**2, A >= (l/3)**0.5 * units.m**1.5])
39 | tol2 = {"mosek_cli": 1e-6, "mosek_conif": 1e-6,
40 | "cvxopt": 1e-7}[gpkit.settings["default_solver"]]
41 | # test Model method
42 | sol2 = m2.autosweep({l: [1, 10]}, tol2, verbosity=0)
43 | bst2 = sol2.bst
44 | print("Solved after %2i passes, cost logtol +/-%.3g" % (bst2.nsols, bst2.tol))
45 | print("Table of solutions used in the autosweep:")
46 | print(bst2.solarray.table())
47 |
--------------------------------------------------------------------------------
/docs/source/examples/autosweep_output.txt:
--------------------------------------------------------------------------------
1 | Solved after 33 passes, cost logtol +/-0.000992
2 | values of l: [ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
3 | values of A: [ 2.0 5.0 10.0 17.0 26.0 37.0 50.0 65.0 82.0 101.0] meter ** 2
4 | cost lower bound:
5 | [3.99999897e+00 2.49990635e+01 9.99519417e+01 2.88964405e+02
6 | 6.75761038e+02 1.36887689e+03 2.49888336e+03 4.22418997e+03
7 | 6.72085595e+03 1.02009910e+04]
8 |
9 | cost estimate:
10 | [3.99999897e+00 2.50021684e+01 1.00001162e+02 2.89043164e+02
11 | 6.76096986e+02 1.36923920e+03 2.50043987e+03 4.22599006e+03
12 | 6.72550897e+03 1.02009910e+04]
13 |
14 | cost upper bound:
15 | [3.99999897e+00 2.50052737e+01 1.00050406e+02 2.89121944e+02
16 | 6.76433102e+02 1.36960161e+03 2.50199736e+03 4.22779092e+03
17 | 6.73016521e+03 1.02009910e+04]
18 |
19 | Solved after 3 passes, cost logtol +/-0
20 | Table of solutions used in the autosweep:
21 |
22 | Optimal Cost
23 | ------------
24 | [ 0.333 1 123 ]
25 |
26 | Free Variables
27 | --------------
28 | A : [ 0.577 1 11.1 ] [m²]
29 |
30 | Fixed Variables
31 | ---------------
32 | l : [ 1 3 10 ] [m]
33 |
34 | Variable Sensitivities
35 | ----------------------
36 | l : [ +1 +2.5 +4 ]
37 |
38 | Most Sensitive Constraints (in last sweep)
39 | ------------------------------------------
40 | +2 : A ≥ (l/3)²
41 |
42 |
--------------------------------------------------------------------------------
/docs/source/examples/beam.py:
--------------------------------------------------------------------------------
1 | """
2 | A simple beam example with fixed geometry. Solves the discretized
3 | Euler-Bernoulli beam equations for a constant distributed load
4 | """
5 | import numpy as np
6 | from gpkit import parse_variables, Model, ureg
7 | from gpkit.small_scripts import mag
8 |
9 | eps = 2e-4 # has to be quite large for consistent cvxopt printouts;
10 | # normally you'd set this to something more like 1e-20
11 |
12 |
13 | class Beam(Model):
14 | """Discretization of the Euler beam equations for a distributed load.
15 |
16 | Variables
17 | ---------
18 | EI [N*m^2] Bending stiffness
19 | dx [m] Length of an element
20 | L 5 [m] Overall beam length
21 |
22 | Boundary Condition Variables
23 | ----------------------------
24 | V_tip eps [N] Tip loading
25 | M_tip eps [N*m] Tip moment
26 | th_base eps [-] Base angle
27 | w_base eps [m] Base deflection
28 |
29 | Node Variables of length N
30 | --------------------------
31 | q 100*np.ones(N) [N/m] Distributed load
32 | V [N] Internal shear
33 | M [N*m] Internal moment
34 | th [-] Slope
35 | w [m] Displacement
36 |
37 | Upper Unbounded
38 | ---------------
39 | w_tip
40 |
41 | """
42 | @parse_variables(__doc__, globals())
43 | def setup(self, N=4):
44 | # minimize tip displacement (the last w)
45 | self.cost = self.w_tip = w[-1]
46 | return {
47 | "definition of dx": L == (N-1)*dx,
48 | "boundary_conditions": [
49 | V[-1] >= V_tip,
50 | M[-1] >= M_tip,
51 | th[0] >= th_base,
52 | w[0] >= w_base
53 | ],
54 | # below: trapezoidal integration to form a piecewise-linear
55 | # approximation of loading, shear, and so on
56 | # shear and moment increase from tip to base (left > right)
57 | "shear integration":
58 | V[:-1] >= V[1:] + 0.5*dx*(q[:-1] + q[1:]),
59 | "moment integration":
60 | M[:-1] >= M[1:] + 0.5*dx*(V[:-1] + V[1:]),
61 | # slope and displacement increase from base to tip (right > left)
62 | "theta integration":
63 | th[1:] >= th[:-1] + 0.5*dx*(M[1:] + M[:-1])/EI,
64 | "displacement integration":
65 | w[1:] >= w[:-1] + 0.5*dx*(th[1:] + th[:-1])
66 | }
67 |
68 |
69 | b = Beam(N=6, substitutions={"L": 6, "EI": 1.1e4, "q": 110*np.ones(6)})
70 | sol = b.solve(verbosity=0)
71 | print(sol.summary(maxcolumns=6))
72 | w_gp = sol("w") # deflection along beam
73 |
74 | L, EI, q = sol("L"), sol("EI"), sol("q")
75 | x = np.linspace(0, mag(L), len(q))*ureg.m # position along beam
76 | q = q[0] # assume uniform loading for the check below
77 | w_exact = q/(24*EI) * x**2 * (x**2 - 4*L*x + 6*L**2) # analytic soln
78 | assert max(abs(w_gp - w_exact)) <= 1.1*ureg.cm
79 |
80 | PLOT = False
81 | if PLOT: # pragma: no cover
82 | import matplotlib.pyplot as plt
83 | x_exact = np.linspace(0, L, 1000)
84 | w_exact = q/(24*EI) * x_exact**2 * (x_exact**2 - 4*L*x_exact + 6*L**2)
85 | plt.plot(x, w_gp, color='red', linestyle='solid', marker='^',
86 | markersize=8)
87 | plt.plot(x_exact, w_exact, color='blue', linestyle='dashed')
88 | plt.xlabel('x [m]')
89 | plt.ylabel('Deflection [m]')
90 | plt.axis('equal')
91 | plt.legend(['GP solution', 'Analytical solution'])
92 | plt.show()
93 |
--------------------------------------------------------------------------------
/docs/source/examples/beam_output.txt:
--------------------------------------------------------------------------------
1 |
2 | ┃┓ ┓ ┓ ┓ ┓
3 | ┃┃ ┃ ┃ ┃ ┣╸th[2]╶⎨
4 | ┃┃ ┃ ┃ ┣╸w[2] ┛ (0.285)
5 | ┃┃ ┃ ┃ ┃ (0.384m) ┣╸th[1]╶⎨
6 | ┃┃ ┃ ┣╸w[3] ┛ ┣╸w[1]╶⎨
7 | ┃┃ ┃ ┃ (0.76m) ┣╸th[3] ┣╸th[2]╶⎨
8 | ┃┃ ┃ ┃ ┛ (0.341) ┛
9 | ┃┃ ┣╸w[4] ┃ ┣╸th[2]╶⎨
10 | ┃┃ ┃ (1.18m) ┛ ┛
11 | Cost╺┫┃ ┃ ┣╸th[3] ┣╸th[2]╶⎨
12 | (1.62m) ┃┣╸w[5] ┃ ┛ ┛
13 | ┃┃ (1.62m) ┃ ┓ ┓
14 | ┃┃ ┃ ┣╸th[4] ┣╸th[2]╶⎨
15 | ┃┃ ┛ ┛ (0.363) ┛
16 | ┃┃ ┓ ┓
17 | ┃┃ ┣╸th[5] ┣╸th[2]╶⎨
18 | ┃┃ ┛ (0.367) ┛
19 | ┃┃ ┓ ┓
20 | ┃┃ ┣╸th[4] ┣╸th[2]╶⎨
21 | ┃┛ ┛ ┛
22 |
23 |
24 |
25 | ┃┓ ┓
26 | ┃┃ ┃
27 | ┃┃ ┣╸L = 5·dx
28 | ┃┃ ┛
29 | ┃┃ ┓
30 | ┃┃ ┃
31 | ┃┃ ┣╸L = 6m
32 | ┃┃ ┛
33 | ┃┃ ┣╸EI = 11,000N·m²
34 | Model╺┫┃ ┣╸w[5] ≥ w[4] + 0.5·dx·(th[5] + th[4])
35 | ┃┣╸Beam ┣╸th[2] ≥ th[1] + 0.5·dx·(M[2] + M[1])/EI
36 | ┃┃ ┣╸w[4] ≥ w[3] + 0.5·dx·(th[4] + th[3])
37 | ┃┃ ┣╸M[1] ≥ M[2] + 0.5·dx·(V[1] + V[2])
38 | ┃┃ ┣╸th[3] ≥ th[2] + 0.5·dx·(M[3] + M[2])/EI
39 | ┃┃ ┣╸V[3] ≥ V[4] + 0.5·dx·(q[3] + q[4])
40 | ┃┃ ┣╸th[1] ≥ th[0] + 0.5·dx·(M[1] + M[0])/EI
41 | ┃┃ ┓
42 | ┃┃ ┃
43 | ┃┃ ┣╸[17 terms]
44 | ┃┛ ┛
45 |
46 |
47 | Free Variables
48 | --------------
49 | dx : 1.2 [m] Length of an element
50 | M : [ 1.98e+03 1.27e+03 713 317 79.2 0.0002 ] [N·m] Internal moment
51 | V : [ 660 528 396 264 132 0.0002 ] [N] Internal shear
52 | th : [ 0.0002 0.177 0.285 0.341 0.363 0.367 ] Slope
53 | w : [ 0.0002 0.107 0.384 0.76 1.18 1.62 ] [m] Displacement
54 |
55 |
--------------------------------------------------------------------------------
/docs/source/examples/boundschecking.py:
--------------------------------------------------------------------------------
1 | "Verifies that bounds are caught through monomials"
2 | from gpkit import Model, parse_variables
3 | from gpkit.exceptions import UnboundedGP, UnknownInfeasible
4 |
5 |
6 | class BoundsChecking(Model):
7 | """Implements a crazy set of unbounded variables.
8 |
9 | Variables
10 | ---------
11 | Ap [-] d
12 | D [-] e
13 | F [-] s
14 | mi [-] c
15 | mf [-] r
16 | T [-] i
17 | nu [-] p
18 | Fs 0.9 [-] t
19 | mb 0.4 [-] i
20 | rf 0.01 [-] o
21 | V 300 [-] n
22 |
23 | Upper Unbounded
24 | ---------------
25 | F
26 |
27 | Lower Unbounded
28 | ---------------
29 | D
30 |
31 | """
32 | @parse_variables(__doc__, globals())
33 | def setup(self):
34 | self.cost = F
35 | return [
36 | F >= D + T,
37 | D == rf*V**2*Ap,
38 | Ap == nu,
39 | T == mf*V,
40 | mf >= mi + mb,
41 | mf == rf*V,
42 | Fs <= mi
43 | ]
44 |
45 |
46 | m = BoundsChecking()
47 | print(m.str_without(["lineage"]))
48 | try:
49 | m.solve()
50 | except UnboundedGP:
51 | gp = m.gp(checkbounds=False)
52 | missingbounds = gp.check_bounds()
53 |
54 | try:
55 | sol = gp.solve(verbosity=0) # Errors on mosek_cli
56 | except UnknownInfeasible: # pragma: no cover
57 | pass
58 |
59 | bpl = ", but would gain it from any of these sets: "
60 | assert missingbounds[(m.D.key, 'lower')] == bpl + "[(%s, 'lower')]" % m.Ap
61 | assert missingbounds[(m.nu.key, 'lower')] == bpl + "[(%s, 'lower')]" % m.Ap
62 | # ordering is arbitrary:
63 | assert missingbounds[(m.Ap.key, 'lower')] in (
64 | bpl + ("[(%s, 'lower')] or [(%s, 'lower')]" % (m.D, m.nu)),
65 | bpl + ("[(%s, 'lower')] or [(%s, 'lower')]" % (m.nu, m.D)))
66 |
--------------------------------------------------------------------------------
/docs/source/examples/boundschecking_output.txt:
--------------------------------------------------------------------------------
1 | BoundsChecking
2 | ==============
3 |
4 | Cost Function
5 | -------------
6 | F
7 |
8 | Constraints
9 | -----------
10 | F ≥ D + T
11 | D = rf·V²·Ap
12 | Ap = nu
13 | T = mf·V
14 | mf ≥ mi + mb
15 | mf = rf·V
16 | Fs ≤ mi
17 |
--------------------------------------------------------------------------------
/docs/source/examples/breakdowns.py:
--------------------------------------------------------------------------------
1 | "An example to show off Breakdowns"
2 | import os
3 | import sys
4 | import pickle
5 | import pint
6 | from packaging import version
7 | from gpkit.breakdowns import Breakdowns
8 |
9 | dirpath = os.path.dirname(os.path.realpath(__file__)) + os.sep
10 | if version.parse(pint.__version__) >= version.parse("0.13"):
11 | sol = pickle.load(open(dirpath+"solar_13.p", "rb"))
12 | elif version.parse(pint.__version__) >= version.parse("0.12"):
13 | sol = pickle.load(open(dirpath+"solar_12.p", "rb"))
14 | elif version.parse(pint.__version__) >= version.parse("0.10"):
15 | sol = pickle.load(open(dirpath+"solar_10.p", "rb"))
16 | elif version.parse(pint.__version__) == version.parse("0.9"):
17 | sol = pickle.load(open(dirpath+"solar.p", "rb"))
18 | else:
19 | sol = None
20 |
21 | # our Miniconda windows test platform can't print unicode
22 | if sys.platform[:3] != "win" and sol is not None:
23 | # the code to create solar.p is in ./breakdowns/solartest.py
24 | bds = Breakdowns(sol)
25 |
26 | print("Cost breakdown (as seen in solution tables)")
27 | print("==============")
28 | bds.plot("cost")
29 |
30 | print("Variable breakdowns (note the two methods of access)")
31 | print("===================")
32 | varkey, = sol["variables"].keymap[("Mission.FlightSegment.AircraftPerf"
33 | ".AircraftDrag.Poper")]
34 | bds.plot(varkey)
35 | bds.plot("AircraftPerf.AircraftDrag.MotorPerf.Q")
36 |
37 | print("Combining the two above by increasing maxwidth")
38 | print("----------------------------------------------")
39 | bds.plot("AircraftPerf.AircraftDrag.Poper", maxwidth=105)
40 |
41 | print("Model sensitivity breakdowns (note the two methods of access)")
42 | print("============================")
43 | bds.plot("model sensitivities")
44 | bds.plot("Aircraft")
45 |
46 | print("Exhaustive variable breakdown traces (and configuration arguments)")
47 | print("====================================")
48 | # often useful as a reference point when reading traces
49 | bds.plot("AircraftPerf.AircraftDrag.Poper", height=12)
50 | # includes factors, can be useful for reading traces as well
51 | bds.plot("AircraftPerf.AircraftDrag.Poper", showlegend=True)
52 | print("\nPermissivity = 2 (the default)")
53 | print("----------------")
54 | bds.trace("AircraftPerf.AircraftDrag.Poper")
55 | print("\nPermissivity = 1 (stops at Pelec = v·i)")
56 | print("----------------")
57 | bds.trace("AircraftPerf.AircraftDrag.Poper", permissivity=1)
58 |
59 | # you can also produce Plotly treemaps/icicle plots of your breakdowns
60 | fig = bds.treemap("model sensitivities", returnfig=True)
61 | fig = bds.icicle("cost", returnfig=True)
62 | # uncommenting any of the below makes and shows the plot directly
63 | # bds.icicle("model sensitivities")
64 | # bds.treemap("cost")
65 |
--------------------------------------------------------------------------------
/docs/source/examples/breakdowns/solartest.py:
--------------------------------------------------------------------------------
1 | from solar.solar import *
2 | Vehicle = Aircraft(Npod=3, sp=True)
3 | M = Mission(Vehicle, latitude=[20])
4 | M.cost = M[M.aircraft.Wtotal]
5 |
6 | M.localsolve().save("solar_13.p") # suffix is min pint version worked for
7 |
--------------------------------------------------------------------------------
/docs/source/examples/checking_result_changes.py:
--------------------------------------------------------------------------------
1 | "Example code for solution saving and differencing."
2 | import pickle
3 | from gpkit import Model, Variable
4 |
5 | # build model (dummy)
6 | # decision variable
7 | x = Variable("x")
8 | y = Variable("y")
9 |
10 | # objective and constraints
11 | objective = 0.23 + x/y # minimize x and y
12 | constraints = [x + y <= 5, x >= 1, y >= 2]
13 |
14 | # create model
15 | m = Model(objective, constraints)
16 |
17 | # solve the model
18 | # verbosity is 0 for testing's sake, no need to do that in your code!
19 | sol = m.solve(verbosity=0)
20 |
21 | # save the current state of the model
22 | sol.save("last_verified.sol")
23 |
24 | # uncomment the line below to verify a new model
25 | last_verified_sol = pickle.load(open("last_verified.sol", mode="rb"))
26 | if not sol.almost_equal(last_verified_sol, reltol=1e-3):
27 | print(last_verified_sol.diff(sol))
28 |
29 | # Note you can replace the last three lines above with
30 | # print(sol.diff("last_verified.sol"))
31 | # if you don't mind doing the diff in that direction.
32 |
--------------------------------------------------------------------------------
/docs/source/examples/checking_result_changes_output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/checking_result_changes_output.txt
--------------------------------------------------------------------------------
/docs/source/examples/debug.py:
--------------------------------------------------------------------------------
1 | "Debug examples"
2 | from gpkit import Variable, Model, units
3 |
4 | x = Variable("x", "ft")
5 | x_min = Variable("x_min", 2, "ft")
6 | x_max = Variable("x_max", 1, "ft")
7 | y = Variable("y", "volts")
8 |
9 | m = Model(x/y, [x <= x_max, x >= x_min])
10 | m.debug()
11 |
12 | print("# Now let's try a model unsolvable with relaxed constants\n")
13 |
14 | m2 = Model(x, [x <= units("inch"), x >= units("yard")])
15 | m2.debug()
16 |
17 | print("# And one that's only unbounded\n")
18 |
19 | # the value of x_min was used up in the previous model!
20 | x_min = Variable("x_min", 2, "ft")
21 | m3 = Model(x/y, [x >= x_min])
22 | m3.debug()
23 |
24 | x_min = Variable("x_min", 2, "ft")
25 | m4 = Model(x, [x >= x_min])
26 | m4.debug()
27 |
--------------------------------------------------------------------------------
/docs/source/examples/debug_output.txt:
--------------------------------------------------------------------------------
1 | Model is feasible with these modifications:
2 |
3 | Arbitrarily Bounded Variables
4 | -----------------------------
5 | value near upper bound of 1e+30: y
6 | sensitive to upper bound of 1e+30: y
7 |
8 | Relaxed Constants
9 | -----------------
10 | x_min [ft]: relaxed from 2 to 1
11 |
12 | # Now let's try a model unsolvable with relaxed constants
13 |
14 | Model is not feasible with relaxed constants and bounded variables.
15 | Model is feasible with these modifications:
16 |
17 | Relaxed Constraints
18 | -------------------
19 | 1: 3500% relaxed, from x [ft] >= 1 [yd]
20 | to 36·x [ft] >= 1 [yd]
21 |
22 | # And one that's only unbounded
23 |
24 | Model is feasible with these modifications:
25 |
26 | Arbitrarily Bounded Variables
27 | -----------------------------
28 | value near upper bound of 1e+30: y
29 | sensitive to upper bound of 1e+30: y
30 |
31 | Model seems feasible without modification, or only needs relaxations of less than 1%. Check the returned solution for details.
32 |
--------------------------------------------------------------------------------
/docs/source/examples/docstringparsing.py:
--------------------------------------------------------------------------------
1 | "Docstring parsing example"
2 | from gpkit import Model, parse_variables
3 | from gpkit.tools.docstring import parse_varstring
4 |
5 |
6 | class Cube(Model):
7 | """Demonstration of nomenclature syntax
8 |
9 | Lines that end in "Variables" will be parsed as a scalar variable table
10 | until the next blank line.
11 |
12 | Variables
13 | ---------
14 | A [m^2] surface area
15 | V 100 [L] minimum volume
16 |
17 | Lines that end in "Variables of length $N" will be parsed as vector
18 | variables of length $N until the next blank line.
19 |
20 | Variables of length 3
21 | ---------------------
22 | s [m] side length
23 |
24 | Let's introduce more variables: (any line ending in "Variables" is parsed)
25 |
26 | Zoning Variables
27 | ----------------
28 | h 1 [m] minimum height
29 |
30 | Upper Unbounded
31 | ---------------
32 | A
33 |
34 | The ordering of these blocks doesn't affect anything; order them in the
35 | way that makes the most sense to someone else reading your model.
36 | """
37 | @parse_variables(__doc__, globals())
38 | def setup(self):
39 |
40 | return [A >= 2*(s[0]*s[1] + s[1]*s[2] + s[2]*s[0]),
41 | s.prod() >= V,
42 | s[2] >= h]
43 |
44 |
45 | print(parse_varstring(Cube.__doc__))
46 | c = Cube()
47 | c.cost = c.A
48 | print(c.solve(verbosity=0).table())
49 |
--------------------------------------------------------------------------------
/docs/source/examples/docstringparsing_output.txt:
--------------------------------------------------------------------------------
1 | from gpkit import Variable, VectorVariable # Demonstration of nomenclature syntax
2 | #
3 | # Lines that end in "Variables" will be parsed as a scalar variable table
4 | # until the next blank line.
5 | #
6 | # Variables
7 | # ---------
8 | A = self.A = Variable('A', 'm^2', 'surface area') # from 'A [m^2] surface area'
9 | V = self.V = Variable('V', 100, 'L', 'minimum volume') # from 'V 100 [L] minimum volume'
10 | #
11 | # Lines that end in "Variables of length $N" will be parsed as vector
12 | # variables of length $N until the next blank line.
13 | #
14 | # Variables of length 3
15 | # ---------------------
16 | s = self.s = VectorVariable(3, 's', 'm', 'side length') # from 's [m] side length'
17 | #
18 | # Let's introduce more variables: (any line ending in "Variables" is parsed)
19 | #
20 | # Zoning Variables
21 | # ----------------
22 | h = self.h = Variable('h', 1, 'm', 'minimum height') # from 'h 1 [m] minimum height'
23 | #
24 | # Upper Unbounded
25 | # ---------------
26 | # A
27 | #
28 | # The ordering of these blocks doesn't affect anything; order them in the
29 | # way that makes the most sense to someone else reading your model.
30 | #
31 |
32 | ┃┓ ┓ /┓
33 | ┃┃ ┃ ┃
34 | ┃┃ ┣╸s[0] /┣╸h
35 | Cost╺┫┃ ┃ (0.316m) ┃ (1m, fixed)
36 | (1.46m²) ┃┣╸A ┛ /┛
37 | ┃┃ (1.46m²) ┓ ┓
38 | ┃┃ ┣╸s[2] ┣╸h
39 | ┃┛ ┛ (1m) ┛
40 |
41 |
42 |
43 | ┃┓ ┓
44 | ┃┃ ┃
45 | ┃┃ ┃
46 | ┃┃ ┃
47 | ┃┃ ┣╸A ≥ 2·(s[0]·s[1] + s[1]·s[2] + s[2]·s[0])
48 | ┃┃ ┃
49 | ┃┃ ┃
50 | ┃┃ ┛
51 | ┃┃ ┓
52 | Model╺┫┃ ┃
53 | ┃┣╸Cube ┣╸V = 100l
54 | ┃┃ ┛
55 | ┃┃ ┓
56 | ┃┃ ┃
57 | ┃┃ ┣╸V ≤ s[:].prod()
58 | ┃┃ ┛
59 | ┃┃ ┣╸h = 1m
60 | ┃┃ ┛
61 | ┃┃ ┣╸s[2] ≥ h
62 | ┃┛ ┛
63 |
64 |
65 | Free Variables
66 | --------------
67 | A : 1.465 [m²] surface area
68 | s : [ 0.316 0.316 1 ] [m] side length
69 |
70 | Fixed Variables
71 | ---------------
72 | V : 100 [l] minimum volume
73 | h : 1 [m] minimum height
74 |
75 | Variable Sensitivities
76 | ----------------------
77 | V : +0.57 minimum volume
78 | h : +0.3 minimum height
79 |
80 | Most Sensitive Constraints
81 | --------------------------
82 | +1 : A ≥ 2·(s[0]·s[1] + s[1]·s[2] + s[2]·s[0])
83 | +0.57 : V ≤ s[:].prod()
84 | +0.3 : s[2] ≥ h
85 |
86 |
--------------------------------------------------------------------------------
/docs/source/examples/evaluated_fixed_variables.py:
--------------------------------------------------------------------------------
1 | "Example pre-solve evaluated fixed variable"
2 | from gpkit import Variable, Model, units
3 |
4 | # code from t_GPSubs.test_calcconst in tests/t_sub.py
5 | x = Variable("x", "hours")
6 | t_day = Variable("t_{day}", 12, "hours")
7 | t_night = Variable("t_{night}",
8 | lambda c: 1*units.day - c(t_day), "hours")
9 |
10 | # note that t_night has a function as its value
11 | m = Model(x, [x >= t_day, x >= t_night])
12 | sol = m.solve(verbosity=0)
13 | assert sol["variables"][t_night] == 12
14 |
15 | # call substitutions
16 | m.substitutions.update({t_day: ("sweep", [8, 12, 16])})
17 | sol = m.solve(verbosity=0)
18 | assert (sol["variables"][t_night] == [16, 12, 8]).all()
19 |
--------------------------------------------------------------------------------
/docs/source/examples/evaluated_fixed_variables_output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/evaluated_fixed_variables_output.txt
--------------------------------------------------------------------------------
/docs/source/examples/evaluated_free_variables.py:
--------------------------------------------------------------------------------
1 | "Example post-solve evaluated variable"
2 | from gpkit import Variable, Model
3 |
4 | # code from t_constraints.test_evalfn in tests/t_sub.py
5 | x = Variable("x")
6 | x2 = Variable("x^2", evalfn=lambda v: v(x)**2)
7 | m = Model(x, [x >= 2])
8 | m.unique_varkeys = set([x2.key])
9 | sol = m.solve(verbosity=0)
10 | assert abs(sol(x2) - 4) <= 1e-4
11 |
--------------------------------------------------------------------------------
/docs/source/examples/evaluated_free_variables_output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/evaluated_free_variables_output.txt
--------------------------------------------------------------------------------
/docs/source/examples/external_constraint.py:
--------------------------------------------------------------------------------
1 | "Can be found in gpkit/docs/source/examples/external_constraint.py"
2 | from external_function import external_code
3 |
4 |
5 | class ExternalConstraint:
6 | "Class for external calling"
7 |
8 | def __init__(self, x, y):
9 | # We need a GPkit variable defined to return in our constraint. The
10 | # easiest way to do this is to read in the parameters of interest in
11 | # the initiation of the class and store them here.
12 | self.x = x
13 | self.y = y
14 |
15 | def as_gpconstr(self, x0):
16 | "Returns locally-approximating GP constraint"
17 | # Creating a default constraint for the first solve
18 | if self.x not in x0:
19 | return (self.y >= self.x)
20 | # Otherwise calls external code at the current position...
21 | x_star = x0[self.x]
22 | res = external_code(x_star)
23 | # ...and returns a posynomial approximation around that position
24 | return (self.y >= res * self.x/x_star)
25 |
--------------------------------------------------------------------------------
/docs/source/examples/external_constraint_output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/external_constraint_output.txt
--------------------------------------------------------------------------------
/docs/source/examples/external_function.py:
--------------------------------------------------------------------------------
1 | """External function for GPkit to call. Can be found
2 | in gpkit/docs/source/examples/external_function.py"""
3 | import numpy as np
4 |
5 | def external_code(x):
6 | "Returns sin(x)"
7 | return np.sin(x)
8 |
--------------------------------------------------------------------------------
/docs/source/examples/external_function_output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/external_function_output.txt
--------------------------------------------------------------------------------
/docs/source/examples/external_sp.py:
--------------------------------------------------------------------------------
1 | "Can be found in gpkit/docs/source/examples/external_sp.py"
2 | import numpy as np
3 | from gpkit import Variable, Model
4 | from external_constraint import ExternalConstraint
5 |
6 | x = Variable("x")
7 | y = Variable("y")
8 |
9 | objective = y
10 |
11 | constraints = [ExternalConstraint(x, y),
12 | x <= np.pi/2,
13 | x >= np.pi/4,
14 | ]
15 |
16 | m = Model(objective, constraints)
17 | print(m.localsolve(verbosity=0).summary())
18 |
--------------------------------------------------------------------------------
/docs/source/examples/external_sp_output.txt:
--------------------------------------------------------------------------------
1 |
2 | ┃┓
3 | Cost╺┫┃
4 | (0.707) ┃┣╸0.785
5 | ┃┛
6 |
7 |
8 |
9 | ┃┓
10 | ┃┃
11 | ┃┣╸
12 | Model╺┫┛
13 | ┃┓
14 | ┃┃
15 | ┃┣╸x ≥ 0.785
16 | ┃┛
17 |
18 |
19 | Free Variables
20 | --------------
21 | x : 0.7854
22 | y : 0.7071
23 |
24 |
--------------------------------------------------------------------------------
/docs/source/examples/freeing_fixed_variables.py:
--------------------------------------------------------------------------------
1 | "Example of freeing fixed variables"
2 | from gpkit import Variable, Model
3 | x = Variable("x")
4 | y = Variable("y", 3) # fix value to 3
5 | m = Model(x, [x >= 1 + y, y >= 1])
6 | # verbosity is 0 for testing's sake, no need to do that in your code!
7 | sol = m.solve(verbosity=0) # optimal cost is 4; y appears in sol["constants"]
8 |
9 | assert abs(sol["cost"] - 4) <= 1e-4
10 | assert y in sol["constants"]
11 |
12 | del m.substitutions["y"]
13 | sol = m.solve(verbosity=0) # optimal cost is 2; y appears in Free Variables
14 | assert abs(sol["cost"] - 2) <= 1e-4
15 | assert y in sol["freevariables"]
16 |
--------------------------------------------------------------------------------
/docs/source/examples/freeing_fixed_variables_output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/freeing_fixed_variables_output.txt
--------------------------------------------------------------------------------
/docs/source/examples/gettingstarted.py:
--------------------------------------------------------------------------------
1 | "The getting started page"
2 | from gpkit import Variable, VectorVariable, Model
3 | from gpkit.nomials import Monomial, Posynomial, PosynomialInequality
4 |
5 | ### Example Free Variables
6 | # Declare a variable, x
7 | x = Variable("x")
8 |
9 | # Declare a variable, y, with units of meters
10 | y = Variable("y", "m")
11 |
12 | # Declare a variable, z, with units of meters, and a description
13 | z = Variable("z", "m", "A variable called z with units of meters")
14 |
15 | ### Example Fixed Variables 1
16 | rho = Variable("rho", 1.225, "kg/m^3", "Density of air at sea level")
17 |
18 | ### Example Fixed Variables 2
19 | #Declare pi equal to 3.14
20 | pi = Variable("pi", 3.14159, "-", constant=True)
21 |
22 | ### Example Vector Variables
23 | # Declare a 3-element vector variable "x" with units of "m"
24 | x = VectorVariable(3, "x", "m", "Cube corner coordinates")
25 | x_min = VectorVariable(3, "x", [1, 2, 3], "m", "Cube corner minimum")
26 |
27 | ### Example Creating Monomials and Posynomials 1
28 | # create a Monomial term xy^2/z
29 | x = Variable("x")
30 | y = Variable("y")
31 | z = Variable("z")
32 | m = x * y**2 / z
33 | assert isinstance(m, Monomial)
34 |
35 | ### Example Creating Monomials and Posynomials 2
36 | # create a Posynomial expression x + xy^2
37 | x = Variable("x")
38 | y = Variable("y")
39 | p = x + x * y**2
40 | assert isinstance(p, Posynomial)
41 |
42 | ### Example Declaring Constraints
43 | # consider a block with dimensions x, y, z less than 1
44 | # constrain surface area less than 1.0 m^2
45 | x = Variable("x", "m")
46 | y = Variable("y", "m")
47 | z = Variable("z", "m")
48 | S = Variable("S", 1.0, "m^2")
49 | c = (2*x*y + 2*x*z + 2*y*z <= S)
50 | assert isinstance(c, PosynomialInequality)
51 |
52 | ### Example Formulating a Model
53 | x = Variable("x")
54 | y = Variable("y")
55 | z = Variable("z")
56 | S = 200
57 | objective = 1/(x*y*z)
58 | constraints = [2*x*y + 2*x*z + 2*y*z <= S,
59 | x >= 2*y]
60 | m = Model(objective, constraints)
61 |
62 | ### Example Solving the Model
63 | sol = m.solve(verbosity=0)
64 |
65 | ### Printing Results 1
66 | print(sol.table())
67 |
68 | ### Printing Results 2
69 | print("The optimal value is %.4g." % sol["cost"])
70 |
71 | ### Example variable sensitivity usage
72 | x = Variable("x")
73 | x_min = Variable("x_{min}", 2)
74 | sol = Model(x, [x_min <= x]).solve(verbosity=0)
75 | sens_x_min = sol["sensitivities"]["variables"][x_min]
76 |
77 | x = Variable("x")
78 | x_squared_min = Variable("x^2_{min}", 2)
79 | sol = Model(x, [x_squared_min <= x**2]).solve(verbosity=0)
80 | sens_x_min = sol["sensitivities"]["variables"][x_squared_min]
81 |
--------------------------------------------------------------------------------
/docs/source/examples/gettingstarted_output.txt:
--------------------------------------------------------------------------------
1 |
2 | ┃/┓
3 | Cost╺┫ ┃
4 | (0.00551) ┃/┣╸y
5 | ┃/┛ (4.08)
6 |
7 |
8 |
9 | ┃┓
10 | ┃┃
11 | ┃┃
12 | Model╺┫┣╸2·x·y + 2·x·z + 2·y·z ≤ 200
13 | ┃┃
14 | ┃┃
15 | ┃┛
16 | ┃┣╸x ≥ 2·y
17 |
18 |
19 | Free Variables
20 | --------------
21 | x : 8.165
22 | y : 4.082
23 | z : 5.443
24 |
25 | Most Sensitive Constraints
26 | --------------------------
27 | +1.5 : 2·x·y + 2·x·z + 2·y·z ≤ 200
28 | +0.17 : x ≥ 2·y
29 |
30 | The optimal value is 0.005511.
31 |
--------------------------------------------------------------------------------
/docs/source/examples/issue_1513.py:
--------------------------------------------------------------------------------
1 | "Tests non-array linked functions & subs in a vectorization environment"
2 | import numpy as np
3 | from gpkit import Variable, Model, ConstraintSet, Vectorize
4 |
5 | class Vehicle(Model):
6 | "Vehicle model"
7 | def setup(self):
8 | self.a = a = Variable("a")
9 | constraints = [a >= 1]
10 | return constraints
11 |
12 | class System(Model):
13 | "System model"
14 | def setup(self):
15 | with Vectorize(1):
16 | self.Fleet2 = Fleet2()
17 | constraints = [self.Fleet2]
18 | self.cost = sum(self.Fleet2.z)
19 | return constraints
20 |
21 | class Fleet2(Model):
22 | "Fleet model (composed of multiple Vehicles)"
23 | def setup(self):
24 | x = Variable("x")
25 | lambdafun = lambda c: [c[x]-1, np.ones(x.shape)]
26 | with Vectorize(2):
27 | y = Variable("y", lambdafun)
28 | self.Vehicle = Vehicle()
29 |
30 | self.z = z = Variable("z")
31 | substitutions = {"x": 4}
32 | constraints = [
33 | z >= sum(y/x*self.Vehicle.a),
34 | self.Vehicle,
35 | ]
36 | return constraints, substitutions
37 |
38 | m = System()
39 | sol = m.solve(verbosity=0)
40 | print(sol.table())
41 |
42 | # now with more fleets per system
43 | class System2(Model):
44 | "System model"
45 | def setup(self):
46 | with Vectorize(3):
47 | self.Fleet2 = Fleet2()
48 | constraints = [self.Fleet2]
49 | self.cost = sum(self.Fleet2.z)
50 | return constraints
51 |
52 | m = System2()
53 | sol = m.solve(verbosity=0)
54 | print(sol.table())
55 |
56 |
57 | # now testing substitutions
58 |
59 | class Simple(Model):
60 | "Simple model"
61 | def setup(self):
62 | self.x = x = Variable("x")
63 | y = Variable("y", 1)
64 | z = Variable("z", 2)
65 | constraints = [
66 | x >= y + z,
67 | ]
68 | return constraints
69 |
70 | class Cake(Model):
71 | "Cake model"
72 | def setup(self):
73 | with Vectorize(3):
74 | s = Simple()
75 | c = ConstraintSet([s])
76 | self.cost = sum(s.x)
77 | return c
78 |
79 | m = Cake()
80 | m.substitutions.update({
81 | "y": ("sweep", [1, 2, 3]),
82 | "z": lambda v: v("y")**2,
83 | })
84 | sol = m.solve(verbosity=0)
85 | print(sol.table())
86 |
--------------------------------------------------------------------------------
/docs/source/examples/issue_1522.py:
--------------------------------------------------------------------------------
1 | "Tests broadcast_sub function for returned-dictionary substitutions"
2 | from gpkit import Variable, Model, ConstraintSet, Vectorize
3 | from gpkit.small_scripts import broadcast_substitution
4 |
5 | class Pie(Model):
6 | "Pie model"
7 | def setup(self):
8 | self.x = x = Variable("x")
9 | z = Variable("z")
10 | constraints = [
11 | x >= z,
12 | ]
13 | substitutions = {'z': 1}
14 | return constraints, substitutions
15 |
16 | class Cake(Model):
17 | "Cake model, containing a vector of Pies"
18 | def setup(self):
19 | self.y = y = Variable("y")
20 | with Vectorize(2):
21 | s = Pie()
22 | constraints = [y >= s.x]
23 | constraints += [s]
24 | subs = {'x': broadcast_substitution(s.x, [2, 3])}
25 | return constraints, subs
26 |
27 | class Yum1(Model):
28 | "Total dessert system model containing 5 Cakes"
29 | def setup(self):
30 | with Vectorize(5):
31 | cake = Cake()
32 | y = cake.y
33 | self.cost = sum(y)
34 | constraints = ConstraintSet([cake])
35 | return constraints
36 |
37 | m = Yum1()
38 | sol = m.solve(verbosity=0)
39 | print(sol.table())
40 |
41 | class Yum2(Model):
42 | "Total dessert system model containing 1 Cake"
43 | def setup(self):
44 | with Vectorize(1):
45 | cake = Cake()
46 | y = cake.y
47 | self.cost = sum(y)
48 | constraints = ConstraintSet([cake])
49 | return constraints
50 |
51 | m = Yum2()
52 | sol = m.solve(verbosity=0)
53 | print(sol.table())
54 |
--------------------------------------------------------------------------------
/docs/source/examples/issue_1522_output.txt:
--------------------------------------------------------------------------------
1 |
2 | ┃┓ ┓
3 | ┃┃ ┃
4 | ┃┣╸y[0] ┣╸x[1,0]
5 | ┃┛ (3) ┛ (3, fixed)
6 | ┃┓ ┓
7 | ┃┃ ┃
8 | ┃┣╸y[1] ┣╸x[1,1]
9 | ┃┛ (3) ┛ (3, fixed)
10 | ┃┓ ┓
11 | Cost╺┫┃ ┃
12 | (15) ┃┣╸y[2] ┣╸x[1,2]
13 | ┃┛ (3) ┛ (3, fixed)
14 | ┃┓ ┓
15 | ┃┃ ┃
16 | ┃┣╸y[3] ┣╸x[1,3]
17 | ┃┛ (3) ┛ (3, fixed)
18 | ┃┓ ┓
19 | ┃┃ ┃
20 | ┃┣╸y[4] ┣╸x[1,4]
21 | ┃┛ (3) ┛ (3, fixed)
22 |
23 |
24 |
25 | ┃┓ ┓
26 | ┃┃ ┃
27 | ┃┃ ┣╸y[0] ≥ x[1,0]
28 | ┃┃ ┛
29 | ┃┃ ┓
30 | ┃┃ ┃
31 | ┃┃ ┣╸y[1] ≥ x[1,1]
32 | ┃┃ ┛
33 | ┃┃ ┓
34 | Model╺┫┃ ┃
35 | ┃┣╸Cake ┣╸y[2] ≥ x[1,2]
36 | ┃┃ ┛
37 | ┃┃ ┓
38 | ┃┃ ┃
39 | ┃┃ ┣╸y[3] ≥ x[1,3]
40 | ┃┃ ┛
41 | ┃┃ ┓
42 | ┃┃ ┃
43 | ┃┃ ┣╸y[4] ≥ x[1,4]
44 | ┃┛ ┛
45 |
46 |
47 | Free Variables
48 | --------------
49 | | Yum1.Cake
50 | y : [ 3 3 3 3 3 ]
51 |
52 | Fixed Variables
53 | ---------------
54 | | Yum1.Cake.Pie
55 | x : [ 2 2 2 2 2
56 | 3 3 3 3 3 ]
57 | z : [ 1 1 1 1 1
58 | 1 1 1 1 1 ]
59 |
60 | Variable Sensitivities
61 | ----------------------
62 | | Yum1.Cake.Pie
63 | x : [ +7.1e-07 +7.1e-07 +7.1e-07 +7.1e-07 +7.1e-07
64 | +0.2 +0.2 +0.2 +0.2 +0.2 ]
65 |
66 | Most Sensitive Constraints
67 | --------------------------
68 | | Yum1.Cake
69 | +0.2 : y[0] ≥ x[1,0]
70 | +0.2 : y[1] ≥ x[1,1]
71 | +0.2 : y[2] ≥ x[1,2]
72 | +0.2 : y[3] ≥ x[1,3]
73 | +0.2 : y[4] ≥ x[1,4]
74 |
75 |
76 | ┃┓
77 | Cost╺┫┃
78 | (3) ┃┣╸x[1,0]
79 | ┃┛ (3, fixed)
80 |
81 |
82 |
83 | ┃┓
84 | Model╺┫┃
85 | ┃┣╸y[0] ≥ x[1,0]
86 | ┃┛
87 |
88 |
89 | Free Variables
90 | --------------
91 | | Yum2.Cake
92 | y : [ 3 ]
93 |
94 | Fixed Variables
95 | ---------------
96 | | Yum2.Cake.Pie
97 | x : [ 2 3 ]
98 | z : [ 1 1 ]
99 |
100 | Variable Sensitivities
101 | ----------------------
102 | | Yum2.Cake.Pie
103 | x : [ +8.4e-08 +1 ]
104 |
105 | Most Sensitive Constraints
106 | --------------------------
107 | | Yum2.Cake
108 | +1 : y[0] ≥ x[1,0]
109 |
110 |
--------------------------------------------------------------------------------
/docs/source/examples/last_verified.pkl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/last_verified.pkl
--------------------------------------------------------------------------------
/docs/source/examples/last_verified.sol:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/last_verified.sol
--------------------------------------------------------------------------------
/docs/source/examples/loose_constraintsets.py:
--------------------------------------------------------------------------------
1 | "Example Loose ConstraintSet usage"
2 | from gpkit import Variable, Model
3 | from gpkit.constraints.loose import Loose
4 |
5 | Loose.reltol = 1e-4 # set the global tolerance of Loose
6 | x = Variable('x')
7 | x_min = Variable('x_{min}', 1)
8 | m = Model(x, [Loose([x >= 2], senstol=1e-4), # set the specific tolerance
9 | x >= x_min])
10 | m.solve(verbosity=0) # prints warning
11 |
--------------------------------------------------------------------------------
/docs/source/examples/loose_constraintsets_output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/loose_constraintsets_output.txt
--------------------------------------------------------------------------------
/docs/source/examples/migp.py:
--------------------------------------------------------------------------------
1 | "Example choice variable usage"
2 | import numpy as np
3 | from gpkit import Variable, Model
4 |
5 | x = Variable("x", choices=range(1, 4))
6 | num = Variable("numerator", np.linspace(0.5, 7, 11))
7 |
8 | m = Model(x + num/x)
9 | sol = m.solve(verbosity=0)
10 |
11 | print(sol.table())
12 |
--------------------------------------------------------------------------------
/docs/source/examples/migp_output.txt:
--------------------------------------------------------------------------------
1 |
2 | Optimal Cost
3 | ------------
4 | [ 1.41 2.14 2.68 3.13 ... ]
5 |
6 | ~~~~~~~~
7 | WARNINGS
8 | ~~~~~~~~
9 | Freed Choice Variables
10 | ----------------------
11 | This model has the discretized choice variables [x], but since the 'cvxopt' solver doesn't support discretization they were treated as continuous variables.
12 | ~~~~~~~~
13 |
14 | Swept Variables
15 | ---------------
16 | numerator : [ 0.5
17 | 1.15
18 | 1.8
19 | 2.45
20 | 3.1
21 | 3.75
22 | 4.4
23 | 5.05
24 | 5.7
25 | 6.35
26 | 7 ]
27 |
28 | Free Variables
29 | --------------
30 | x : [ 0.707
31 | 1.07
32 | 1.34
33 | 1.57
34 | 1.76
35 | 1.94
36 | 2.1
37 | 2.25
38 | 2.39
39 | 2.52
40 | 2.65 ]
41 |
42 | Variable Sensitivities
43 | ----------------------
44 | numerator : [ +0.5
45 | +0.5
46 | +0.5
47 | +0.5
48 | +0.5
49 | +0.5
50 | +0.5
51 | +0.5
52 | +0.5
53 | +0.5
54 | +0.5 ]
55 |
56 | Most Sensitive Constraints (in last sweep)
57 | ------------------------------------------
58 | (none)
59 |
60 |
--------------------------------------------------------------------------------
/docs/source/examples/model_var_access.py:
--------------------------------------------------------------------------------
1 | "Demo of accessing variables in models"
2 | from gpkit import Model, Variable
3 |
4 |
5 | class Battery(Model):
6 | """A simple battery
7 |
8 | Upper Unbounded
9 | ---------------
10 | m
11 |
12 | Lower Unbounded
13 | ---------------
14 | E
15 |
16 | """
17 | def setup(self):
18 | h = Variable("h", 200, "Wh/kg", "specific energy")
19 | E = self.E = Variable("E", "MJ", "stored energy")
20 | m = self.m = Variable("m", "lb", "battery mass")
21 | return [E <= m*h]
22 |
23 |
24 | class Motor(Model):
25 | """Electric motor
26 |
27 | Upper Unbounded
28 | ---------------
29 | m
30 |
31 | Lower Unbounded
32 | ---------------
33 | Pmax
34 |
35 | """
36 | def setup(self):
37 | m = self.m = Variable("m", "lb", "motor mass")
38 | f = Variable("f", 20, "lb/hp", "mass per unit power")
39 | Pmax = self.Pmax = Variable("P_{max}", "hp", "max output power")
40 | return [m >= f*Pmax]
41 |
42 |
43 | class PowerSystem(Model):
44 | """A battery powering a motor
45 |
46 | Upper Unbounded
47 | ---------------
48 | m
49 |
50 | Lower Unbounded
51 | ---------------
52 | E, Pmax
53 |
54 | """
55 | def setup(self):
56 | battery, motor = Battery(), Motor()
57 | components = [battery, motor]
58 | m = self.m = Variable("m", "lb", "mass")
59 | self.E = battery.E
60 | self.Pmax = motor.Pmax
61 |
62 | return [components,
63 | m >= sum(comp.m for comp in components)]
64 |
65 | PS = PowerSystem()
66 | print("Getting the only var 'E': %s" % PS["E"])
67 | print("The top-level var 'm': %s" % PS.m)
68 | print("All the variables 'm': %s" % PS.variables_byname("m"))
69 |
--------------------------------------------------------------------------------
/docs/source/examples/model_var_access_output.txt:
--------------------------------------------------------------------------------
1 | Getting the only var 'E': PowerSystem.Battery.E [MJ]
2 | The top-level var 'm': PowerSystem.m [lb]
3 | All the variables 'm': [gpkit.Variable(PowerSystem.Battery.m [lb]), gpkit.Variable(PowerSystem.Motor.m [lb]), gpkit.Variable(PowerSystem.m [lb])]
4 |
--------------------------------------------------------------------------------
/docs/source/examples/performance_modeling_output.txt:
--------------------------------------------------------------------------------
1 |
2 | Cost Function
3 | -------------
4 | Wfuel[0]
5 |
6 | Constraints
7 | -----------
8 | Mission
9 | "fuel constraints":
10 | Wfuel[:-1] ≥ Wfuel[1:] + Wburn[:-1]
11 | Wfuel[3] ≥ Wburn[3]
12 |
13 | FlightSegment
14 | AircraftP
15 | Wburn[:] ≥ 0.1·D[:]
16 | Aircraft.W + Wfuel[:] ≤ 0.5·Mission.FlightSegment.FlightState.rho[:]·CL[:]·S·V[:]²
17 | "performance":
18 | WingAero
19 | D[:] ≥ 0.5·Mission.FlightSegment.FlightState.rho[:]·V[:]²·CD[:]·S
20 | Re[:] = Mission.FlightSegment.FlightState.rho[:]·V[:]·c/mu[:]
21 | CD[:] ≥ 0.074/Re[:]^0.2 + CL[:]²/π/A/e[:]
22 |
23 | FlightState
24 | (no constraints)
25 |
26 | Aircraft
27 | Aircraft.W ≥ Fuselage.W + Wing.W
28 | Fuselage
29 | (no constraints)
30 |
31 | Wing
32 | c = (S/A)^0.5
33 | Wing.W ≥ S·Wing.rho
34 |
35 | ┃┓ ┓ ┓ ┓ ┓
36 | ┃┃ ┃ ┃ ┃ ┃
37 | ┃┃ ┃ ┃ ┣╸Wburn[2] ┣╸CD[2]╶⎨
38 | ┃┃ ┃ ┃ ┃ (0.272lbf) ┃ (0.0189)
39 | ┃┃ ┃ ┃ ┛ ┛
40 | ┃┃ ┃ ┣╸Wfuel[2] ┓ ┓
41 | ┃┃ ┃ ┃ (0.544lbf) ┃ ┃
42 | ┃┃ ┣╸Wfuel[1] ┃ ┣╸Wfuel[3] ┣╸CD[3]╶⎨
43 | ┃┃ ┃ (0.817lbf) ┃ ┃ (0.272lbf) ┃ (0.0188)
44 | Cost╺┫┃ ┃ ┛ ┛ ┛
45 | (1.09lbf) ┃┣╸Wfuel[0] ┃ ┓ ┓ ┓
46 | ┃┃ (1.09lbf) ┃ ┃ ┃ ┣╸CL[1]²
47 | ┃┃ ┃ ┣╸Wburn[1] ┣╸CD[1] ┛ (1.01)
48 | ┃┃ ┃ ┃ (0.273lbf) ┃ (0.0189) ┣╸1/Re[1]^0.2
49 | ┃┃ ┛ ┛ ┛ ┛ (0.0772)
50 | ┃┃ ┓ ┓ ┓
51 | ┃┃ ┃ ┃ ┣╸CL[0]²
52 | ┃┃ ┣╸Wburn[0] ┣╸CD[0] ┛ (1.01)
53 | ┃┃ ┃ (0.274lbf) ┃ (0.019) ┣╸1/Re[0]^0.2
54 | ┃┛ ┛ ┛ ┛ (0.0772)
55 |
56 |
57 |
58 | ┃┓ ┓ ┓
59 | ┃┃ ┃ ┃
60 | ┃┃ ┃ ┃
61 | ┃┃ ┃ ┃
62 | ┃┃ ┣╸FlightSegment ┣╸AircraftP╶⎨
63 | ┃┃ ┃ ┃
64 | ┃┣╸Mission ┃ ┃
65 | ┃┃ ┃ ┃
66 | ┃┃ ┛ ┛
67 | Model╺┫┃ ┣╸Wfuel[0] ≥ Wfuel[1] + Wburn[0]
68 | ┃┃ ┛
69 | ┃┃ ┣╸Wfuel[1] ≥ Wfuel[2] + Wburn[1]
70 | ┃┛ ┣╸Wfuel[2] ≥ Wfuel[3] + Wburn[2]
71 | ┃┓ ┓
72 | ┃┃ ┣╸Wing╶⎨
73 | ┃┃ ┛
74 | ┃┣╸Aircraft ┣╸W ≥ Fuselage.W + Wing.W
75 | ┃┃ ┛
76 | ┃┃ ┣╸Fuselage ┣╸W = 100lbf
77 | ┃┛ ┛ ┛
78 |
79 |
80 | Free Variables
81 | --------------
82 | | Aircraft
83 | W : 144.1 [lbf] weight
84 |
85 | | Aircraft.Wing
86 | S : 44.14 [ft²] surface area
87 | W : 44.14 [lbf] weight
88 | c : 1.279 [ft] mean chord
89 |
90 | | Mission.FlightSegment.AircraftP
91 | Wburn : [ 0.274 0.273 0.272 0.272 ] [lbf] segment fuel burn
92 | Wfuel : [ 1.09 0.817 0.544 0.272 ] [lbf] fuel weight
93 |
94 | | Mission.FlightSegment.AircraftP.WingAero
95 | D : [ 2.74 2.73 2.72 2.72 ] [lbf] drag force
96 |
97 | Insensitive Constraints |below +1e-05|
98 | --------------------------------------
99 | (none)
100 |
101 | Solution Diff (for selected variables)
102 | ======================================
103 | (argument is the baseline solution)
104 |
105 | Constraint Differences
106 | **********************
107 | @@ -31,3 +31,4 @@
108 | Wing
109 | c = (S/A)^0.5
110 | Wing.W ≥ S·Wing.rho
111 | + Wburn[:] ≥ 0.2·D[:]
112 |
113 | **********************
114 |
115 | Relative Differences |above 1%|
116 | -------------------------------
117 | Wburn : [ +102.1% +101.6% +101.1% +100.5% ] segment fuel burn
118 | Wfuel : [ +101.3% +101.1% +100.8% +100.5% ] fuel weight
119 | D : [ +1.1% - - - ] drag force
120 |
121 |
--------------------------------------------------------------------------------
/docs/source/examples/plot_autosweep1d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/plot_autosweep1d.png
--------------------------------------------------------------------------------
/docs/source/examples/plot_sweep1d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/plot_sweep1d.png
--------------------------------------------------------------------------------
/docs/source/examples/plot_sweep1d.py:
--------------------------------------------------------------------------------
1 | "Demonstrates manual and auto sweeping and plotting"
2 | import matplotlib as mpl
3 | mpl.use('Agg')
4 | # comment out the lines above to show figures in a window
5 | import numpy as np
6 | from gpkit import Model, Variable, units
7 | from gpkit.constraints.tight import Tight
8 |
9 | x = Variable("x", "m", "Swept Variable")
10 | y = Variable("y", "m^2", "Cost")
11 | m = Model(y, [
12 | y >= (x/2)**-0.5 * units.m**2.5 + 1*units.m**2,
13 | Tight([y >= (x/2)**2])
14 | ])
15 |
16 | # arguments are: model, swept: values, posnomial for y-axis
17 | sol = m.sweep({x: np.linspace(1, 3, 20)}, verbosity=0)
18 | f, ax = sol.plot(y)
19 | ax.set_title("Manually swept (20 points)")
20 | f.show()
21 | f.savefig("plot_sweep1d.png")
22 | sol.save()
23 |
24 | # arguments are: model, swept: (min, max, optional logtol), posnomial for y-axis
25 | sol = m.autosweep({x: (1, 3)}, tol=0.001, verbosity=0)
26 | f, ax = sol.plot(y)
27 | ax.set_title("Autoswept (7 points)\nGuaranteed to be in blue region")
28 | f.show()
29 | f.savefig("plot_autosweep1d.png")
30 |
--------------------------------------------------------------------------------
/docs/source/examples/plot_sweep1d_output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/plot_sweep1d_output.txt
--------------------------------------------------------------------------------
/docs/source/examples/primal_infeasible_ex1.py:
--------------------------------------------------------------------------------
1 | "A simple primal infeasible example"
2 | from gpkit import Variable, Model
3 |
4 | x = Variable("x")
5 | y = Variable("y")
6 |
7 | m = Model(x*y, [
8 | x >= 1,
9 | y >= 2,
10 | x*y >= 0.5,
11 | x*y <= 1.5
12 | ])
13 |
14 | # raises UnknownInfeasible on cvxopt, PrimalInfeasible on mosek
15 | # m.solve()
16 |
--------------------------------------------------------------------------------
/docs/source/examples/primal_infeasible_ex1_output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/primal_infeasible_ex1_output.txt
--------------------------------------------------------------------------------
/docs/source/examples/primal_infeasible_ex2.py:
--------------------------------------------------------------------------------
1 | "Another simple primal infeasible example"
2 | from gpkit import Variable, Model
3 |
4 | x = Variable("x")
5 | y = Variable("y", 2)
6 |
7 | constraints = [
8 | x >= 1,
9 | 0.5 <= x*y,
10 | x*y <= 1.5
11 | ]
12 |
13 | objective = x*y
14 | m = Model(objective, constraints)
15 |
16 | # raises UnknownInfeasible on cvxopt and PrimalInfeasible on mosek
17 | # m.solve()
18 |
--------------------------------------------------------------------------------
/docs/source/examples/primal_infeasible_ex2_output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/primal_infeasible_ex2_output.txt
--------------------------------------------------------------------------------
/docs/source/examples/relaxation.py:
--------------------------------------------------------------------------------
1 | "Relaxation examples"
2 |
3 | from gpkit import Variable, Model
4 |
5 | x = Variable("x")
6 | x_min = Variable("x_min", 2)
7 | x_max = Variable("x_max", 1)
8 | m = Model(x, [x <= x_max, x >= x_min])
9 | print("Original model")
10 | print("==============")
11 | print(m)
12 | print("")
13 | # m.solve() # raises a RuntimeWarning!
14 |
15 | print("With constraints relaxed equally")
16 | print("================================")
17 |
18 | from gpkit.constraints.relax import ConstraintsRelaxedEqually
19 |
20 | allrelaxed = ConstraintsRelaxedEqually(m)
21 | mr1 = Model(allrelaxed.relaxvar, allrelaxed)
22 | print(mr1)
23 | print(mr1.solve(verbosity=0).table()) # solves with an x of 1.414
24 | from gpkit.breakdowns import Breakdowns
25 | Breakdowns(mr1.solution).trace("cost")
26 | print("")
27 |
28 | print("With constraints relaxed individually")
29 | print("=====================================")
30 |
31 | from gpkit.constraints.relax import ConstraintsRelaxed
32 |
33 | constraintsrelaxed = ConstraintsRelaxed(m)
34 | mr2 = Model(constraintsrelaxed.relaxvars.prod() * m.cost**0.01,
35 | # add a bit of the original cost in
36 | constraintsrelaxed)
37 | print(mr2)
38 | print(mr2.solve(verbosity=0).table()) # solves with an x of 1.0
39 | print("")
40 |
41 | print("With constants relaxed individually")
42 | print("===================================")
43 |
44 | from gpkit.constraints.relax import ConstantsRelaxed
45 |
46 | constantsrelaxed = ConstantsRelaxed(m)
47 | mr3 = Model(constantsrelaxed.relaxvars.prod() * m.cost**0.01,
48 | # add a bit of the original cost in
49 | constantsrelaxed)
50 | print(mr3)
51 | print(mr3.solve(verbosity=0).table()) # brings x_min down to 1.0
52 | print("")
53 |
--------------------------------------------------------------------------------
/docs/source/examples/simple_box.py:
--------------------------------------------------------------------------------
1 | "Maximizes box volume given area and aspect ratio constraints."
2 | from gpkit import Variable, Model
3 |
4 | # Parameters
5 | alpha = Variable("alpha", 2, "-", "lower limit, wall aspect ratio")
6 | beta = Variable("beta", 10, "-", "upper limit, wall aspect ratio")
7 | gamma = Variable("gamma", 2, "-", "lower limit, floor aspect ratio")
8 | delta = Variable("delta", 10, "-", "upper limit, floor aspect ratio")
9 | A_wall = Variable("A_{wall}", 200, "m^2", "upper limit, wall area")
10 | A_floor = Variable("A_{floor}", 50, "m^2", "upper limit, floor area")
11 |
12 | # Decision variables
13 | h = Variable("h", "m", "height")
14 | w = Variable("w", "m", "width")
15 | d = Variable("d", "m", "depth")
16 |
17 | # Constraints
18 | constraints = [A_wall >= 2*h*w + 2*h*d,
19 | A_floor >= w*d,
20 | h/w >= alpha,
21 | h/w <= beta,
22 | d/w >= gamma,
23 | d/w <= delta]
24 |
25 | # Objective function
26 | V = h*w*d
27 | objective = 1/V # To maximize V, we minimize its reciprocal
28 |
29 | # Formulate the Model
30 | m = Model(objective, constraints)
31 |
32 | # Solve the Model and print the results table
33 | print(m.solve(verbosity=0).table())
34 |
--------------------------------------------------------------------------------
/docs/source/examples/simple_box_output.txt:
--------------------------------------------------------------------------------
1 |
2 | ┃/┓
3 | Cost╺┫ ┃
4 | (0.00367/m³) ┃/┣╸alpha
5 | ┃/┛ (2, fixed)
6 |
7 |
8 |
9 | ┃┓
10 | ┃┃
11 | ┃┃
12 | ┃┣╸A_{wall} = 200m²
13 | ┃┃
14 | ┃┛
15 | ┃┓
16 | Model╺┫┃
17 | ┃┃
18 | ┃┣╸A_{wall} ≥ 2·h·w + 2·h·d
19 | ┃┃
20 | ┃┛
21 | ┃┣╸alpha = 2
22 | ┃┛
23 | ┃┣╸alpha ≤ h/w
24 | ┃┛
25 |
26 |
27 | Free Variables
28 | --------------
29 | d : 8.17 [m] depth
30 | h : 8.163 [m] height
31 | w : 4.081 [m] width
32 |
33 | Fixed Variables
34 | ---------------
35 | A_{floor} : 50 [m²] upper limit, floor area
36 | A_{wall} : 200 [m²] upper limit, wall area
37 | alpha : 2 lower limit, wall aspect ratio
38 | beta : 10 upper limit, wall aspect ratio
39 | delta : 10 upper limit, floor aspect ratio
40 | gamma : 2 lower limit, floor aspect ratio
41 |
42 | Variable Sensitivities
43 | ----------------------
44 | A_{wall} : -1.5 upper limit, wall area
45 | alpha : +0.5 lower limit, wall aspect ratio
46 |
47 | Most Sensitive Constraints
48 | --------------------------
49 | +1.5 : A_{wall} ≥ 2·h·w + 2·h·d
50 | +0.5 : alpha ≤ h/w
51 |
52 |
--------------------------------------------------------------------------------
/docs/source/examples/simple_sp.py:
--------------------------------------------------------------------------------
1 | """Adapted from t_SP in tests/t_geometric_program.py"""
2 | from gpkit import Model, Variable, SignomialsEnabled
3 |
4 | # Decision variables
5 | x = Variable('x')
6 | y = Variable('y')
7 |
8 | # must enable signomials for subtraction
9 | with SignomialsEnabled():
10 | constraints = [x >= 1-y, y <= 0.1]
11 |
12 | # create and solve the SP
13 | m = Model(x, constraints)
14 | print(m.localsolve(verbosity=0).summary())
15 | assert abs(m.solution(x) - 0.9) < 1e-6
16 |
17 | # full interim solutions are available
18 | print("x values of each GP solve (note convergence)")
19 | print(", ".join("%.5f" % sol["freevariables"][x] for sol in m.program.results))
20 |
21 | # use x0 to give the solution, reducing number of GPs needed
22 | m.localsolve(verbosity=0, x0={x: 0.9, y:0.1})
23 | assert len(m.program.results) == 2
24 |
--------------------------------------------------------------------------------
/docs/source/examples/simple_sp_output.txt:
--------------------------------------------------------------------------------
1 |
2 | ┃┓
3 | Cost╺┫┃
4 | (0.9) ┃┣╸1/y^0.1
5 | ┃┛ (1.26)
6 |
7 |
8 |
9 | ┃┓
10 | ┃┃
11 | ┃┃
12 | Model╺┫┣╸1 - y ≤ x
13 | ┃┃
14 | ┃┃
15 | ┃┛
16 | ┃┣╸y ≤ 0.1
17 |
18 |
19 | Free Variables
20 | --------------
21 | x : 0.9
22 | y : 0.1
23 |
24 | x values of each GP solve (note convergence)
25 | 2.50000, 0.92548, 0.90003, 0.90000
26 |
--------------------------------------------------------------------------------
/docs/source/examples/simpleflight.py:
--------------------------------------------------------------------------------
1 | "Minimizes airplane drag for a simple drag and structure model."
2 | import pickle
3 | import numpy as np
4 | from gpkit import Variable, Model, SolutionArray
5 | pi = np.pi
6 |
7 |
8 | # Constants
9 | k = Variable("k", 1.2, "-", "form factor")
10 | e = Variable("e", 0.95, "-", "Oswald efficiency factor")
11 | mu = Variable("\\mu", 1.78e-5, "kg/m/s", "viscosity of air")
12 | rho = Variable("\\rho", 1.23, "kg/m^3", "density of air")
13 | tau = Variable("\\tau", 0.12, "-", "airfoil thickness to chord ratio")
14 | N_ult = Variable("N_{ult}", 3.8, "-", "ultimate load factor")
15 | V_min = Variable("V_{min}", 22, "m/s", "takeoff speed")
16 | C_Lmax = Variable("C_{L,max}", 1.5, "-", "max CL with flaps down")
17 | S_wetratio = Variable("(\\frac{S}{S_{wet}})", 2.05, "-", "wetted area ratio")
18 | W_W_coeff1 = Variable("W_{W_{coeff1}}", 8.71e-5, "1/m",
19 | "Wing Weight Coefficent 1")
20 | W_W_coeff2 = Variable("W_{W_{coeff2}}", 45.24, "Pa",
21 | "Wing Weight Coefficent 2")
22 | CDA0 = Variable("(CDA0)", 0.031, "m^2", "fuselage drag area")
23 | W_0 = Variable("W_0", 4940.0, "N", "aircraft weight excluding wing")
24 |
25 | # Free Variables
26 | D = Variable("D", "N", "total drag force")
27 | A = Variable("A", "-", "aspect ratio")
28 | S = Variable("S", "m^2", "total wing area")
29 | V = Variable("V", "m/s", "cruising speed")
30 | W = Variable("W", "N", "total aircraft weight")
31 | Re = Variable("Re", "-", "Reynold's number")
32 | C_D = Variable("C_D", "-", "Drag coefficient of wing")
33 | C_L = Variable("C_L", "-", "Lift coefficent of wing")
34 | C_f = Variable("C_f", "-", "skin friction coefficient")
35 | W_w = Variable("W_w", "N", "wing weight")
36 |
37 | constraints = []
38 |
39 | # Drag model
40 | C_D_fuse = CDA0/S
41 | C_D_wpar = k*C_f*S_wetratio
42 | C_D_ind = C_L**2/(pi*A*e)
43 | constraints += [C_D >= C_D_fuse + C_D_wpar + C_D_ind]
44 |
45 | # Wing weight model
46 | W_w_strc = W_W_coeff1*(N_ult*A**1.5*(W_0*W*S)**0.5)/tau
47 | W_w_surf = W_W_coeff2 * S
48 | constraints += [W_w >= W_w_surf + W_w_strc]
49 |
50 | # and the rest of the models
51 | constraints += [D >= 0.5*rho*S*C_D*V**2,
52 | Re <= (rho/mu)*V*(S/A)**0.5,
53 | C_f >= 0.074/Re**0.2,
54 | W <= 0.5*rho*S*C_L*V**2,
55 | W <= 0.5*rho*S*C_Lmax*V_min**2,
56 | W >= W_0 + W_w]
57 |
58 | print("SINGLE\n======")
59 | m = Model(D, constraints)
60 | sol = m.solve(verbosity=0)
61 | print(sol.summary())
62 | # save solution to a file and retrieve it
63 | sol.save("solution.pkl")
64 | sol.save_compressed("solution.pgz")
65 | print(sol.diff("solution.pkl"))
66 |
67 | print("SWEEP\n=====")
68 | N = 2
69 | sweeps = {V_min: ("sweep", np.linspace(20, 25, N)),
70 | V: ("sweep", np.linspace(45, 55, N)), }
71 | m.substitutions.update(sweeps)
72 | sweepsol = m.solve(verbosity=0)
73 | print(sweepsol.summary())
74 | sol_loaded = pickle.load(open("solution.pkl", "rb"))
75 | assert sol_loaded.almost_equal(SolutionArray.decompress_file("solution.pgz"))
76 | print(sweepsol.diff(sol_loaded, absdiff=True, senssdiff=True))
77 |
--------------------------------------------------------------------------------
/docs/source/examples/sin_approx_example.py:
--------------------------------------------------------------------------------
1 | "Can be found in gpkit/docs/source/examples/sin_approx_example.py"
2 | import numpy as np
3 | from gpkit import Variable, Model
4 |
5 |
6 | x = Variable("x")
7 | y = Variable("y")
8 |
9 | objective = y
10 |
11 | constraints = [y >= x,
12 | x <= np.pi/2,
13 | x >= np.pi/4,
14 | ]
15 |
16 | m = Model(objective, constraints)
17 | print(m.solve(verbosity=0).summary())
18 |
--------------------------------------------------------------------------------
/docs/source/examples/sin_approx_example_output.txt:
--------------------------------------------------------------------------------
1 |
2 | ┃┓
3 | Cost╺┫┃
4 | (0.785) ┃┣╸0.785
5 | ┃┛
6 |
7 |
8 |
9 | ┃┓
10 | ┃┃
11 | ┃┣╸x ≥ 0.785
12 | Model╺┫┛
13 | ┃┓
14 | ┃┃
15 | ┃┣╸y ≥ x
16 | ┃┛
17 |
18 |
19 | Free Variables
20 | --------------
21 | x : 0.7854
22 | y : 0.7854
23 |
24 |
--------------------------------------------------------------------------------
/docs/source/examples/solar.p:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/solar.p
--------------------------------------------------------------------------------
/docs/source/examples/solar_10.p:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/solar_10.p
--------------------------------------------------------------------------------
/docs/source/examples/solar_12.p:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/solar_12.p
--------------------------------------------------------------------------------
/docs/source/examples/solar_13.p:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/solar_13.p
--------------------------------------------------------------------------------
/docs/source/examples/sp_to_gp_sweep.py:
--------------------------------------------------------------------------------
1 | "example of an SP that turns into a GP"
2 | import numpy as np
3 | from gpkit import Model, Variable, SignomialsEnabled, units
4 | from gpkit.constraints.tight import Tight
5 |
6 |
7 | def SimPleAC():
8 | "Creates SimpleAC model"
9 | # Env. constants
10 | g = Variable("g", 9.81, "m/s^2", "gravitational acceleration")
11 | mu = Variable("\\mu", 1.775e-5, "kg/m/s", "viscosity of air")
12 | rho = Variable("\\rho", 1.23, "kg/m^3", "density of air")
13 | rho_f = Variable("\\rho_f", 817, "kg/m^3", "density of fuel")
14 |
15 | # Non-dimensional constants
16 | C_Lmax = Variable("C_{L,max}", 1.6, "-", "max CL with flaps down")
17 | e = Variable("e", 0.92, "-", "Oswald efficiency factor")
18 | k = Variable("k", 1.17, "-", "form factor")
19 | N_ult = Variable("N_{ult}", 3.3, "-", "ultimate load factor")
20 | S_wetratio = Variable("(\\frac{S}{S_{wet}})", 2.075, "-",
21 | "wetted area ratio")
22 | tau = Variable("\\tau", 0.12, "-", "airfoil thickness to chord ratio")
23 | W_W_coeff1 = Variable("W_{W_{coeff1}}", 2e-5, "1/m",
24 | "wing weight coefficent 1") # 12e-5 originally
25 | W_W_coeff2 = Variable("W_{W_{coeff2}}", 60, "Pa",
26 | "wing weight coefficent 2")
27 |
28 | # Dimensional constants
29 | Range = Variable("Range", 3000, "km", "aircraft range")
30 | TSFC = Variable("TSFC", 0.6, "1/hr", "thrust specific fuel consumption")
31 | V_min = Variable("V_{min}", 25, "m/s", "takeoff speed")
32 | W_0 = Variable("W_0", 6250, "N", "aircraft weight excluding wing")
33 |
34 | # Free Variables
35 | LoD = Variable("L/D", "-", "lift-to-drag ratio")
36 | D = Variable("D", "N", "total drag force")
37 | V = Variable("V", "m/s", "cruising speed")
38 | W = Variable("W", "N", "total aircraft weight")
39 | Re = Variable("Re", "-", "Reynold's number")
40 | CDA0 = Variable("(CDA0)", "m^2", "fuselage drag area") # 0.035 originally
41 | C_D = Variable("C_D", "-", "drag coefficient")
42 | C_L = Variable("C_L", "-", "lift coefficient of wing")
43 | C_f = Variable("C_f", "-", "skin friction coefficient")
44 | W_f = Variable("W_f", "N", "fuel weight")
45 | V_f = Variable("V_f", "m^3", "fuel volume")
46 | V_f_avail = Variable("V_{f_{avail}}", "m^3", "fuel volume available")
47 | T_flight = Variable("T_{flight}", "hr", "flight time")
48 |
49 | # Free variables (fixed for performance eval.)
50 | A = Variable("A", "-", "aspect ratio")
51 | S = Variable("S", "m^2", "total wing area")
52 | W_w = Variable("W_w", "N", "wing weight")
53 | W_w_strc = Variable("W_w_strc", "N", "wing structural weight")
54 | W_w_surf = Variable("W_w_surf", "N", "wing skin weight")
55 | V_f_wing = Variable("V_f_wing", "m^3", "fuel volume in the wing")
56 | V_f_fuse = Variable("V_f_fuse", "m^3", "fuel volume in the fuselage")
57 |
58 | objective = W_f
59 |
60 | constraints = []
61 |
62 | # Weight and lift model
63 | constraints += [
64 | W >= W_0 + W_w + W_f,
65 | W_0 + W_w + 0.5 * W_f <= 0.5 * rho * S * C_L * V ** 2,
66 | W <= 0.5 * rho * S * C_Lmax * V_min ** 2,
67 | T_flight >= Range / V,
68 | LoD == C_L/C_D]
69 |
70 | # Thrust and drag model
71 | C_D_fuse = CDA0 / S
72 | C_D_wpar = k * C_f * S_wetratio
73 | C_D_ind = C_L ** 2 / (np.pi * A * e)
74 | constraints += [
75 | W_f >= TSFC * T_flight * D,
76 | D >= 0.5 * rho * S * C_D * V ** 2,
77 | C_D >= C_D_fuse + C_D_wpar + C_D_ind,
78 | V_f_fuse <= 10*units("m")*CDA0,
79 | Re <= (rho / mu) * V * (S / A) ** 0.5,
80 | C_f >= 0.074 / Re ** 0.2]
81 |
82 | # Fuel volume model
83 | with SignomialsEnabled():
84 | constraints += [
85 | V_f == W_f / g / rho_f,
86 | # linear with b and tau, quadratic with chord
87 | V_f_wing**2 <= 0.0009*S**3/A*tau**2,
88 | V_f_avail <= V_f_wing + V_f_fuse, # [SP]
89 | Tight([V_f_avail >= V_f])]
90 |
91 | # Wing weight model
92 | constraints += [
93 | W_w_surf >= W_W_coeff2 * S,
94 | W_w_strc**2 >= W_W_coeff1**2/tau**2 * N_ult**2*A**3*(V_f_fuse*g*rho_f
95 | + W_0)*W*S,
96 | W_w >= W_w_surf + W_w_strc]
97 |
98 | m = Model(objective, constraints)
99 |
100 | return m
101 |
102 |
103 | sa = SimPleAC()
104 | sa.substitutions.update({"V_f_wing": ("sweep", np.linspace(0.1, 0.5, 3)),
105 | "V_f_fuse": 0.5})
106 | sol = sa.solve(verbosity=0)
107 | print(sol.summary())
108 |
--------------------------------------------------------------------------------
/docs/source/examples/sp_to_gp_sweep_output.txt:
--------------------------------------------------------------------------------
1 |
2 | Optimal Cost
3 | ------------
4 | [ 4.63e+03 6.23e+03 7.36e+03 ]
5 |
6 | ~~~~~~~~
7 | WARNINGS
8 | ~~~~~~~~
9 | Unexpectedly Loose Constraints in sweep 0
10 | -----------------------------------------
11 | 0.5886 >= 0.5775 : V_{f_{avail}} ≥ V_f
12 |
13 | Unexpectedly Loose Constraints in sweep 1
14 | -----------------------------------------
15 | 0.7884 >= 0.7769 : V_{f_{avail}} ≥ V_f
16 |
17 | Unexpectedly Loose Constraints in sweep 2
18 | -----------------------------------------
19 | 0.9585 >= 0.9187 : V_{f_{avail}} ≥ V_f
20 | ~~~~~~~~
21 |
22 | Swept Variables
23 | ---------------
24 | V_f_wing : [ 0.1 0.3 0.5 ] [m³] fuel volume in the wing
25 |
26 | Free Variables
27 | --------------
28 | (CDA0) : [ 0.05 0.05 0.05 ] [m²] fuselage drag area
29 | A : [ 12.4 3.78 2.35 ] aspect ratio
30 | C_D : [ 0.0136 0.011 0.0099 ] drag coefficient
31 | C_L : [ 0.327 0.162 0.121 ] lift coefficient of wing
32 | C_f : [ 0.00343 0.00284 0.00261 ] skin friction coefficient
33 | D : [ 466 774 1e+03 ] [N] total drag force
34 | L/D : [ 24.1 14.8 12.2 ] lift-to-drag ratio
35 | Re : [ 4.64e+06 1.21e+07 1.83e+07 ] Reynold's number
36 | S : [ 22 29.7 35.6 ] [m²] total wing area
37 | T_{flight} : [ 16.6 13.4 12.3 ] [hr] flight time
38 | V : [ 50.3 62.1 67.9 ] [m/s] cruising speed
39 | V_f : [ 0.577 0.777 0.919 ] [m³] fuel volume
40 | V_{f_{avail}} : [ 0.589 0.788 0.958 ] [m³] fuel volume available
41 | W : [ 1.35e+04 1.45e+04 1.59e+04 ] [N] total aircraft weight
42 | W_f : [ 4.63e+03 6.23e+03 7.36e+03 ] [N] fuel weight
43 | W_w : [ 2.65e+03 2.05e+03 2.29e+03 ] [N] wing weight
44 | W_w_strc : [ 1.33e+03 269 151 ] [N] wing structural weight
45 | W_w_surf : [ 1.32e+03 1.78e+03 2.14e+03 ] [N] wing skin weight
46 |
47 |
--------------------------------------------------------------------------------
/docs/source/examples/sub_multi_values.py:
--------------------------------------------------------------------------------
1 | "Example substitution; adapted from t_sub.py/t_NomialSubs/test_Vector"
2 | from gpkit import Variable, VectorVariable
3 | x = Variable("x")
4 | y = Variable("y")
5 | z = VectorVariable(2, "z")
6 | p = x*y*z
7 | assert all(p.sub({x: 1, "y": 2}) == 2*z)
8 | assert all(p.sub({x: 1, y: 2, "z": [1, 2]}) == z.sub({z: [2, 4]}))
9 |
--------------------------------------------------------------------------------
/docs/source/examples/sub_multi_values_output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/sub_multi_values_output.txt
--------------------------------------------------------------------------------
/docs/source/examples/substitutions.py:
--------------------------------------------------------------------------------
1 | "Example substitution; adapted from t_sub.py/t_NomialSubs /test_Basic"
2 | from gpkit import Variable
3 | x = Variable("x")
4 | p = x**2
5 | assert p.sub({x: 3}) == 9
6 | assert p.sub({x.key: 3}) == 9
7 | assert p.sub({"x": 3}) == 9
8 |
--------------------------------------------------------------------------------
/docs/source/examples/substitutions_output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/substitutions_output.txt
--------------------------------------------------------------------------------
/docs/source/examples/tight_constraintsets.py:
--------------------------------------------------------------------------------
1 | "Example Tight ConstraintSet usage"
2 | from gpkit import Variable, Model
3 | from gpkit.constraints.tight import Tight
4 |
5 | Tight.reltol = 1e-2 # set the global tolerance of Tight
6 | x = Variable('x')
7 | x_min = Variable('x_{min}', 2)
8 | m = Model(x, [Tight([x >= 1], reltol=1e-3), # set the specific tolerance
9 | x >= x_min])
10 | m.solve(verbosity=0) # prints warning
11 |
--------------------------------------------------------------------------------
/docs/source/examples/tight_constraintsets_output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/tight_constraintsets_output.txt
--------------------------------------------------------------------------------
/docs/source/examples/treemap.py:
--------------------------------------------------------------------------------
1 | "Treemap example"
2 | import plotly # pylint: disable=unused-import
3 | from gpkit.interactive.plotting import treemap
4 | from performance_modeling import M
5 |
6 | fig = treemap(M)
7 | # plotly.offline.plot(fig, filename="treemap.html") # uncomment to show
8 |
9 | fig = treemap(M, itemize="constraints", sizebycount=True)
10 | # plotly.offline.plot(fig, filename="sizedtreemap.html") # uncomment to show
11 |
--------------------------------------------------------------------------------
/docs/source/examples/treemap_output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/treemap_output.txt
--------------------------------------------------------------------------------
/docs/source/examples/unbounded.py:
--------------------------------------------------------------------------------
1 | "Demonstrate a trivial unbounded variable"
2 | from gpkit import Variable, Model
3 | from gpkit.constraints.bounded import Bounded
4 |
5 | x = Variable("x")
6 |
7 | constraints = [x >= 1]
8 |
9 | m = Model(1/x, constraints) # MOSEK returns DUAL_INFEAS_CER on .solve()
10 | m = Model(1/x, Bounded(constraints))
11 | # by default, prints bounds warning during solve
12 | sol = m.solve(verbosity=0)
13 | print(sol.summary())
14 | # but they can also be accessed from the solution:
15 | assert (sol["boundedness"]["value near upper bound of 1e+30"]
16 | == sol["boundedness"]["sensitive to upper bound of 1e+30"])
17 |
--------------------------------------------------------------------------------
/docs/source/examples/unbounded_output.txt:
--------------------------------------------------------------------------------
1 |
2 | ┃┓
3 | Cost╺┫┃
4 | (1e-30) ┃┣╸1/x
5 | ┃┛ (1e-30)
6 |
7 |
8 |
9 | ┃┓
10 | Model╺┫┃
11 | ┃┣╸x ≤ 1e+30
12 | ┃┛
13 |
14 |
15 | ~~~~~~~~
16 | WARNINGS
17 | ~~~~~~~~
18 | Arbitrarily Bounded Variables
19 | -----------------------------
20 | value near upper bound of 1e+30: x
21 | sensitive to upper bound of 1e+30: x
22 | ~~~~~~~~
23 |
24 | Free Variables
25 | --------------
26 | x : 1e+30
27 |
28 |
--------------------------------------------------------------------------------
/docs/source/examples/vectorization.py:
--------------------------------------------------------------------------------
1 | "Example Vectorize usage, from gpkit/tests/t_vars.py"
2 | from gpkit import Variable, Vectorize, VectorVariable
3 |
4 | with Vectorize(3):
5 | with Vectorize(5):
6 | y = Variable("y")
7 | x = VectorVariable(2, "x")
8 | z = VectorVariable(7, "z")
9 |
10 | assert(y.shape == (5, 3))
11 | assert(x.shape == (2, 5, 3))
12 | assert(z.shape == (7, 3))
13 |
--------------------------------------------------------------------------------
/docs/source/examples/vectorization_output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/examples/vectorization_output.txt
--------------------------------------------------------------------------------
/docs/source/examples/vectorize.py:
--------------------------------------------------------------------------------
1 | "Vectorization demonstration"
2 | from gpkit import Model, Variable, Vectorize
3 |
4 | class Test(Model):
5 | """A simple scalar model
6 |
7 | Upper Unbounded
8 | ---------------
9 | x
10 | """
11 | def setup(self):
12 | x = self.x = Variable("x")
13 | return [x >= 1]
14 |
15 | print("SCALAR")
16 | m = Test()
17 | m.cost = m["x"]
18 | print(m.solve(verbosity=0).summary())
19 |
20 | print("__________\n")
21 | print("VECTORIZED")
22 | with Vectorize(3):
23 | m = Test()
24 | m.cost = m["x"].prod()
25 | m.append(m["x"][1] >= 2)
26 | print(m.solve(verbosity=0).summary())
27 |
--------------------------------------------------------------------------------
/docs/source/examples/vectorize_output.txt:
--------------------------------------------------------------------------------
1 | SCALAR
2 |
3 | ┃┓
4 | Cost╺┫┃
5 | (1) ┃┣╸1
6 | ┃┛
7 |
8 |
9 |
10 | ┃┓
11 | Model╺┫┃
12 | ┃┣╸x ≥ 1
13 | ┃┛
14 |
15 |
16 | Free Variables
17 | --------------
18 | x : 1
19 |
20 | __________
21 |
22 | VECTORIZED
23 |
24 | ┃┓
25 | Cost╺┫┃
26 | (2) ┃┣╸2
27 | ┃┛
28 |
29 |
30 |
31 | ┃┓ ┓
32 | ┃┃ ┃
33 | ┃┃ ┣╸x[0] ≥ 1
34 | ┃┃ ┛
35 | ┃┣╸Test1 ┓
36 | Model╺┫┃ ┃
37 | ┃┃ ┣╸x[2] ≥ 1
38 | ┃┛ ┛
39 | ┃┓
40 | ┃┃
41 | ┃┣╸x[1] ≥ 2
42 | ┃┛
43 |
44 |
45 | Free Variables
46 | --------------
47 | x : [ 1 2 1 ]
48 |
49 |
--------------------------------------------------------------------------------
/docs/source/examples/water_tank.py:
--------------------------------------------------------------------------------
1 | "Minimizes cylindrical tank surface area for a particular volume."
2 | from gpkit import Variable, VectorVariable, Model
3 |
4 | M = Variable("M", 100, "kg", "Mass of Water in the Tank")
5 | rho = Variable("\\rho", 1000, "kg/m^3", "Density of Water in the Tank")
6 | A = Variable("A", "m^2", "Surface Area of the Tank")
7 | V = Variable("V", "m^3", "Volume of the Tank")
8 | d = VectorVariable(3, "d", "m", "Dimension Vector")
9 |
10 | # because its units are incorrect the line below will print a warning
11 | bad_monomial_equality = (M == V)
12 |
13 | constraints = (A >= 2*(d[0]*d[1] + d[0]*d[2] + d[1]*d[2]),
14 | V == d[0]*d[1]*d[2],
15 | M == V*rho)
16 |
17 | m = Model(A, constraints)
18 | sol = m.solve(verbosity=0)
19 | print(sol.summary())
20 |
--------------------------------------------------------------------------------
/docs/source/examples/water_tank_output.txt:
--------------------------------------------------------------------------------
1 | Infeasible monomial equality: Cannot convert from 'V [m³]' to 'M [kg]'
2 |
3 | ┃┓ ┓ ┓
4 | ┃┃ ┃ ┃
5 | ┃┃ ┣╸d[0] ┣╸M
6 | Cost╺┫┃ ┃ (0.464m) ┃ (100kg, fixed)
7 | (1.29m²) ┃┣╸A ┛ ┛
8 | ┃┃ (1.29m²) ┓
9 | ┃┃ ┣╸d[1]·d[2]
10 | ┃┛ ┛ (0.215m²)
11 |
12 |
13 |
14 | ┃┓
15 | ┃┃
16 | ┃┣╸A ≥ 2·(d[0]·d[1] + d[0]·d[2] + d[1]·d[2])
17 | ┃┛
18 | ┃┓
19 | ┃┃
20 | ┃┣╸M = 100kg
21 | ┃┛
22 | ┃┓
23 | Model╺┫┃
24 | ┃┣╸M = V·\rho
25 | ┃┛
26 | ┃┓
27 | ┃┃
28 | ┃┣╸V = d[0]·d[1]·d[2]
29 | ┃┛
30 | ┃┓
31 | ┃┃
32 | ┃┣╸\rho = 1,000kg/m³
33 | ┃┛
34 |
35 |
36 | Free Variables
37 | --------------
38 | A : 1.293 [m²] Surface Area of the Tank
39 | V : 0.1 [m³] Volume of the Tank
40 | d : [ 0.464 0.464 0.464 ] [m] Dimension Vector
41 |
42 |
--------------------------------------------------------------------------------
/docs/source/examples/x_greaterthan_1.py:
--------------------------------------------------------------------------------
1 | "Very simple problem: minimize x while keeping x greater than 1."
2 | from gpkit import Variable, Model
3 |
4 | # Decision variable
5 | x = Variable("x")
6 |
7 | # Constraint
8 | constraints = [x >= 1]
9 |
10 | # Objective (to minimize)
11 | objective = x
12 |
13 | # Formulate the Model
14 | m = Model(objective, constraints)
15 |
16 | # Solve the Model
17 | sol = m.solve(verbosity=0)
18 |
19 | # print selected results
20 | print("Optimal cost: %.4g" % sol["cost"])
21 | print("Optimal x val: %.4g" % sol["variables"][x])
22 |
--------------------------------------------------------------------------------
/docs/source/examples/x_greaterthan_1_output.txt:
--------------------------------------------------------------------------------
1 | Optimal cost: 1
2 | Optimal x val: 1
3 |
--------------------------------------------------------------------------------
/docs/source/figures/Mission.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/figures/Mission.gif
--------------------------------------------------------------------------------
/docs/source/figures/referencesplot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/figures/referencesplot.png
--------------------------------------------------------------------------------
/docs/source/figures/sankey_autosaves/Mission.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/figures/sankey_autosaves/Mission.png
--------------------------------------------------------------------------------
/docs/source/figures/sankey_autosaves/Model.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/figures/sankey_autosaves/Model.png
--------------------------------------------------------------------------------
/docs/source/figures/sankey_autosaves/SolarMission.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/figures/sankey_autosaves/SolarMission.png
--------------------------------------------------------------------------------
/docs/source/figures/sankey_autosaves/SolarMission_Aircraft.Wing.Planform.b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/figures/sankey_autosaves/SolarMission_Aircraft.Wing.Planform.b.png
--------------------------------------------------------------------------------
/docs/source/figures/sankey_autosaves/SolarMission_CFRPFabric.tmin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/figures/sankey_autosaves/SolarMission_CFRPFabric.tmin.png
--------------------------------------------------------------------------------
/docs/source/figures/sankey_autosaves/SolarMission_Nprop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/figures/sankey_autosaves/SolarMission_Nprop.png
--------------------------------------------------------------------------------
/docs/source/figures/sankey_autosaves/SolarMission_Wtotal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/figures/sankey_autosaves/SolarMission_Wtotal.png
--------------------------------------------------------------------------------
/docs/source/figures/sizedconstrainttreemap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/figures/sizedconstrainttreemap.png
--------------------------------------------------------------------------------
/docs/source/figures/solartest.py:
--------------------------------------------------------------------------------
1 | from solar.solar import *
2 | Vehicle = Aircraft(Npod=3, sp=True)
3 | M = Mission(Vehicle, latitude=[20])
4 | M.cost = M[M.aircraft.Wtotal]
5 |
6 | M.localsolve().save("solar.p")
7 |
--------------------------------------------------------------------------------
/docs/source/figures/treemap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/figures/treemap.png
--------------------------------------------------------------------------------
/docs/source/gp101.rst:
--------------------------------------------------------------------------------
1 | .. _geometricprogramming:
2 |
3 | Geometric Programming 101
4 | *************************
5 |
6 | What is a GP?
7 | =============
8 |
9 | A Geometric Program (GP) is a type of non-linear optimization problem whose objective and constraints have a particular form.
10 |
11 | The decision variables must be strictly positive (non-zero, non-negative) quantities. This is a good fit for engineering design equations (which are often constructed to have only positive quantities), but any model with variables of unknown sign (such as forces and velocities without a predefined direction) may be difficult to express in a GP. Such models might be better expressed as :ref:`Signomials `.
12 |
13 | More precisely, GP objectives and inequalities are formed out of *monomials* and *posynomials*. In the context of GP, a monomial is defined as:
14 |
15 | .. math::
16 |
17 | f(x) = c x_1^{a_1} x_2^{a_2} ... x_n^{a_n}
18 |
19 | where :math:`c` is a positive constant, :math:`x_{1..n}` are decision variables, and :math:`a_{1..n}` are real exponents. For example, taking :math:`x`, :math:`y` and :math:`z` to be positive variables, the expressions
20 |
21 | .. math::
22 |
23 | 7x \qquad 4xy^2z \qquad \frac{2x}{y^2z^{0.3}} \qquad \sqrt{2xy}
24 |
25 | are all monomials. Building on this, a posynomial is defined as a sum of monomials:
26 |
27 | .. math::
28 |
29 | g(x) = \sum_{k=1}^K c_k x_1^{a_1k} x_2^{a_2k} ... x_n^{a_nk}
30 |
31 | For example, the expressions
32 |
33 | .. math::
34 |
35 | x^2 + 2xy + 1 \qquad 7xy + 0.4(yz)^{-1/3} \qquad 0.56 + \frac{x^{0.7}}{yz}
36 |
37 | are all posynomials.
38 | Alternatively, monomials can be defined as the subset of posynomials having only one term.
39 | Using :math:`f_i` to represent a monomial and :math:`g_i` to represent a posynomial,
40 | a GP in standard form is written as:
41 |
42 | .. math:: \begin{array}{lll}\text{}
43 | \text{minimize} & g_0(x) & \\
44 | \text{subject to} & f_i(x) = 1, & i = 1,....,m \\
45 | & g_i(x) \leq 1, & i = 1,....,n
46 | \end{array}
47 |
48 | Boyd et. al. give the following example of a GP in standard form:
49 |
50 | .. math:: \begin{array}{llll}\text{}
51 | \text{minimize} & x^{-1}y^{-1/2}z^{-1} + 2.3xz + 4xyz \\
52 | \text{subject to} & (1/3)x^{-2}y^{-2} + (4/3)y^{1/2}z^{-1} \leq 1 \\
53 | & x + 2y + 3z \leq 1 \\
54 | & (1/2)xy = 1
55 | \end{array}
56 |
57 | Why are GPs special?
58 | ====================
59 |
60 | Geometric programs have several powerful properties:
61 |
62 | #. Unlike most non-linear optimization problems, large GPs can be **solved extremely quickly**.
63 | #. If there exists an optimal solution to a GP, it is guaranteed to be **globally optimal**.
64 | #. Modern GP solvers require **no initial guesses** or tuning of solver parameters.
65 |
66 | These properties arise because GPs become *convex optimization problems* via a logarithmic transformation. In addition to their mathematical benefits, recent research has shown that many practical problems can be formulated as GPs or closely approximated as GPs.
67 |
68 |
69 | .. _signomials:
70 |
71 | What are Signomials / Signomial Programs?
72 | =========================================
73 |
74 | When the coefficients in a posynomial are allowed to be negative (but the variables stay strictly positive), that is called a Signomial.
75 |
76 | A Signomial Program has signomial constraints. While they cannot be solved as quickly or to global optima, because they build on the structure of a GP they can often be solved more quickly than a generic nonlinear program. More information can be found under :ref:`signomialprogramming`.
77 |
78 |
79 | Where can I learn more?
80 | =======================
81 |
82 | To learn more about GPs, refer to the following resources:
83 |
84 | * `A tutorial on geometric programming `_, by S. Boyd, S.J. Kim, L. Vandenberghe, and A. Hassibi.
85 | * `Convex optimization `_, by S. Boyd and L. Vandenberghe.
86 | * `Geometric Programming for Aircraft Design Optimization `_, Hoburg, Abbeel 2014
87 |
--------------------------------------------------------------------------------
/docs/source/gplogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/gplogo.png
--------------------------------------------------------------------------------
/docs/source/gplogo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/docs/source/index.rst:
--------------------------------------------------------------------------------
1 | .. figure:: gplogo.png
2 | :width: 250 px
3 |
4 | GPkit is a Python package for defining and manipulating
5 | geometric programming (GP) models.
6 |
7 | Our hopes are to bring geometric programming
8 | into engineering design processes
9 | in a disciplined and collaborative way, and to
10 | encourage research with GPs by providing an
11 | extensible object-oriented framework.
12 |
13 | GPkit abstracts away solvers so users
14 | can work directly with engineering equations and optimization concepts.
15 | Supported solvers are
16 | `MOSEK `_
17 | and `CVXOPT `_.
18 |
19 | Join our `mailing list `_ and/or `chatroom `_ for support and examples.
20 |
21 | Table of contents
22 | ====================
23 | .. toctree::
24 | :maxdepth: 2
25 |
26 | gp101
27 | installation
28 | gettingstarted
29 | debugging
30 | visint
31 | modelbuilding
32 | advancedcommands
33 | signomialprogramming
34 | examples
35 | autodoc/gpkit
36 | citinggpkit
37 | acknowledgements
38 | releasenotes
39 |
--------------------------------------------------------------------------------
/docs/source/installation.rst:
--------------------------------------------------------------------------------
1 | .. _installation:
2 |
3 | Installation
4 | ************
5 |
6 | 1. If you are on Mac or Windows, we recommend installing `Anaconda `_. Alternatively, `install pip and create a virtual environment `_.
7 | 2. (optional) Install the MOSEK 9 solver with ``pip install Mosek``, then a license as described below
8 | 3. (optional) Install the MOSEK 8 solver as described below
9 | 4. Run ``pip install gpkit`` in the appropriate terminal or command prompt.
10 | 5. Open a Python prompt and run ``import gpkit`` to finish installation and run unit tests.
11 |
12 | If you encounter any bugs please email ``gpkit@mit.edu``
13 | or `raise a GitHub issue `_.
14 |
15 |
16 | Installing MOSEK 8
17 | ==================
18 | GPkit interfaces with two off the shelf solvers: cvxopt, and MOSEK (versions 8 and 9).
19 | Cvxopt is open source and installed by default; MOSEK requires a commercial licence or (free)
20 | academic license. In MOSEK version 8 GPkit uses the command-line interface ``mskexpopt`` solver, while
21 | in MOSEK 9 it uses the more active exponential-cone interface (and hence supports :ref:`migp`).
22 |
23 | Mac OS X
24 | - If ``which gcc`` does not return anything, install the `Apple Command Line Tools `_.
25 | - Download `MOSEK 8 `_, then:
26 | - Move the ``mosek`` folder to your home directory
27 | - Follow `these steps for Mac `_.
28 | - If applicable, request an `academic license file `_ and put it in ``~/mosek/``
29 |
30 | Linux
31 | - Download `MOSEK 8 `_, then:
32 | - Move the ``mosek`` folder to your home directory
33 | - Follow `these steps for Linux `_.
34 | - If applicable, request an `academic license file `_ and put it in ``~/mosek/``
35 |
36 | Windows
37 | - Make sure ``gcc`` is on your system path.
38 | - To do this, type ``gcc`` into a command prompt.
39 | - If you get ``executable not found``, then install the 64-bit version (x86_64 installer architecture dropdown option) with GCC version 6.4.0 or older of `mingw `_.
40 | - In an Anaconda command prompt (or equivalent), run ``cd C:\Program Files\mingw-w64\x86_64-6.4.0-posix-seh-rt_v5-rev0\`` (or whatever corresponds to the correct installation directory; note that if mingw is in ``Program Files (x86)`` instead of ``Program Files`` you've installed the 32-bit version by mistake)
41 | - Run ``mingw-w64`` to add it to your executable path. For step 3 of the install process you'll need to run ``pip install gpkit`` from this prompt.
42 | - Download `MOSEK 8 `_, then:
43 | - Follow `these steps for Windows `_.
44 | - If applicable, request an `academic license file `_ and put it in ``C:\Users\(your_username)\mosek\``
45 |
46 | Debugging your installation
47 | ===========================
48 |
49 | You may need to rebuild GPkit if any of the following occur:
50 | - You install MOSEK after installing GPkit
51 | - You see ``Could not load settings file.`` when importing GPkit, or
52 | - ``Could not load MOSEK library: ImportError('expopt.so not found.')``
53 |
54 | To rebuild GPkit run ``python -c "from gpkit.build import rebuild; rebuild()"``.
55 |
56 | If that doesn't solve your issue then try the following:
57 | - ``pip uninstall gpkit``
58 | - ``pip install --no-cache-dir --no-deps gpkit``
59 | - ``python -c "import gpkit.tests; gpkit.tests.run()"``
60 | - If any tests fail, please email ``gpkit@mit.edu`` or `raise a GitHub issue `_.
61 |
62 |
63 | Bleeding-edge installations
64 | ===========================
65 |
66 | Active developers may wish to install the `latest GPkit `_ directly from Github. To do so,
67 |
68 | 1. ``pip uninstall gpkit`` to uninstall your existing GPkit.
69 | 2. ``git clone https://github.com/convexengineering/gpkit.git``
70 | 3. ``pip install -e gpkit`` to install that directory as your environment-wide GPkit.
71 | 4. ``cd ..; python -c "import gpkit.tests; gpkit.tests.run()"`` to test your installation from a non-local directory.
72 |
--------------------------------------------------------------------------------
/docs/source/ipynb/Box/Box_files/Box_34_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/ipynb/Box/Box_files/Box_34_0.png
--------------------------------------------------------------------------------
/docs/source/ipynb/Box/box-ractive.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/docs/source/ipynb/Box/box.constraints:
--------------------------------------------------------------------------------
1 | var w = r.plan.scalex,
2 | h = r.left.scalex,
3 | d = r.plan.scaley,
4 | dw = 50*(w-1),
5 | dh = 50*(h-1),
6 | dd = 50*(d-1)
7 |
8 | r.top.scalex = w
9 | r.top.scaley = h
10 | r.top.y = -dh -dd
11 | r.bottom.scalex = w
12 | r.bottom.scaley = h
13 | r.bottom.y = dh + dd
14 |
15 | r.left.scalex = h
16 | r.left.scaley = d
17 | r.left.x = -dh - dw
18 | r.right.scalex = h
19 | r.right.scaley = d
20 | r.right.x = dh + dw
21 |
--------------------------------------------------------------------------------
/docs/source/ipynb/Box/box.gpkit:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/docs/source/ipynb/Box/box.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
93 |
--------------------------------------------------------------------------------
/docs/source/ipynb/Box/boxlogo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
94 |
--------------------------------------------------------------------------------
/docs/source/ipynb/Fuel/Fuel_files/Fuel_17_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/ipynb/Fuel/Fuel_files/Fuel_17_0.png
--------------------------------------------------------------------------------
/docs/source/ipynb/Fuel/Fuel_files/Fuel_17_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/ipynb/Fuel/Fuel_files/Fuel_17_1.png
--------------------------------------------------------------------------------
/docs/source/ipynb/Fuel/Fuel_files/Fuel_17_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/docs/source/ipynb/Fuel/Fuel_files/Fuel_17_2.png
--------------------------------------------------------------------------------
/docs/source/modelbuilding.rst:
--------------------------------------------------------------------------------
1 | Building Complex Models
2 | ***********************
3 |
4 | Checking for result changes
5 | ===========================
6 | Tracking the effects of changes to complex models can get out of hand;
7 | we recommend saving solutions with ``sol.save()``, then checking that new solutions are almost equivalent
8 | with ``sol1.almost_equal(sol2)`` and/or ``print(sol1.diff(sol2))``, as shown below.
9 |
10 | .. literalinclude:: examples/checking_result_changes.py
11 |
12 | You can also check differences between swept solutions, or between
13 | a point solution and a sweep.
14 |
15 |
16 | Inheriting from ``Model``
17 | =========================
18 |
19 | GPkit encourages an object-oriented modeling approach, where the modeler creates objects that inherit from Model to break large systems down into subsystems and analysis domains. The benefits of this approach include modularity, reusability, and the ability to more closely follow mental models of system hierarchy. For example: two different models for a simple beam, designed by different modelers, should be able to be used interchangeably inside another subsystem (such as an aircraft wing) without either modeler having to write specifically with that use in mind.
20 |
21 | When you create a class that inherits from Model, write a ``.setup()`` method to create the model's variables and return its constraints. ``GPkit.Model.__init__`` will call that method and automatically add your model's name and unique ID to any created variables.
22 |
23 | Variables created in a ``setup`` method are added to the model even if they are not present in any constraints. This allows for simplistic 'template' models, which assume constant values for parameters and can grow incrementally in complexity as those variables are freed.
24 |
25 | At the end of this page a detailed example shows this technique in practice.
26 |
27 | Accessing Variables in Models
28 | =============================
29 | GPkit provides several ways to access a Variable in a ``Model`` (or ``ConstraintSet``):
30 |
31 | - using ``Model.variables_byname(key)``. This returns all Variables in the Model, as well as in any submodels, that match the key.
32 | - using ``Model.__getitem__``. ``Model[key]`` returns the only variable matching the key, even if the match occurs in a submodel. If multiple variables match the key, an error is raised.
33 |
34 | These methods are illustrated in the following example.
35 |
36 | .. literalinclude:: examples/model_var_access.py
37 |
38 | .. literalinclude:: examples/model_var_access_output.txt
39 | :language: breakdowns
40 |
41 | Vectorization
42 | =============
43 |
44 | ``gpkit.Vectorize`` creates an environment in which Variables are created with an additional dimension:
45 |
46 | .. literalinclude:: examples/vectorization.py
47 |
48 | This allows models written with scalar constraints to be created with vector constraints:
49 |
50 | .. literalinclude:: examples/vectorize.py
51 |
52 | .. literalinclude:: examples/vectorize_output.txt
53 | :language: breakdowns
54 |
55 |
56 |
57 | Multipoint analysis modeling
58 | ============================
59 |
60 | In many engineering models, there is a physical object that is operated in multiple conditions. Some variables correspond to the design of the object (size, weight, construction) while others are vectorized over the different conditions (speed, temperature, altitude). By combining named models and vectorization we can create intuitive representations of these systems while maintaining modularity and interoperability.
61 |
62 | In the example below, the models ``Aircraft`` and ``Wing`` have a ``.dynamic()`` method which creates instances of ``AircraftPerformance`` and ``WingAero``, respectively. The ``Aircraft`` and ``Wing`` models create variables, such as size and weight without fuel, that represent a physical object. The ``dynamic`` models create properties that change based on the flight conditions, such as drag and fuel weight.
63 |
64 | This means that when an aircraft is being optimized for a mission, you can create the aircraft (``AC`` in this example) and then pass it to a ``Mission`` model which can create vectorized aircraft performance models for each flight segment and/or flight condition.
65 |
66 | The :ref:`sensitivity diagram ` which this code outputs shows how it is organized (right-click and open in a new tab to see it more clearly):
67 |
68 | .. figure:: figures/sankey_autosaves/Model.png
69 |
70 | .. literalinclude:: examples/performance_modeling.py
71 |
72 | Note that the output table has been filtered above to show only variables of interest.
73 |
74 | .. literalinclude:: examples/performance_modeling_output.txt
75 | :language: breakdowns
76 |
--------------------------------------------------------------------------------
/docs/source/releasenotes.rst:
--------------------------------------------------------------------------------
1 | Release Notes
2 | *************
3 |
4 | `Release notes are available on Github `_
5 |
--------------------------------------------------------------------------------
/docs/source/signomialprogramming.rst:
--------------------------------------------------------------------------------
1 | .. _signomialprogramming:
2 |
3 | Signomial Programming
4 | *********************
5 |
6 | Signomial programming finds a local solution to a problem of the form:
7 |
8 |
9 | .. math:: \begin{array}{lll}\text{}
10 | \text{minimize} & g_0(x) & \\
11 | \text{subject to} & f_i(x) = 1, & i = 1,....,m \\
12 | & g_i(x) - h_i(x) \leq 1, & i = 1,....,n
13 | \end{array}
14 |
15 | where each :math:`f` is monomial while each :math:`g` and :math:`h` is a posynomial.
16 |
17 | This requires multiple solutions of geometric programs, and so will take longer to solve than an equivalent geometric programming formulation.
18 |
19 | In general, when given the choice of which variables to include in the positive-posynomial / :math:`g` side of the constraint, the modeler should:
20 |
21 | #. maximize the number of variables in :math:`g`,
22 | #. prioritize variables that are in the objective,
23 | #. then prioritize variables that are present in other constraints.
24 |
25 | The ``.localsolve`` syntax was chosen to emphasize that signomial programming returns a local optimum. For the same reason, calling ``.solve`` on an SP will raise an error.
26 |
27 | By default, signomial programs are first solved conservatively (by assuming each :math:`h` is equal only to its constant portion) and then become less conservative on each iteration.
28 |
29 | Example Usage
30 | =============
31 |
32 | .. literalinclude:: examples/simple_sp.py
33 |
34 | When using the ``localsolve`` method, the ``reltol`` argument specifies the relative tolerance of the solver: that is, by what percent does the solution have to improve between iterations? If any iteration improves less than that amount, the solver stops and returns its value.
35 |
36 | If you wish to start the local optimization at a particular point :math:`x_0`, however, you may do so by putting that position (a dictionary formatted as you would a substitution) as the ``x0`` argument.
37 |
38 | .. _sgp:
39 |
40 | Sequential Geometric Programs
41 | =============================
42 |
43 | The method of solving local GP approximations of a non-GP compatible model can be generalized, at the cost of the general smoothness and lack of a need for trust regions that SPs guarantee.
44 |
45 | For some applications, it is useful to call external codes which may not be GP compatible. Imagine we wished to solve the following optimization problem:
46 |
47 | .. math:: \begin{array}{lll}\text{}
48 | \text{minimize} & y & \\
49 | \text{subject to} & y \geq \sin(x) \\
50 | & \frac{\pi}{4} \leq x \leq \frac{\pi}{2}
51 | \end{array}
52 |
53 | This problem is not GP compatible due to the :math:`sin(x)` constraint. One approach might be to take the first term of the Taylor expansion of :math:`sin(x)` and attempt to solve:
54 |
55 | .. literalinclude:: examples/sin_approx_example.py
56 |
57 | .. literalinclude:: examples/sin_approx_example_output.txt
58 | :language: breakdowns
59 |
60 | Assume we have some external code which is capable of evaluating our incompatible function:
61 |
62 | .. literalinclude:: examples/external_function.py
63 |
64 | Now, we can create a ConstraintSet that allows GPkit to treat the incompatible constraint as though it were a signomial programming constraint:
65 |
66 | .. literalinclude:: examples/external_constraint.py
67 |
68 | and replace the incompatible constraint in our GP:
69 |
70 | .. literalinclude:: examples/external_sp.py
71 |
72 | .. literalinclude:: examples/external_sp_output.txt
73 | :language: breakdowns
74 |
75 | which is the expected result. This method has been generalized to larger problems, such as calling XFOIL and AVL.
76 |
77 | If you wish to start the local optimization at a particular point :math:`x_0`, however, you may do so by putting that position (a dictionary formatted as you would a substitution) as the ``x0`` argument
78 |
--------------------------------------------------------------------------------
/fulltests.sh:
--------------------------------------------------------------------------------
1 | python -c "from gpkit.tests import run; run()"
2 | rm *.pkl
3 | rm solution.*
4 | rm referencesplot.*
5 |
--------------------------------------------------------------------------------
/gpkit/__init__.py:
--------------------------------------------------------------------------------
1 | "GP and SP modeling package"
2 | #pylint:disable=wrong-import-position
3 | __version__ = "1.1"
4 | GPCOLORS = ["#59ade4", "#FA3333"]
5 | GPBLU, GPRED = GPCOLORS
6 |
7 | from .build import build
8 | from .units import units, ureg, DimensionalityError
9 | from .globals import settings, SignomialsEnabled, Vectorize, NamedVariables
10 | from .varkey import VarKey
11 | from .nomials import Monomial, Posynomial, Signomial, NomialArray
12 | from .nomials import VectorizableVariable as Variable
13 | # NOTE above: the Variable the user sees is not the Variable used internally
14 | from .nomials import VectorVariable, ArrayVariable
15 | from .constraints.gp import GeometricProgram
16 | from .constraints.sgp import SequentialGeometricProgram
17 | from .constraints.sigeq import SignomialEquality
18 | from .constraints.set import ConstraintSet
19 | from .constraints.model import Model
20 | from .solution_array import SolutionArray
21 | from .tools.docstring import parse_variables
22 | from .tests.run_tests import run as run_unit_tests
23 |
24 | if "just built!" in settings: # pragma: no cover
25 | run_unit_tests(verbosity=1)
26 | print("""
27 | GPkit is now installed with solver(s) %s
28 | To incorporate new solvers at a later date, run `gpkit.build()`.
29 |
30 | If any tests didn't pass, please post the output above
31 | (starting from "Found no installed solvers, beginning a build.")
32 | to gpkit@mit.edu or https://github.com/convexengineering/gpkit/issues/new
33 | so we can prevent others from having these errors.
34 |
35 | The same goes for any other bugs you encounter with GPkit:
36 | send 'em our way, along with any interesting models, speculative features,
37 | comments, discussions, or clarifications you feel like sharing.
38 |
39 | Finally, we hope you find our documentation (https://gpkit.readthedocs.io/)
40 | and engineering-design models (https://github.com/convexengineering/gplibrary/)
41 | to be useful resources for your own applications.
42 |
43 | Enjoy!
44 | """ % settings["installed_solvers"])
45 |
--------------------------------------------------------------------------------
/gpkit/constraints/__init__.py:
--------------------------------------------------------------------------------
1 | "Contains ConstraintSet and related classes and objects"
2 | from .single_equation import SingleEquationConstraint
3 | from .array import ArrayConstraint
4 |
--------------------------------------------------------------------------------
/gpkit/constraints/array.py:
--------------------------------------------------------------------------------
1 | "Implements ArrayConstraint"
2 | from .single_equation import SingleEquationConstraint
3 |
4 |
5 | class ArrayConstraint(SingleEquationConstraint, list):
6 | """A ConstraintSet for prettier array-constraint printing.
7 |
8 | When created by NomialArray `left` and `right` are likely to be
9 | be either NomialArrays or Varkeys of VectorVariables.
10 | """
11 | def __init__(self, constraints, left, oper, right):
12 | self.constraints = constraints
13 | list.__init__(self, constraints)
14 | SingleEquationConstraint.__init__(self, left, oper, right)
15 |
16 | def __iter__(self):
17 | yield from self.constraints.flat
18 |
19 | def lines_without(self, excluded):
20 | "Returns lines for indentation in hierarchical printing."
21 | return self.str_without(excluded).split("\n")
22 |
23 | def __bool__(self):
24 | "Allows the use of '=' NomialArrays as truth elements."
25 | return False if self.oper != "=" else bool(self.constraints.all())
26 |
--------------------------------------------------------------------------------
/gpkit/constraints/bounded.py:
--------------------------------------------------------------------------------
1 | "Implements Bounded"
2 | from collections import defaultdict
3 | import numpy as np
4 | from .. import Variable
5 | from .set import ConstraintSet
6 | from ..small_scripts import appendsolwarning, initsolwarning
7 |
8 |
9 | def varkey_bounds(varkeys, lower, upper):
10 | """Returns constraints list bounding all varkeys.
11 |
12 | Arguments
13 | ---------
14 | varkeys : iterable
15 | list of varkeys to create bounds for
16 |
17 | lower : float
18 | lower bound for all varkeys
19 |
20 | upper : float
21 | upper bound for all varkeys
22 | """
23 | constraints = []
24 | for varkey in varkeys:
25 | variable = Variable(**varkey.descr)
26 | if variable.units: # non-dimensionalize the variable monomial
27 | variable.units = variable.hmap.units = None
28 | constraint = []
29 | if lower:
30 | constraint.append(lower <= variable)
31 | if upper:
32 | constraint.append(variable <= upper)
33 | constraints.append(constraint)
34 | return constraints
35 |
36 |
37 | class Bounded(ConstraintSet):
38 | """Bounds contained variables, generally ensuring dual feasibility.
39 |
40 | Arguments
41 | ---------
42 | constraints : iterable
43 | constraints whose varkeys will be bounded
44 |
45 | eps : float (default 1e-30)
46 | default lower bound is eps, upper bound is 1/eps
47 |
48 | lower : float (default None)
49 | lower bound for all varkeys, replaces eps
50 |
51 | upper : float (default None)
52 | upper bound for all varkeys, replaces 1/eps
53 | """
54 | sens_threshold = 1e-7
55 | logtol_threshold = 3
56 |
57 | def __init__(self, constraints, *, eps=1e-30, lower=None, upper=None):
58 | if not isinstance(constraints, ConstraintSet):
59 | constraints = ConstraintSet(constraints)
60 | self.lowerbound = lower or eps
61 | self.upperbound = upper or 1/eps
62 | constrained_varkeys = constraints.constrained_varkeys()
63 | self.bound_varkeys = frozenset(vk for vk in constrained_varkeys
64 | if vk not in constraints.substitutions)
65 | bounding_constraints = varkey_bounds(self.bound_varkeys,
66 | self.lowerbound, self.upperbound)
67 | super().__init__({"original constraints": constraints,
68 | "variable bounds": bounding_constraints})
69 |
70 | def process_result(self, result):
71 | "Add boundedness to the model's solution"
72 | super().process_result(result)
73 | if "boundedness" not in result:
74 | result["boundedness"] = {}
75 | result["boundedness"].update(self.check_boundaries(result))
76 |
77 | def check_boundaries(self, result):
78 | "Creates (and potentially prints) a dictionary of unbounded variables."
79 | out = defaultdict(set)
80 | initsolwarning(result, "Arbitrarily Bounded Variables")
81 | for i, varkey in enumerate(self.bound_varkeys):
82 | value = result["variables"][varkey]
83 | c_senss = [result["sensitivities"]["constraints"].get(c, 0)
84 | for c in self["variable bounds"][i]]
85 | if self.lowerbound:
86 | bound = "lower bound of %.2g" % self.lowerbound
87 | if c_senss[0] >= self.sens_threshold:
88 | out["sensitive to " + bound].add(varkey)
89 | if np.log(value/self.lowerbound) <= self.logtol_threshold:
90 | out["value near " + bound].add(varkey)
91 | if self.upperbound:
92 | bound = "upper bound of %.2g" % self.upperbound
93 | if c_senss[-1] >= self.sens_threshold:
94 | out["sensitive to " + bound].add(varkey)
95 | if np.log(self.upperbound/value) <= self.logtol_threshold:
96 | out["value near " + bound].add(varkey)
97 | for bound, vks in out.items():
98 | msg = "% 34s: %s" % (bound, ", ".join([str(v) for v in vks]))
99 | appendsolwarning(msg, out, result,
100 | "Arbitrarily Bounded Variables")
101 | return out
102 |
--------------------------------------------------------------------------------
/gpkit/constraints/costed.py:
--------------------------------------------------------------------------------
1 | "Implement CostedConstraintSet"
2 | import numpy as np
3 | from .set import ConstraintSet
4 | from ..small_scripts import maybe_flatten
5 | from ..repr_conventions import lineagestr
6 |
7 |
8 | class CostedConstraintSet(ConstraintSet):
9 | """A ConstraintSet with a cost
10 |
11 | Arguments
12 | ---------
13 | cost : gpkit.Posynomial
14 | constraints : Iterable
15 | substitutions : dict
16 | """
17 | lineage = None
18 |
19 | def __init__(self, cost, constraints, substitutions=None):
20 | self.cost = maybe_flatten(cost)
21 | if isinstance(self.cost, np.ndarray): # if it's still a vector
22 | raise ValueError("Cost must be scalar, not the vector %s." % cost)
23 | subs = {k: k.value for k in self.cost.vks if "value" in k.descr}
24 | if substitutions:
25 | subs.update(substitutions)
26 | ConstraintSet.__init__(self, constraints, subs, bonusvks=self.cost.vks)
27 |
28 | def constrained_varkeys(self):
29 | "Return all varkeys in the cost and non-ConstraintSet constraints"
30 | constrained_varkeys = ConstraintSet.constrained_varkeys(self)
31 | constrained_varkeys.update(self.cost.vks)
32 | return constrained_varkeys
33 |
34 | def _rootlines(self, excluded=()):
35 | "String showing cost, to be used when this is the top constraint"
36 | if self.cost.vks:
37 | description = ["", "Cost Function", "-------------",
38 | " %s" % self.cost.str_without(excluded),
39 | "", "Constraints", "-----------"]
40 | else: # don't print the cost if it's a constant
41 | description = ["", "Constraints", "-----------"]
42 | if self.lineage:
43 | fullname = lineagestr(self)
44 | description = [fullname, "="*len(fullname)] + description
45 | return description
46 |
47 | def _rootlatex(self, excluded=()):
48 | "Latex showing cost, to be used when this is the top constraint"
49 | return "\n".join(["\\text{minimize}",
50 | " & %s \\\\" % self.cost.latex(excluded),
51 | "\\text{subject to}"])
52 |
--------------------------------------------------------------------------------
/gpkit/constraints/loose.py:
--------------------------------------------------------------------------------
1 | "Implements Loose"
2 | from .set import ConstraintSet
3 | from ..small_scripts import appendsolwarning, initsolwarning
4 |
5 |
6 | class Loose(ConstraintSet):
7 | "ConstraintSet whose inequalities must result in an equality."
8 | senstol = 1e-5
9 | raiseerror = False
10 |
11 | def __init__(self, constraints, *, senstol=None):
12 | super().__init__(constraints)
13 | self.senstol = senstol or self.senstol
14 |
15 | def process_result(self, result):
16 | "Checks that all constraints are satisfied with equality"
17 | super().process_result(result)
18 | initsolwarning(result, "Unexpectedly Tight Constraints")
19 | if "sensitivities" not in result:
20 | appendsolwarning("Could not evaluate due to choice variables.",
21 | (), result, "Unexpectedly Tight Constraints")
22 | return
23 | for constraint in self.flat():
24 | c_senss = result["sensitivities"]["constraints"].get(constraint, 0)
25 | if c_senss >= self.senstol:
26 | cstr = ("Constraint [ %.100s... %s %.100s... )"
27 | % (constraint.left, constraint.oper, constraint.right))
28 | msg = ("%s is not loose: it has a sensitivity of %+.4g."
29 | " (Allowable sensitivity: %.4g)" %
30 | (cstr, c_senss, self.senstol))
31 | appendsolwarning(msg, (c_senss, constraint), result,
32 | "Unexpectedly Tight Constraints")
33 | if self.raiseerror:
34 | raise RuntimeWarning(msg)
35 |
--------------------------------------------------------------------------------
/gpkit/constraints/sigeq.py:
--------------------------------------------------------------------------------
1 | "Implements SignomialEquality"
2 | from .set import ConstraintSet
3 | from ..nomials import SingleSignomialEquality as SSE
4 | from ..nomials.array import array_constraint as arrify
5 |
6 |
7 | class SignomialEquality(ConstraintSet):
8 | "A constraint of the general form posynomial == posynomial"
9 |
10 | def __init__(self, left, right):
11 | if hasattr(left, "shape") or hasattr(right, "shape"):
12 | ConstraintSet.__init__(self, arrify("=", SSE)(left, right))
13 | else:
14 | ConstraintSet.__init__(self, [SSE(left, right)])
15 |
--------------------------------------------------------------------------------
/gpkit/constraints/single_equation.py:
--------------------------------------------------------------------------------
1 | "Implements SingleEquationConstraint"
2 | from operator import le, ge, eq
3 | from ..small_scripts import try_str_without
4 | from ..repr_conventions import ReprMixin, UNICODE_EXPONENTS
5 |
6 |
7 | class SingleEquationConstraint(ReprMixin):
8 | "Constraint expressible in a single equation."
9 | latex_opers = {"<=": "\\leq", ">=": "\\geq", "=": "="}
10 | unicode_opers = {"<=": "≤", ">=": "≥", "=": "="}
11 | func_opers = {"<=": le, ">=": ge, "=": eq}
12 |
13 | def __init__(self, left, oper, right):
14 | self.left, self.oper, self.right = left, oper, right
15 |
16 | def str_without(self, excluded=("units")):
17 | "String representation without attributes in excluded list"
18 | leftstr = try_str_without(self.left, excluded)
19 | rightstr = try_str_without(self.right, excluded)
20 | rlines = rightstr.split("\n")
21 | if len(rlines) > 1:
22 | indent = len("%s %s " % (leftstr.split("\n")[-1], self.oper))
23 | rightstr = ("\n" + " "*indent).join(rlines)
24 | if UNICODE_EXPONENTS:
25 | oper = self.unicode_opers[self.oper]
26 | else:
27 | oper = self.oper
28 | return "%s %s %s" % (leftstr, oper, rightstr)
29 |
30 | def latex(self, excluded=("units")):
31 | "Latex representation without attributes in excluded list"
32 | return ("%s %s %s" % (
33 | try_str_without(self.left, excluded, latex=True),
34 | self.latex_opers[self.oper],
35 | try_str_without(self.right, excluded, latex=True)))
36 |
--------------------------------------------------------------------------------
/gpkit/constraints/tight.py:
--------------------------------------------------------------------------------
1 | "Implements Tight"
2 | from .set import ConstraintSet
3 | from ..small_scripts import mag
4 | from ..small_scripts import appendsolwarning, initsolwarning
5 | from .. import SignomialsEnabled
6 |
7 |
8 | class Tight(ConstraintSet):
9 | "ConstraintSet whose inequalities must result in an equality."
10 | reltol = 1e-3
11 |
12 | def __init__(self, constraints, *, reltol=None, **kwargs):
13 | super().__init__(constraints)
14 | self.reltol = reltol or self.reltol
15 | self.__dict__.update(kwargs) # NOTE: for Berk's use in labelling
16 |
17 | def process_result(self, result):
18 | "Checks that all constraints are satisfied with equality"
19 | super().process_result(result)
20 | variables = result["variables"]
21 | initsolwarning(result, "Unexpectedly Loose Constraints")
22 | for constraint in self.flat():
23 | with SignomialsEnabled():
24 | leftval = constraint.left.sub(variables).value
25 | rightval = constraint.right.sub(variables).value
26 | rel_diff = mag(abs(1 - leftval/rightval))
27 | if rel_diff >= self.reltol:
28 | msg = ("Constraint [%.100s... %s %.100s...] is not tight:"
29 | " the left hand side evaluated to %s but"
30 | " the right hand side evaluated to %s"
31 | " (Allowable error: %s%%, Actual error: %.2g%%)" %
32 | (constraint.left, constraint.oper, constraint.right,
33 | leftval, rightval,
34 | self.reltol*100, mag(rel_diff)*100))
35 | if hasattr(leftval, "magnitude"):
36 | rightval = rightval.to(leftval.units).magnitude
37 | leftval = leftval.magnitude
38 | tightvalues = (leftval, constraint.oper, rightval)
39 | appendsolwarning(msg, (rel_diff, tightvalues, constraint),
40 | result, "Unexpectedly Loose Constraints")
41 |
--------------------------------------------------------------------------------
/gpkit/exceptions.py:
--------------------------------------------------------------------------------
1 | "GPkit-specific Exception classes"
2 | from . import DimensionalityError # pylint: disable=unused-import
3 |
4 | class MathematicallyInvalid(TypeError):
5 | "Raised whenever something violates a mathematical definition."
6 |
7 | class InvalidPosynomial(MathematicallyInvalid):
8 | "Raised if a Posynomial would be created with a negative coefficient"
9 |
10 | class InvalidGPConstraint(MathematicallyInvalid):
11 | "Raised if a non-GP-compatible constraint is used in a GP"
12 |
13 | class InvalidSGPConstraint(MathematicallyInvalid):
14 | "Raised if a non-SGP-compatible constraint is used in an SGP"
15 |
16 |
17 | class UnnecessarySGP(ValueError):
18 | "Raised if an SGP is fully GP-compatible"
19 |
20 | class UnboundedGP(ValueError):
21 | "Raise if a GP is not fully bounded"
22 |
23 |
24 | class InvalidLicense(RuntimeWarning):
25 | "Raised if a solver's license is missing, invalid, or expired."
26 |
27 |
28 | class Infeasible(RuntimeWarning):
29 | "Raised if a model does not solve"
30 |
31 | class UnknownInfeasible(Infeasible):
32 | "Raised if a model does not solve for unknown reasons"
33 |
34 | class PrimalInfeasible(Infeasible):
35 | "Raised if a model returns a certificate of primal infeasibility"
36 |
37 | class DualInfeasible(Infeasible):
38 | "Raised if a model returns a certificate of dual infeasibility"
39 |
--------------------------------------------------------------------------------
/gpkit/globals.py:
--------------------------------------------------------------------------------
1 | "global mutable variables"
2 | import os
3 | from collections import defaultdict
4 | from . import build
5 |
6 |
7 | def load_settings(path=None, trybuild=True):
8 | "Load the settings file at SETTINGS_PATH; return settings dict"
9 | if path is None:
10 | path = os.sep.join([os.path.dirname(__file__), "env", "settings"])
11 | try: # if the settings file already exists, read it
12 | with open(path) as settingsfile:
13 | lines = [line[:-1].split(" : ") for line in settingsfile
14 | if len(line.split(" : ")) == 2]
15 | settings_ = {name: value.split(", ") for name, value in lines}
16 | for name, value in settings_.items():
17 | # flatten 1-element lists unless they're the solver list
18 | if len(value) == 1 and name != "installed_solvers":
19 | settings_[name], = value
20 | except IOError: # pragma: no cover
21 | settings_ = {"installed_solvers": [""]}
22 | if settings_["installed_solvers"] == [""] and trybuild: # pragma: no cover
23 | print("Found no installed solvers, beginning a build.")
24 | build()
25 | settings_ = load_settings(path, trybuild=False)
26 | if settings_["installed_solvers"] != [""]:
27 | settings_["just built!"] = True
28 | else:
29 | print("""
30 | =============
31 | Build failed! :(
32 | =============
33 | You may need to install a solver and then `import gpkit` again;
34 | see https://gpkit.readthedocs.io/en/latest/installation.html
35 | for troubleshooting details.
36 |
37 | But before you go, please post the output above
38 | (starting from "Found no installed solvers, beginning a build.")
39 | to gpkit@mit.edu or https://github.com/convexengineering/gpkit/issues/new
40 | so we can prevent others from having to see this message.
41 |
42 | Thanks! :)
43 | """)
44 | settings_["default_solver"] = settings_["installed_solvers"][0]
45 | return settings_
46 |
47 |
48 | settings = load_settings()
49 |
50 |
51 | class SignomialsEnabledMeta(type):
52 | "Metaclass to implement falsiness for SignomialsEnabled"
53 | def __bool__(cls): return cls._true # pylint: disable=multiple-statements
54 |
55 | class SignomialsEnabled(metaclass=SignomialsEnabledMeta): # pylint: disable=no-init
56 | """Class to put up and tear down signomial support in an instance of GPkit.
57 |
58 | Example
59 | -------
60 | >>> import gpkit
61 | >>> x = gpkit.Variable("x")
62 | >>> y = gpkit.Variable("y", 0.1)
63 | >>> with SignomialsEnabled():
64 | >>> constraints = [x >= 1-y]
65 | >>> gpkit.Model(x, constraints).localsolve()
66 | """
67 | _true = False # default signomial permissions
68 | # pylint: disable=multiple-statements
69 | def __enter__(self): SignomialsEnabled._true = True
70 | def __exit__(self, type_, val, traceback): SignomialsEnabled._true = False
71 |
72 |
73 | class Vectorize:
74 | """Creates an environment in which all variables are
75 | exended in an additional dimension.
76 | """
77 | vectorization = () # the current vectorization shape
78 |
79 | def __init__(self, dimension_length):
80 | self.dimension_length = dimension_length
81 |
82 | def __enter__(self):
83 | "Enters a vectorized environment."
84 | Vectorize.vectorization = (self.dimension_length,) + self.vectorization
85 |
86 | def __exit__(self, type_, val, traceback):
87 | "Leaves a vectorized environment."
88 | Vectorize.vectorization = self.vectorization[1:]
89 |
90 |
91 | class NamedVariables:
92 | """Creates an environment in which all variables have
93 | a model name and num appended to their varkeys.
94 | """
95 | lineage = () # the current model nesting
96 | modelnums = defaultdict(int) # the number of models of each lineage
97 | namedvars = defaultdict(list) # variables created in the current nesting
98 |
99 | @classmethod
100 | def reset_modelnumbers(cls):
101 | "Clear all model number counters"
102 | for key in list(cls.modelnums):
103 | del cls.modelnums[key]
104 |
105 | def __init__(self, name):
106 | self.name = name
107 |
108 | def __enter__(self):
109 | "Enters a named environment."
110 | num = self.modelnums[(self.lineage, self.name)]
111 | self.modelnums[(self.lineage, self.name)] += 1
112 | NamedVariables.lineage += ((self.name, num),) # NOTE: Side effects
113 | return self.lineage, self.namedvars[self.lineage]
114 |
115 | def __exit__(self, type_, val, traceback):
116 | "Leaves a named environment."
117 | del self.namedvars[self.lineage]
118 | NamedVariables.lineage = self.lineage[:-1] # NOTE: Side effects
119 |
--------------------------------------------------------------------------------
/gpkit/interactive/__init__.py:
--------------------------------------------------------------------------------
1 | "Module for the interactive and plotting functions of GPkit"
2 |
--------------------------------------------------------------------------------
/gpkit/interactive/plot_sweep.py:
--------------------------------------------------------------------------------
1 | "Implements plot_sweep1d function"
2 | import matplotlib.pyplot as plt
3 | from ..exceptions import InvalidGPConstraint
4 |
5 |
6 | def assign_axes(var, posys, axes):
7 | "Assigns axes to posys, creating and formatting if necessary"
8 | if not hasattr(posys, "__iter__"):
9 | posys = [posys]
10 | N = len(posys)
11 | if axes is None:
12 | _, axes = plt.subplots(N, 1, sharex="col", figsize=(4.5, 3+1.5*N))
13 | if N == 1:
14 | axes = [axes]
15 | format_and_label_axes(var, posys, axes)
16 | elif N == 1 and not hasattr(axes, "__len__"):
17 | axes = [axes]
18 | return posys, axes
19 |
20 |
21 | def format_and_label_axes(var, posys, axes, ylabel=True):
22 | "Formats and labels axes"
23 | for posy, ax in zip(posys, axes):
24 | if ylabel:
25 | if hasattr(posy, "key"):
26 | ylabel = (posy.key.descr.get("label", posy.key.name)
27 | + " [%s]" % posy.key.unitstr(dimless="-"))
28 | else:
29 | ylabel = str(posy)
30 | ax.set_ylabel(ylabel)
31 | ax.grid(color="0.6")
32 | # ax.set_frame_on(False)
33 | for item in [ax.xaxis.label, ax.yaxis.label]:
34 | item.set_fontsize(12)
35 | for item in ax.get_xticklabels() + ax.get_yticklabels():
36 | item.set_fontsize(9)
37 | ax.tick_params(length=0)
38 | ax.spines['left'].set_visible(False)
39 | ax.spines['top'].set_visible(False)
40 | for i in ax.spines.values():
41 | i.set_linewidth(0.6)
42 | i.set_color("0.6")
43 | i.set_linestyle("dotted")
44 | xlabel = (var.key.descr.get("label", var.key.name)
45 | + " [%s]" % var.key.unitstr(dimless="-"))
46 | ax.set_xlabel(xlabel) # pylint: disable=undefined-loop-variable
47 | plt.locator_params(nbins=4)
48 | plt.subplots_adjust(wspace=0.15)
49 |
50 |
51 | # pylint: disable=too-many-locals,too-many-branches,too-many-statements
52 | def plot_1dsweepgrid(model, sweeps, posys, origsol=None, tol=0.01, **solveargs):
53 | """Creates and plots a sweep from an existing model
54 |
55 | Example usage:
56 | f, _ = plot_sweep_1d(m, {'x': np.linspace(1, 2, 5)}, 'y')
57 | f.savefig('mysweep.png')
58 | """
59 | origsubs = {swept: model.substitutions[swept] for swept in sweeps
60 | if swept in model.substitutions}
61 | if origsubs and not origsol:
62 | try:
63 | origsol = model.solve(**solveargs)
64 | except InvalidGPConstraint:
65 | origsol = model.localsolve(**solveargs)
66 | if not hasattr(posys, "__iter__"):
67 | posys = [posys]
68 |
69 | N, S = len(posys), len(sweeps)
70 | f, axes = plt.subplots(N, S, sharex='col', sharey='row',
71 | figsize=(4+2*S, 4+2*N))
72 | plt.subplots_adjust(hspace=0.15)
73 |
74 | for i, (swept, swept_over) in enumerate(sweeps.items()):
75 | if isinstance(swept_over, tuple) and len(swept_over) == 2:
76 | sol = model.autosweep({swept: swept_over}, tol=tol, **solveargs)
77 | else:
78 | sol = model.sweep({swept: swept_over}, **solveargs)
79 |
80 | if len(sweeps) == 1:
81 | if len(posys) == 1:
82 | subaxes = [axes]
83 | else:
84 | subaxes = axes
85 | elif len(posys) == 1:
86 | subaxes = [axes[i]]
87 | else:
88 | subaxes = axes[:, i]
89 |
90 | sol.plot(posys, subaxes)
91 | if origsubs:
92 | for posy, ax in zip(posys, subaxes):
93 | ax.plot(origsubs[swept], origsol(posy), "ko", markersize=4)
94 | format_and_label_axes(swept, posys, subaxes, ylabel=(i == 0))
95 | model.substitutions.update(origsubs)
96 |
97 | return f, axes
98 |
--------------------------------------------------------------------------------
/gpkit/interactive/plotting.py:
--------------------------------------------------------------------------------
1 | """Plotting methods"""
2 | from collections import Counter
3 | import plotly.graph_objects as go
4 | import matplotlib.pyplot as plt
5 | import numpy as np
6 | from .plot_sweep import assign_axes
7 | from .. import GPCOLORS
8 |
9 |
10 | def compare(models, sweeps, posys, tol=0.001):
11 | """Compares the values of posys over a sweep of several models.
12 |
13 | If posys is of the same length as models, this will plot different
14 | variables from different models.
15 |
16 | Currently only supports a single sweepvar.
17 |
18 | Example Usage:
19 | compare([aec, fbc], {"R": (160, 300)},
20 | ["cost", ("W_{\\rm batt}", "W_{\\rm fuel}")], tol=0.001)
21 | """
22 | sols = [m.autosweep(sweeps, tol, verbosity=0) for m in models]
23 | posys, axes = assign_axes(sols[0].bst.sweptvar, posys, None)
24 | for posy, ax in zip(posys, axes):
25 | for i, sol in enumerate(sols):
26 | if hasattr(posy, "__len__") and len(posy) == len(sols):
27 | p = posy[i]
28 | else:
29 | p = posy
30 | color = GPCOLORS[i % len(GPCOLORS)]
31 | if sol._is_cost(p): # pylint: disable=protected-access
32 | ax.fill_between(sol.sampled_at,
33 | sol.cost_lb(), sol.cost_ub(),
34 | facecolor=color, edgecolor=color,
35 | linewidth=0.75)
36 | else:
37 | ax.plot(sol.sampled_at, sol(p), color=color)
38 |
39 |
40 | def plot_convergence(model):
41 | """Plots the convergence of a signomial programming model
42 |
43 | Arguments
44 | ---------
45 | model: Model
46 | Signomial programming model that has already been solved
47 |
48 | Returns
49 | -------
50 | matplotlib.pyplot Figure
51 | Plot of cost as functions of SP iteration #
52 | """
53 | fig, ax = plt.subplots()
54 |
55 | it = np.array([])
56 | cost = np.array([])
57 | for n in range(len(model.program.gps)):
58 | try:
59 | cost = np.append(cost, model.program.gps[n].result['cost'])
60 | it = np.append(it, n+1)
61 | except TypeError:
62 | pass
63 | ax.plot(it, cost, '-o')
64 | ax.set_xlabel('Iteration')
65 | ax.set_ylabel('Cost')
66 | ax.set_xticks(range(1, len(model.program.gps)+1))
67 | return fig, ax
68 |
69 |
70 | def treemap(model, itemize="variables", sizebycount=False):
71 | """Plots model structure as Plotly TreeMap
72 |
73 | Arguments
74 | ---------
75 | model: Model
76 | GPkit model object
77 |
78 | itemize (optional): string, either "variables" or "constraints"
79 | Specify whether to iterate over the model varkeys or constraints
80 |
81 | sizebycount (optional): bool
82 | Whether to size blocks by number of variables/constraints or use
83 | default sizing
84 |
85 | Returns
86 | -------
87 | plotly.graph_objects.Figure
88 | Plot of model hierarchy
89 |
90 | """
91 | modelnames = []
92 | parents = []
93 | sizes = []
94 |
95 | if itemize == "variables":
96 | lineagestrs = [l.lineagestr() or "Model" for l in model.varkeys]
97 | elif itemize == "constraints":
98 | lineagestrs = [l.lineagestr() or "Model" for l in model.flat()]
99 |
100 | modelcount = Counter(lineagestrs)
101 | for modelname, count in modelcount.items():
102 | modelnames.append(modelname)
103 | if "." in modelname:
104 | parent = modelname.rsplit(".", 1)[0]
105 | elif modelname != "Model":
106 | parent = "Model"
107 | else:
108 | parent = ""
109 | parents.append(parent)
110 | sizes.append(count)
111 |
112 | for parent in parents:
113 | if parent not in modelnames:
114 | modelnames.append(parent)
115 | if "." in parent:
116 | grandparent = parent.rsplit(".", 1)[0]
117 | elif parent != "Model":
118 | grandparent = "Model"
119 | else:
120 | grandparent = ""
121 | parents.append(grandparent)
122 | sizes.append(0)
123 |
124 | fig = go.Figure(go.Treemap(
125 | ids=modelnames,
126 | labels=[modelname.split(".")[-1] for modelname in modelnames],
127 | parents=parents,
128 | values=sizes if sizebycount else None,
129 | ))
130 | return fig
131 |
--------------------------------------------------------------------------------
/gpkit/interactive/references.py:
--------------------------------------------------------------------------------
1 | "Code to make variable references plots"
2 |
3 | import os
4 | import shutil
5 | import webbrowser
6 | from collections import defaultdict
7 |
8 |
9 | # pylint:disable=too-many-locals
10 | def referencesplot(model, *, openimmediately=True):
11 | """Makes a references plot.
12 |
13 | 1) Creates the JSON file for a d3 references plot
14 | 2) Places it and the corresponding HTML file in the working directory
15 | 3) (optionally) opens that HTML file up immediately in a web browser
16 |
17 | """
18 | imports = {}
19 | totalv_ss = defaultdict(dict)
20 | for constraint in model.flat():
21 | for varkey in constraint.vks:
22 | vlineage = varkey.lineagestr()
23 | clineage = constraint.lineagestr()
24 | if not vlineage:
25 | vlineage = "%s [%s]" % (varkey, varkey.unitstr())
26 | for lin in (clineage, vlineage):
27 | if lin not in imports:
28 | imports[lin] = set()
29 | if vlineage != clineage:
30 | imports[clineage].add(vlineage)
31 | if constraint.v_ss:
32 | totalv_ss[clineage] += constraint.v_ss
33 |
34 | def clean_lineage(lineage, clusterdepth=2):
35 | prelineage = ".".join(lineage.split(".")[:clusterdepth])
36 | last = "0".join(lineage.split(".")[clusterdepth:])
37 | return "model."+prelineage + "." + last
38 |
39 | lines = ['jsondata = [']
40 | for lineage, limports in imports.items():
41 | name, short = clean_lineage(lineage), lineage.split(".")[-1]
42 | limports = map(clean_lineage, limports)
43 | lines.append(
44 | ' {"name":"%s","fullname":"%s","shortname":"%s","imports":%s},'
45 | % (name, lineage, short, repr(list(limports)).replace("'", '"')))
46 | lines[-1] = lines[-1][:-1]
47 | lines.append("]")
48 |
49 | if totalv_ss:
50 | def get_total_senss(clineage, vlineage, normalize=False):
51 | v_ss = totalv_ss[clineage]
52 | num = sum(abs(ss) for vk, ss in v_ss.items()
53 | if vk.lineagestr() == vlineage)
54 | if not normalize:
55 | return num
56 | return num/sum(abs(ss) for ss in v_ss.values())
57 | lines.append("globalsenss = {")
58 | for clineage, limports in imports.items():
59 | if not limports:
60 | continue
61 | limports = {vl: get_total_senss(clineage, vl) for vl in limports}
62 | lines.append(' "%s": %s,' %
63 | (clineage, repr(limports).replace("'", '"')))
64 | lines[-1] = lines[-1][:-1]
65 | lines.append("}")
66 | lines.append("normalizedsenss = {")
67 | for clineage, limports in imports.items():
68 | if not limports:
69 | continue
70 | limports = {vl: get_total_senss(clineage, vl, normalize=True)
71 | for vl in limports}
72 | lines.append(' "%s": %s,' %
73 | (clineage, repr(limports).replace("'", '"')))
74 | lines[-1] = lines[-1][:-1]
75 | lines.append("}")
76 |
77 | with open("referencesplot.json", "w") as f:
78 | f.write("\n".join(lines))
79 |
80 | htmlfile = "referencesplot.html"
81 | if not os.path.isfile(htmlfile):
82 | shutil.copy(os.path.join(os.path.dirname(__file__), htmlfile), htmlfile)
83 |
84 | if openimmediately:
85 | webbrowser.open("file://" + os.path.join(os.getcwd(), htmlfile),
86 | autoraise=True)
87 |
--------------------------------------------------------------------------------
/gpkit/nomials/__init__.py:
--------------------------------------------------------------------------------
1 | "Contains nomials, inequalities, and arrays"
2 | from .array import NomialArray
3 | from .core import Nomial
4 | from .data import NomialData
5 | from .map import NomialMap
6 | from .math import Monomial, Posynomial, Signomial
7 | from .math import MonomialEquality, PosynomialInequality
8 | from .math import SignomialInequality, SingleSignomialEquality
9 | from .substitution import parse_subs
10 | from .variables import Variable, ArrayVariable, VectorizableVariable
11 |
12 | VectorVariable = ArrayVariable
13 |
--------------------------------------------------------------------------------
/gpkit/nomials/data.py:
--------------------------------------------------------------------------------
1 | """Machinery for exps, cs, varlocs data -- common to nomials and programs"""
2 | import numpy as np
3 | from ..keydict import KeySet
4 | from ..repr_conventions import ReprMixin
5 | from ..varkey import VarKey
6 |
7 |
8 | class NomialData(ReprMixin):
9 | """Object for holding cs, exps, and other basic 'nomial' properties.
10 |
11 | cs: array (coefficient of each monomial term)
12 | exps: tuple of {VarKey: float} (exponents of each monomial term)
13 | varlocs: {VarKey: list} (terms each variable appears in)
14 | units: pint.UnitsContainer
15 | """
16 | # pylint: disable=too-many-instance-attributes
17 | _hashvalue = _varlocs = _exps = _cs = _varkeys = None
18 |
19 | def __init__(self, hmap):
20 | self.hmap = hmap
21 | self.units = self.hmap.units
22 | self.any_nonpositive_cs = any(c <= 0 for c in self.hmap.values())
23 |
24 | def to(self, units):
25 | "Create new Signomial converted to new units"
26 | return self.__class__(self.hmap.to(units))
27 |
28 | @property
29 | def exps(self):
30 | "Create exps or return cached exps"
31 | if self._exps is None:
32 | self._exps = tuple(self.hmap.keys())
33 | return self._exps
34 |
35 | @property
36 | def cs(self):
37 | "Create cs or return cached cs"
38 | if self._cs is None:
39 | self._cs = np.array(list(self.hmap.values()))
40 | if self.hmap.units:
41 | # TODO: treat vars as dimensionless, it's a hack
42 | self._cs = self._cs*self.hmap.units
43 | return self._cs
44 |
45 | def __hash__(self):
46 | return hash(self.hmap)
47 |
48 | @property
49 | def vks(self):
50 | "Set of a NomialData's varkeys, created as necessary."
51 | vks = set()
52 | for exp in self.hmap:
53 | vks.update(exp)
54 | return vks
55 |
56 | @property # TODO: remove this
57 | def varkeys(self):
58 | "KeySet of a NomialData's varkeys, created as necessary."
59 | return KeySet(self.vks)
60 |
61 | def __eq__(self, other):
62 | "Equality test"
63 | if not hasattr(other, "hmap"):
64 | return NotImplemented
65 | if isinstance(other, VarKey):
66 | return False
67 | if self.hmap != other.hmap:
68 | return False
69 | if self.units != other.units:
70 | return False
71 | return True
72 |
--------------------------------------------------------------------------------
/gpkit/nomials/substitution.py:
--------------------------------------------------------------------------------
1 | "Scripts to parse and collate substitutions"
2 | import warnings as pywarnings
3 | import numpy as np
4 | from ..small_scripts import splitsweep
5 | from ..keydict import KeySet
6 |
7 |
8 | def parse_subs(varkeys, substitutions, clean=False):
9 | "Seperates subs into the constants, sweeps, linkedsweeps actually present."
10 | constants, sweep, linkedsweep = {}, {}, {}
11 | if clean:
12 | for var in varkeys:
13 | if dict.__contains__(substitutions, var):
14 | sub = dict.__getitem__(substitutions, var)
15 | append_sub(sub, [var], constants, sweep, linkedsweep)
16 | else:
17 | if not hasattr(varkeys, "keymap"):
18 | varkeys = KeySet(varkeys)
19 | varkeys.update_keymap()
20 | if hasattr(substitutions, "keymap"):
21 | for var in varkeys.keymap:
22 | if dict.__contains__(substitutions, var):
23 | sub = dict.__getitem__(substitutions, var)
24 | keys = varkeys.keymap[var]
25 | append_sub(sub, keys, constants, sweep, linkedsweep)
26 | else:
27 | for var in substitutions:
28 | key = getattr(var, "key", var)
29 | if key in varkeys.keymap:
30 | sub, keys = substitutions[var], varkeys.keymap[key]
31 | append_sub(sub, keys, constants, sweep, linkedsweep)
32 | return constants, sweep, linkedsweep
33 |
34 |
35 | def append_sub(sub, keys, constants, sweep, linkedsweep):
36 | "Appends sub to constants, sweep, or linkedsweep."
37 | sweepsub, sweepval = splitsweep(sub)
38 | if sweepsub: # if the whole key is swept
39 | sub = sweepval
40 | for key in keys:
41 | if not key.shape or not getattr(sub, "shape", hasattr(sub, "__len__")):
42 | value = sub
43 | else:
44 | with pywarnings.catch_warnings():
45 | pywarnings.filterwarnings("error")
46 | try:
47 | sub = np.array(sub) if not hasattr(sub, "shape") else sub
48 | except Warning: # pragma: no cover #TODO: coverage this
49 | # ragged nested sequences, eg [[2]], [3, 4]], in py3.7+
50 | sub = np.array(sub, dtype=object)
51 | if key.shape == sub.shape:
52 | value = sub[key.idx]
53 | sweepel, sweepval = splitsweep(value)
54 | if sweepel: # if only an element is swept
55 | value = sweepval
56 | sweepsub = True
57 | elif sweepsub:
58 | try:
59 | np.broadcast(sub, np.empty(key.shape))
60 | except ValueError:
61 | raise ValueError("cannot sweep variable %s of shape %s"
62 | " with array of shape %s; array shape"
63 | " must either be %s or %s" %
64 | (key.veckey, key.shape, sub.shape,
65 | key.shape, ("N",)+key.shape))
66 | idx = (slice(None),)+key.descr["idx"]
67 | value = sub[idx]
68 | else:
69 | raise ValueError("cannot substitute array of shape %s for"
70 | " variable %s of shape %s." %
71 | (sub.shape, key.veckey, key.shape))
72 | if hasattr(value, "__call__") and not hasattr(value, "key"):
73 | linkedsweep[key] = value
74 | elif sweepsub:
75 | sweep[key] = value
76 | else:
77 | try:
78 | assert np.isnan(value)
79 | except (AssertionError, TypeError, ValueError):
80 | constants[key] = value
81 |
--------------------------------------------------------------------------------
/gpkit/small_scripts.py:
--------------------------------------------------------------------------------
1 | """Assorted helper methods"""
2 | from collections.abc import Iterable
3 | import numpy as np
4 |
5 |
6 | def broadcast_substitution(key, array):
7 | "Broadcasts input into the shape of a given key"
8 | return np.broadcast_to(array, reversed(key.key.shape)).T
9 |
10 |
11 | def veclinkedfn(linkedfn, i):
12 | "Generate an indexed linking function."
13 | def newlinkedfn(c):
14 | "Linked function that pulls out a particular index"
15 | return np.array(linkedfn(c))[i]
16 | return newlinkedfn
17 |
18 |
19 | def initsolwarning(result, category="uncategorized"):
20 | "Creates a results dictionary for a particular category of warning."
21 | if "warnings" not in result:
22 | result["warnings"] = {}
23 | if category not in result["warnings"]:
24 | result["warnings"][category] = []
25 |
26 |
27 | def appendsolwarning(msg, data, result, category="uncategorized"):
28 | "Append a particular category of warnings to a solution."
29 | result["warnings"][category].append((msg, data))
30 |
31 |
32 | @np.vectorize
33 | def isnan(element):
34 | "Determine if something of arbitrary type is a numpy nan."
35 | try:
36 | return np.isnan(element)
37 | except TypeError:
38 | return False
39 |
40 |
41 | def maybe_flatten(value):
42 | "Extract values from 0-d numpy arrays, if necessary"
43 | if hasattr(value, "size") and value.size == 1:
44 | return value.item()
45 | return value
46 |
47 |
48 | def try_str_without(item, excluded, *, latex=False):
49 | "Try to call item.str_without(excluded); fall back to str(item)"
50 | if latex and hasattr(item, "latex"):
51 | return item.latex(excluded)
52 | if hasattr(item, "str_without"):
53 | return item.str_without(excluded)
54 | return str(item)
55 |
56 |
57 | def mag(c):
58 | "Return magnitude of a Number or Quantity"
59 | return getattr(c, "magnitude", c)
60 |
61 |
62 | def is_sweepvar(sub):
63 | "Determines if a given substitution indicates a sweep."
64 | return splitsweep(sub)[0]
65 |
66 |
67 | def splitsweep(sub):
68 | "Splits a substitution into (is_sweepvar, sweepval)"
69 | try:
70 | sweep, value = sub
71 | if sweep is "sweep" and (isinstance(value, Iterable) or # pylint: disable=literal-comparison
72 | hasattr(value, "__call__")):
73 | return True, value
74 | except (TypeError, ValueError):
75 | pass
76 | return False, None
77 |
--------------------------------------------------------------------------------
/gpkit/solvers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/convexengineering/gpkit/bea1234606649dd11a2e59b610b2ba8b8c8adfae/gpkit/solvers/__init__.py
--------------------------------------------------------------------------------
/gpkit/solvers/cvxopt.py:
--------------------------------------------------------------------------------
1 | "Implements the GPkit interface to CVXOPT"
2 | import numpy as np
3 | from cvxopt import spmatrix, matrix
4 | from cvxopt.solvers import gp
5 | from gpkit.exceptions import UnknownInfeasible, DualInfeasible
6 |
7 |
8 | # pylint: disable=too-many-locals,too-many-statements
9 | def optimize(*, c, A, k, meq_idxs, use_leqs=True, **kwargs):
10 | """Interface to the CVXOPT solver
11 |
12 | Definitions
13 | -----------
14 | "[a,b] array of floats" indicates array-like data with shape [a,b]
15 | n is the number of monomials in the gp
16 | m is the number of variables in the gp
17 | p is the number of posynomial constraints in the gp
18 |
19 | Arguments
20 | ---------
21 | c : floats array of shape n
22 | Coefficients of each monomial
23 | A : floats array of shape (n, m)
24 | Exponents of the various free variables for each monomial.
25 | k : ints array of shape p+1
26 | k[0] is the number of monomials (rows of A) present in the objective
27 | k[1:] is the number of monomials present in each constraint
28 |
29 | Returns
30 | -------
31 | dict
32 | Contains the following keys
33 | "success": bool
34 | "objective_sol" float
35 | Optimal value of the objective
36 | "primal_sol": floats array of size m
37 | Optimal value of free variables. Note: not in logspace.
38 | "dual_sol": floats array of size p
39 | Optimal value of the dual variables, in logspace.
40 | """
41 | log_c = np.log(np.array(c))
42 | A = A.tocsr()
43 | maxcol = A.shape[1]-1
44 | lse_mons, lin_mons, leq_mons = [], [], []
45 | lse_posys, lin_posys, leq_posys = [], [], []
46 | constraint_hashes = set()
47 | for i, n_monomials in enumerate(k):
48 | start = sum(k[:i])
49 | mons = range(start, start+k[i])
50 | A_m = A[mons, :].tocoo()
51 | chash = hash((c[i], tuple(A_m.data), tuple(A_m.row), tuple(A_m.col)))
52 | if chash in constraint_hashes:
53 | continue # already got it
54 | if i: # skip cost posy
55 | constraint_hashes.add(chash)
56 | if use_leqs and start in meq_idxs.all:
57 | if start in meq_idxs.first_half:
58 | leq_posys.append(i)
59 | leq_mons.extend(mons)
60 | elif i != 0 and n_monomials == 1:
61 | lin_mons.extend(mons)
62 | lin_posys.append(i)
63 | else:
64 | lse_mons.extend(mons)
65 | lse_posys.append(i)
66 | if leq_mons:
67 | A_leq = A[leq_mons, :].tocoo()
68 | log_c_leq = log_c[leq_mons]
69 | kwargs["A"] = spmatrix([float(r) for r in A_leq.data]+[0],
70 | [int(r) for r in A_leq.row]+[0],
71 | [int(r) for r in A_leq.col]+[maxcol], tc="d")
72 | kwargs["b"] = matrix(-log_c_leq)
73 | if lin_mons:
74 | A_lin = A[lin_mons, :].tocoo()
75 | log_c_lin = log_c[lin_mons]
76 | kwargs["G"] = spmatrix([float(r) for r in A_lin.data]+[0],
77 | [int(r) for r in A_lin.row]+[0],
78 | [int(r) for r in A_lin.col]+[maxcol], tc="d")
79 | kwargs["h"] = matrix(-log_c_lin)
80 | k_lse = [k[i] for i in lse_posys]
81 | A_lse = A[lse_mons, :].tocoo()
82 | log_c_lse = log_c[lse_mons]
83 | F = spmatrix([float(r) for r in A_lse.data]+[0],
84 | [int(r) for r in A_lse.row]+[0],
85 | [int(r) for r in A_lse.col]+[maxcol], tc="d")
86 | g = matrix(log_c_lse)
87 | try:
88 | solution = gp(k_lse, F, g, **kwargs)
89 | except ValueError as e:
90 | raise DualInfeasible() from e
91 | if solution["status"] != "optimal":
92 | raise UnknownInfeasible("solution status " + repr(solution["status"]))
93 | la = np.zeros(len(k))
94 | la[lin_posys] = list(solution["zl"])
95 | la[lse_posys] = [1.] + list(solution["znl"])
96 | for leq_posy, yi in zip(leq_posys, solution["y"]):
97 | if yi >= 0:
98 | la[leq_posy] = yi
99 | else: # flip it around to the other "inequality"
100 | la[leq_posy+1] = -yi
101 | return dict(status=solution["status"],
102 | objective=np.exp(solution["primal objective"]),
103 | primal=np.ravel(solution["x"]),
104 | la=la)
105 |
--------------------------------------------------------------------------------
/gpkit/tests/__init__.py:
--------------------------------------------------------------------------------
1 | "GPkit testing module"
2 |
3 | from .run_tests import run
4 |
--------------------------------------------------------------------------------
/gpkit/tests/from_paths.py:
--------------------------------------------------------------------------------
1 | "Runs each file listed in pwd/TESTS as a test"
2 | import unittest
3 | import os
4 | import re
5 | from gpkit import settings
6 | from gpkit.tests.helpers import generate_example_tests, new_test
7 |
8 |
9 | class TestFiles(unittest.TestCase):
10 | "Stub to be filled with files in $pwd/TESTS"
11 |
12 |
13 | def clean(string):
14 | """Parses string into valid python variable name
15 |
16 | https://stackoverflow.com/questions/3303312/
17 | how-do-i-convert-a-string-to-a-valid-variable-name-in-python
18 | """
19 | string = re.sub('[^0-9a-zA-Z_]', '_', string) # Replace invalid with _
20 | return re.sub('^[^a-zA-Z_]+', '', string) # Remove leading until valid
21 |
22 |
23 | def add_filetest(testclass, path):
24 | "Add test that imports the given path and runs its test() function"
25 | path = path.strip()
26 | print("adding test for", repr(path))
27 |
28 | def test_fn(self):
29 | top_level = os.getcwd()
30 | try:
31 | dirname = os.path.dirname(path)
32 | if dirname:
33 | os.chdir(os.path.dirname(path))
34 | mod = __import__(os.path.basename(path)[:-3])
35 | if not hasattr(mod, "test"):
36 | self.fail("file '%s' had no `test` function." % path)
37 | mod.test()
38 | finally:
39 | os.chdir(top_level)
40 |
41 | setattr(testclass, "test_"+clean(path), test_fn)
42 |
43 |
44 | def newtest_fn(name, solver, import_dict, path):
45 | "Doubly nested callbacks to run the test with `getattr(self, name)()`"
46 | return new_test(name, solver, import_dict, path,
47 | testfn=(lambda name, import_dict, path:
48 | lambda self: getattr(self, name)())) # pylint:disable=undefined-variable
49 |
50 |
51 | def run(filename="TESTS", xmloutput=False, skipsolvers="look around"):
52 | "Parse and run paths from a given file for each solver"
53 | with open(filename, "r") as f:
54 | for path in f:
55 | add_filetest(TestFiles, path)
56 | if skipsolvers == "look around":
57 | from .test_repo import get_settings
58 | skipsolvers = get_settings()["skipsolvers"]
59 | solvers = [s for s in settings["installed_solvers"]
60 | if not skipsolvers or s not in skipsolvers]
61 | tests = generate_example_tests("", [TestFiles], solvers,
62 | newtest_fn=newtest_fn)
63 | if not solvers:
64 | # Dummy test in case all installed solvers are skipped.
65 | tests[0].test_dummy = lambda self: None
66 | from gpkit.tests.run_tests import run as run_
67 | run_(tests=tests, xmloutput=xmloutput)
68 |
--------------------------------------------------------------------------------
/gpkit/tests/run_tests.py:
--------------------------------------------------------------------------------
1 | """Script for running all gpkit unit tests"""
2 | from gpkit.tests.helpers import run_tests
3 |
4 |
5 | def import_tests():
6 | """Get a list of all GPkit unit test TestCases"""
7 | tests = []
8 |
9 | from gpkit.tests import t_tools
10 | tests += t_tools.TESTS
11 |
12 | from gpkit.tests import t_sub
13 | tests += t_sub.TESTS
14 |
15 | from gpkit.tests import t_vars
16 | tests += t_vars.TESTS
17 |
18 | from gpkit.tests import t_nomials
19 | tests += t_nomials.TESTS
20 |
21 | from gpkit.tests import t_constraints
22 | tests += t_constraints.TESTS
23 |
24 | from gpkit.tests import t_nomial_array
25 | tests += t_nomial_array.TESTS
26 |
27 | from gpkit.tests import t_model
28 | tests += t_model.TESTS
29 |
30 | from gpkit.tests import t_solution_array
31 | tests += t_solution_array.TESTS
32 |
33 | from gpkit.tests import t_small
34 | tests += t_small.TESTS
35 |
36 | from gpkit.tests import t_examples
37 | tests += t_examples.TESTS
38 |
39 | from gpkit.tests import t_keydict
40 | tests += t_keydict.TESTS
41 |
42 | return tests
43 |
44 |
45 | def run(xmloutput=False, tests=None, verbosity=1):
46 | """Run all gpkit unit tests.
47 |
48 | Arguments
49 | ---------
50 | xmloutput: bool
51 | If true, generate xml output files for continuous integration
52 | """
53 | if tests is None:
54 | tests = import_tests()
55 | if xmloutput:
56 | run_tests(tests, xmloutput='test_reports')
57 | else: # pragma: no cover
58 | run_tests(tests, verbosity=verbosity)
59 |
60 | if __name__ == "__main__": # pragma: no cover
61 | run()
62 |
--------------------------------------------------------------------------------
/gpkit/tests/t_keydict.py:
--------------------------------------------------------------------------------
1 | """Test KeyDict class"""
2 | import unittest
3 | import numpy as np
4 | from gpkit import Variable, VectorVariable
5 | import gpkit
6 | from gpkit.keydict import KeyDict
7 | from gpkit.tests.helpers import run_tests
8 |
9 |
10 | class TestKeyDict(unittest.TestCase):
11 | """TestCase for the KeyDict class"""
12 |
13 | def test_nonnumeric(self):
14 | x = VectorVariable(2, "x")
15 | kd = KeyDict()
16 | kd[x[1]] = "2"
17 | self.assertTrue(np.isnan(kd[x[0]]))
18 | self.assertEqual(kd[x[1]], "2")
19 | self.assertNotIn(x[0], kd)
20 | self.assertIn(x[1], kd)
21 |
22 | def test_setattr(self):
23 | kd = KeyDict()
24 | x = Variable("x", lineage=(("test", 0),))
25 | kd[x] = 1
26 | self.assertIn(x, kd)
27 | self.assertEqual(set(kd), set([x.key]))
28 |
29 | def test_getattr(self):
30 | kd = KeyDict()
31 | x = Variable("x", lineage=[("Motor", 0)])
32 | kd[x] = 52
33 | self.assertEqual(kd[x], 52)
34 | self.assertEqual(kd[x.key], 52)
35 | self.assertEqual(kd["x"], 52)
36 | self.assertEqual(kd["Motor.x"], 52)
37 | self.assertNotIn("x.Someothermodelname", kd)
38 |
39 | def test_failed_getattr(self):
40 | kd = KeyDict()
41 | with self.assertRaises(KeyError):
42 | _ = kd["waldo"]
43 | # issue 893: failed __getitem__ caused state change
44 | self.assertNotIn("waldo", kd)
45 | waldo = Variable("waldo")
46 | kd.update({waldo: 5})
47 | res = kd["waldo"]
48 | self.assertEqual(res, 5)
49 | self.assertIn("waldo", kd)
50 |
51 | def test_vector(self):
52 | v = VectorVariable(3, "v")
53 | kd = KeyDict()
54 | kd[v] = np.array([2, 3, 4])
55 | self.assertTrue(all(kd[v] == kd[v.key])) # pylint:disable=no-member
56 | self.assertTrue(all(kd["v"] == np.array([2, 3, 4])))
57 | self.assertEqual(v[0].key.idx, (0,))
58 | self.assertEqual(kd[v][0], kd[v[0]])
59 | self.assertEqual(kd[v][0], 2)
60 | kd[v[0]] = 6
61 | self.assertEqual(kd[v][0], kd[v[0]])
62 | self.assertEqual(kd[v][0], 6)
63 | self.assertTrue(all(kd[v] == np.array([6, 3, 4])))
64 | v = VectorVariable(3, "v", "m")
65 | kd[v] = np.array([2, 3, 4])
66 | if gpkit.units:
67 | kd[v[0]] = gpkit.units("inch")
68 |
69 |
70 | TESTS = [TestKeyDict]
71 |
72 |
73 | if __name__ == "__main__": # pragma: no cover
74 | run_tests(TESTS)
75 |
--------------------------------------------------------------------------------
/gpkit/tests/t_small.py:
--------------------------------------------------------------------------------
1 | """Tests for small_classes.py and small_scripts.py"""
2 | import unittest
3 | from gpkit.small_classes import HashVector
4 | from gpkit.repr_conventions import unitstr
5 | import gpkit
6 |
7 |
8 | class TestHashVector(unittest.TestCase):
9 | """TestCase for the HashVector class"""
10 |
11 | def test_init(self):
12 | """Make sure HashVector acts like a dict"""
13 | # args and kwargs
14 | hv = HashVector([(2, 3), (1, 10)], dog='woof')
15 | self.assertTrue(isinstance(hv, dict))
16 | self.assertEqual(hv, {2: 3, 1: 10, 'dog': 'woof'})
17 | # no args
18 | self.assertEqual(HashVector(), {})
19 | # creation from dict
20 | self.assertEqual(HashVector({'x': 7}), {'x': 7})
21 |
22 | def test_neg(self):
23 | """Test negation"""
24 | hv = HashVector(x=7, y=0, z=-1)
25 | self.assertEqual(-hv, {'x': -7, 'y': 0, 'z': 1})
26 |
27 | def test_pow(self):
28 | """Test exponentiation"""
29 | hv = HashVector(x=4, y=0, z=1)
30 | self.assertEqual(hv**0.5, {'x': 2, 'y': 0, 'z': 1})
31 | with self.assertRaises(TypeError):
32 | _ = hv**hv
33 | with self.assertRaises(TypeError):
34 | _ = hv**"a"
35 |
36 | def test_mul_add(self):
37 | """Test multiplication and addition"""
38 | a = HashVector(x=1, y=7)
39 | b = HashVector()
40 | c = HashVector(x=3, z=4)
41 | # nonsense multiplication
42 | with self.assertRaises(TypeError):
43 | _ = a * set()
44 | # multiplication and addition by scalars
45 | r = a*0
46 | self.assertEqual(r, HashVector(x=0, y=0))
47 | self.assertTrue(isinstance(r, HashVector))
48 | r = a - 2
49 | self.assertEqual(r, HashVector(x=-1, y=5))
50 | self.assertTrue(isinstance(r, HashVector))
51 | with self.assertRaises(TypeError):
52 | _ = r + "a"
53 | # multiplication and addition by dicts
54 | self.assertEqual(a + b, a)
55 | self.assertEqual(a + b + c, HashVector(x=4, y=7, z=4))
56 |
57 |
58 | class TestSmallScripts(unittest.TestCase):
59 | """TestCase for gpkit.small_scripts"""
60 | def test_unitstr(self):
61 | x = gpkit.Variable("x", "ft")
62 | # pint issue 356
63 | footstrings = ("ft", "foot") # backwards compatibility with pint 0.6
64 | if gpkit.units:
65 | self.assertEqual(unitstr(gpkit.Variable("n", "count")), "count")
66 | self.assertIn(unitstr(x), footstrings)
67 | self.assertIn(unitstr(x.key), footstrings)
68 | self.assertEqual(unitstr(gpkit.Variable("y"), dimless="---"), "---")
69 | self.assertEqual(unitstr(None, dimless="--"), "--")
70 |
71 | def test_pint_366(self):
72 | # test for https://github.com/hgrecco/pint/issues/366
73 | if gpkit.units:
74 | self.assertIn(unitstr(gpkit.units("nautical_mile")),
75 | ("nmi", "nautical_mile"))
76 | self.assertEqual(gpkit.units("nautical_mile"), gpkit.units("nmi"))
77 |
78 |
79 | TESTS = [TestHashVector, TestSmallScripts]
80 |
81 |
82 | if __name__ == "__main__": # pragma: no cover
83 | # pylint: disable=wrong-import-position
84 | from gpkit.tests.helpers import run_tests
85 | run_tests(TESTS)
86 |
--------------------------------------------------------------------------------
/gpkit/tests/t_solution_array.py:
--------------------------------------------------------------------------------
1 | """Tests for SolutionArray class"""
2 | import unittest
3 | import numpy as np
4 | from gpkit import Variable, VectorVariable, Model, SignomialsEnabled
5 | import gpkit
6 | from gpkit.solution_array import var_table
7 | from gpkit.varkey import VarKey
8 | from gpkit.small_classes import Strings, Quantity
9 |
10 |
11 | class TestSolutionArray(unittest.TestCase):
12 | """Unit tests for the SolutionArray class"""
13 |
14 | def test_call(self):
15 | A = Variable('A', '-', 'Test Variable')
16 | prob = Model(A, [A >= 1])
17 | sol = prob.solve(verbosity=0)
18 | self.assertAlmostEqual(sol(A), 1.0, 8)
19 |
20 | def test_call_units(self):
21 | # test from issue541
22 | x = Variable("x", 10, "ft")
23 | y = Variable("y", "m")
24 | m = Model(y, [y >= x])
25 | sol = m.solve(verbosity=0)
26 | self.assertAlmostEqual(sol("y")/sol("x"), 1.0, 6)
27 | self.assertAlmostEqual(sol(x)/sol(y), 1.0, 6)
28 |
29 | def test_call_vector(self):
30 | n = 5
31 | x = VectorVariable(n, 'x')
32 | prob = Model(sum(x), [x >= 2.5])
33 | sol = prob.solve(verbosity=0)
34 | solx = sol(x)
35 | self.assertEqual(type(solx), Quantity)
36 | self.assertEqual(type(sol["variables"][x]), np.ndarray)
37 | self.assertEqual(solx.shape, (n,))
38 | for i in range(n):
39 | self.assertAlmostEqual(solx[i], 2.5, places=4)
40 |
41 | def test_subinto(self):
42 | Nsweep = 20
43 | Pvals = np.linspace(13, 24, Nsweep)
44 | H_max = Variable("H_max", 10, "m", "Length")
45 | A_min = Variable("A_min", 10, "m^2", "Area")
46 | P_max = Variable("P", Pvals, "m", "Perimeter")
47 | H = Variable("H", "m", "Length")
48 | W = Variable("W", "m", "Width")
49 | m = Model(12/(W*H**3),
50 | [H <= H_max,
51 | H*W >= A_min,
52 | P_max >= 2*H + 2*W])
53 | sol = m.solve(verbosity=0)
54 | Psol = sol.subinto(P_max)
55 | self.assertEqual(len(Psol), Nsweep)
56 | self.assertAlmostEqual(0*gpkit.ureg.m,
57 | np.max(np.abs(Pvals*gpkit.ureg.m - Psol)))
58 | self.assertAlmostEqual(0*gpkit.ureg.m,
59 | np.max(np.abs(Psol - sol(P_max))))
60 |
61 | def test_table(self):
62 | x = Variable('x')
63 | gp = Model(x, [x >= 12])
64 | sol = gp.solve(verbosity=0)
65 | tab = sol.table()
66 | self.assertTrue(isinstance(tab, Strings))
67 |
68 | def test_units_sub(self):
69 | # issue 809
70 | T = Variable("T", "N", "thrust")
71 | Tmin = Variable("T_{min}", "N", "minimum thrust")
72 | m = Model(T, [T >= Tmin])
73 | tminsub = 1000 * gpkit.ureg.lbf
74 | m.substitutions.update({Tmin: tminsub})
75 | sol = m.solve(verbosity=0)
76 | self.assertAlmostEqual(sol(Tmin), tminsub)
77 | self.assertFalse(
78 | "1000N" in
79 | sol.table().replace(" ", "").replace("[", "").replace("]", ""))
80 |
81 | def test_key_options(self):
82 | # issue 993
83 | x = Variable("x")
84 | y = Variable("y")
85 | with SignomialsEnabled():
86 | m = Model(y, [y + 6*x >= 13 + x**2])
87 | msol = m.localsolve(verbosity=0)
88 | spsol = m.sp().localsolve(verbosity=0) # pylint: disable=no-member
89 | gpsol = m.program.gps[-1].solve(verbosity=0)
90 | self.assertEqual(msol(x), msol("x"))
91 | self.assertEqual(spsol(x), spsol("x"))
92 | self.assertEqual(gpsol(x), gpsol("x"))
93 | self.assertEqual(msol(x), spsol(x))
94 | self.assertEqual(msol(x), gpsol(x))
95 |
96 |
97 | class TestResultsTable(unittest.TestCase):
98 | """TestCase for var_table()"""
99 |
100 | def test_nan_printing(self):
101 | """Test that solution prints when it contains nans"""
102 | x = VarKey(name='x')
103 | data = {x: np.array([np.nan, 1, 1, 1, 1])}
104 | title = "Free variables"
105 | printstr = "\n".join(var_table(data, title))
106 | self.assertTrue(" - " in printstr) # nan is printed as " - "
107 | self.assertTrue(title in printstr)
108 |
109 | def test_result_access(self):
110 | x = Variable("x")
111 | y = Variable("y")
112 | with SignomialsEnabled():
113 | sig = (y + 6*x >= 13 + x**2)
114 | m = Model(y, [sig])
115 | sol = m.localsolve(verbosity=0)
116 | self.assertTrue(all([isinstance(gp.result.table(), Strings)
117 | for gp in m.program.gps]))
118 | self.assertAlmostEqual(sol["cost"]/4.0, 1.0, 5)
119 | self.assertAlmostEqual(sol("x")/3.0, 1.0, 3)
120 |
121 | TESTS = [TestSolutionArray, TestResultsTable]
122 |
123 | if __name__ == "__main__": # pragma: no cover
124 | # pylint: disable=wrong-import-position
125 | from gpkit.tests.helpers import run_tests
126 | run_tests(TESTS)
127 |
--------------------------------------------------------------------------------
/gpkit/tests/test_repo.py:
--------------------------------------------------------------------------------
1 | "Implements tests for all external repositories."
2 | import os
3 | import sys
4 | import subprocess
5 | from time import sleep
6 | from collections import defaultdict
7 |
8 |
9 | def test_repo(repo=".", xmloutput=False):
10 | """Test repository.
11 |
12 | If no repo name given, runs in current directory.
13 | Otherwise, assumes is in directory above the repo
14 | with a shared gplibrary repository.
15 | """
16 | os.chdir(repo)
17 | settings = get_settings()
18 | print("")
19 | print("SETTINGS")
20 | print(settings)
21 | print("")
22 |
23 | if repo == "." and not os.path.isdir("gpkitmodels"):
24 | git_clone("gplibrary")
25 | pip_install("gplibrary", local=True)
26 |
27 | # install dependencies other than gplibrary
28 | if settings["pip install"]:
29 | for package in settings["pip install"].split(","):
30 | package = package.strip()
31 | pip_install(package)
32 | if os.path.isfile("setup.py"):
33 | pip_install(".")
34 |
35 | skipsolvers = None
36 | if "skipsolvers" in settings:
37 | skipsolvers = [s.strip() for s in settings["skipsolvers"].split(",")]
38 |
39 | testpy = ("from gpkit.tests.from_paths import run;"
40 | "run(xmloutput=%s, skipsolvers=%s)"
41 | % (xmloutput, skipsolvers))
42 | subprocess.call(["python", "-c", testpy])
43 | if repo != ".":
44 | os.chdir("..")
45 |
46 |
47 | def test_repos(repos=None, xmloutput=False, ingpkitmodels=False):
48 | """Get the list of external repos to test, and test.
49 |
50 | Arguments
51 | ---------
52 | xmloutput : bool
53 | True if the tests should produce xml reports
54 |
55 | ingpkitmodels : bool
56 | False if you're in the gpkitmodels directory that should be considered
57 | as the default. (overriden by repo-specific branch specifications)
58 | """
59 | if not ingpkitmodels:
60 | git_clone("gplibrary")
61 | repos_list_filename = "gplibrary"+os.sep+"EXTERNALTESTS"
62 | pip_install("gplibrary", local=True)
63 | else:
64 | print("USING LOCAL DIRECTORY AS GPKITMODELS DIRECTORY")
65 | repos_list_filename = "EXTERNALTESTS"
66 | pip_install(".", local=True)
67 | repos = [line.strip() for line in open(repos_list_filename, "r")]
68 | for repo in repos:
69 | git_clone(repo)
70 | test_repo(repo, xmloutput)
71 |
72 |
73 | def get_settings():
74 | "Gets settings from a TESTCONFIG file"
75 | settings = defaultdict(str)
76 | if os.path.isfile("TESTCONFIG"):
77 | with open("TESTCONFIG", "r") as f:
78 | for line in f:
79 | if len(line.strip().split(" : ")) > 1:
80 | key, value = line.strip().split(" : ")
81 | settings[key] = value
82 | return settings
83 |
84 |
85 | def git_clone(repo, branch="master"):
86 | "Tries several times to clone a given repository"
87 | cmd = ["git", "clone", "--depth", "1"]
88 | cmd += ["-b", branch]
89 | cmd += ["https://github.com/convexengineering/%s.git" % repo]
90 | call_and_retry(cmd)
91 |
92 |
93 | def pip_install(package, local=False):
94 | "Tries several times to install a pip package"
95 | if sys.platform == "win32":
96 | cmd = ["pip"]
97 | else:
98 | cmd = ["python", os.environ["PIP"]]
99 | cmd += ["install"]
100 | if local:
101 | cmd += ["--no-cache-dir", "--no-deps", "-e"]
102 | cmd += [package]
103 | call_and_retry(cmd)
104 |
105 |
106 | def call_and_retry(cmd, max_iterations=5, delay=5):
107 | "Tries max_iterations times (waiting d each time) to run a command"
108 | iterations = 0
109 | return_code = None
110 | print("calling", cmd)
111 | while return_code != 0 and iterations < max_iterations:
112 | iterations += 1
113 | print(" attempt", iterations)
114 | return_code = subprocess.call(cmd)
115 | sleep(delay)
116 | return return_code
117 |
--------------------------------------------------------------------------------
/gpkit/tools/__init__.py:
--------------------------------------------------------------------------------
1 | "Contains miscellaneous tools including fmincon comparison tool"
2 | from .autosweep import autosweep_1d
3 | from .tools import te_exp_minus1
4 |
--------------------------------------------------------------------------------
/gpkit/tools/tools.py:
--------------------------------------------------------------------------------
1 | """Non-application-specific convenience methods for GPkit"""
2 | import numpy as np
3 |
4 |
5 | def te_exp_minus1(posy, nterm):
6 | """Taylor expansion of e^{posy} - 1
7 |
8 | Arguments
9 | ---------
10 | posy : gpkit.Posynomial
11 | Variable or expression to exponentiate
12 | nterm : int
13 | Number of non-constant terms in resulting Taylor expansion
14 |
15 | Returns
16 | -------
17 | gpkit.Posynomial
18 | Taylor expansion of e^{posy} - 1, carried to nterm terms
19 | """
20 | res = 0
21 | factorial_denom = 1
22 | for i in range(1, nterm + 1):
23 | factorial_denom *= i
24 | res += posy**i / factorial_denom
25 | return res
26 |
27 |
28 | def te_secant(var, nterm):
29 | """Taylor expansion of secant(var).
30 |
31 | Arguments
32 | ---------
33 | var : gpkit.monomial
34 | Variable or expression argument
35 | nterm : int
36 | Number of non-constant terms in resulting Taylor expansion
37 |
38 | Returns
39 | -------
40 | gpkit.Posynomial
41 | Taylor expansion of secant(x), carried to nterm terms
42 | """
43 | # The first 12 Euler Numbers
44 | E2n = np.asarray([1.0,
45 | 5,
46 | 61,
47 | 1385,
48 | 50521,
49 | 2702765,
50 | 199360981,
51 | 19391512145,
52 | 2404879675441,
53 | 370371188237525,
54 | 69348874393137901,
55 | 15514534163557086905])
56 | if nterm > 12:
57 | n_extend = np.asarray(range(13, nterm+1))
58 | E2n_add = (8 * np.sqrt(n_extend/np.pi)
59 | * (4*n_extend/(np.pi * np.exp(1)))**(2*n_extend))
60 | E2n = np.append(E2n, E2n_add)
61 |
62 | res = 1
63 | factorial_denom = 1
64 | for i in range(1, nterm + 1):
65 | factorial_denom *= ((2*i)*(2*i-1))
66 | res = res + var**(2*i) * E2n[i-1] / factorial_denom
67 | return res
68 |
69 |
70 | def te_tangent(var, nterm):
71 | """Taylor expansion of tangent(var).
72 |
73 | Arguments
74 | ---------
75 | var : gpkit.monomial
76 | Variable or expression argument
77 | nterm : int
78 | Number of non-constant terms in resulting Taylor expansion
79 |
80 | Returns
81 | -------
82 | gpkit.Posynomial
83 | Taylor expansion of tangent(x), carried to nterm terms
84 | """
85 | if nterm > 15:
86 | raise NotImplementedError("Tangent expansion not implemented above"
87 | " 15 terms")
88 |
89 | # The first 15 Bernoulli Numbers
90 | B2n = np.asarray([1/6,
91 | -1/30,
92 | 1/42,
93 | -1/30,
94 | 5/66,
95 | -691/2730,
96 | 7/6,
97 | -3617/510,
98 | 43867/798,
99 | -174611/330,
100 | 854513/138,
101 | -236364091/2730,
102 | 8553103/6,
103 | -23749461029/870,
104 | 8615841276005/14322])
105 |
106 | res = 0
107 | factorial_denom = 1
108 | for i in range(1, nterm + 1):
109 | factorial_denom *= ((2*i)*(2*i-1))
110 | res += ((-1)**(i-1) * 2**(2*i) * (2**(2*i) - 1) *
111 | B2n[i-1] / factorial_denom * var**(2*i-1))
112 | return res
113 |
--------------------------------------------------------------------------------
/gpkit/units.py:
--------------------------------------------------------------------------------
1 | "wraps pint in gpkit monomials"
2 | import pint
3 | ureg = pint.UnitRegistry() # pylint: disable=invalid-name
4 | ureg.define("USD = [money] = $")
5 | pint.set_application_registry(ureg)
6 | Quantity = ureg.Quantity
7 | DimensionalityError = pint.DimensionalityError
8 | QTY_CACHE = {}
9 |
10 |
11 | def qty(unit):
12 | "Returns a Quantity, caching the result for future retrievals"
13 | if unit not in QTY_CACHE:
14 | QTY_CACHE[unit] = Quantity(1, unit)
15 | return QTY_CACHE[unit]
16 |
17 |
18 | class GPkitUnits:
19 | "Return Monomials instead of Quantitites"
20 | division_cache = {}
21 | multiplication_cache = {}
22 | monomial_cache = {}
23 |
24 | def __call__(self, unity):
25 | "Returns a unit Monomial, caching the result for future retrievals"
26 | from . import Monomial
27 | if unity not in self.monomial_cache:
28 | self.monomial_cache[unity] = Monomial(qty(unity))
29 | return self.monomial_cache[unity]
30 |
31 | __getattr__ = __call__
32 |
33 | def of_division(self, numerator, denominator):
34 | "Cached unit division. Requires Quantity inputs."
35 | if numerator.units is denominator.units:
36 | return 1
37 | key = (id(numerator.units), id(denominator.units))
38 | try:
39 | return self.division_cache[key]
40 | except KeyError:
41 | if numerator.units and denominator.units:
42 | conversion = numerator.units/denominator.units
43 | else:
44 | conversion = numerator.units or 1/denominator.units
45 | try:
46 | self.division_cache[key] = float(conversion)
47 | except DimensionalityError:
48 | raise DimensionalityError(numerator, denominator)
49 | return self.division_cache[key]
50 |
51 | def of_product(self, thing1, thing2):
52 | "Cached unit division. Requires united inputs."
53 | key = (thing1.units, thing2.units)
54 | try:
55 | return self.multiplication_cache[key]
56 | except KeyError:
57 | mul_units = qty((thing1*thing2).units)
58 | try:
59 | self.multiplication_cache[key] = (None, float(mul_units))
60 | except DimensionalityError:
61 | self.multiplication_cache[key] = (mul_units, None)
62 | return self.multiplication_cache[key]
63 |
64 |
65 | units = GPkitUnits()
66 |
--------------------------------------------------------------------------------
/linecount.sh:
--------------------------------------------------------------------------------
1 | pylint --rcfile .pylintrc gpkit | grep "Raw metrics" -A 14 | tail -n 13
2 | echo "Just tests"
3 | pylint --rcfile .pylintrc gpkit/tests | grep "Raw metrics" -A 14 | tail -n 13
4 |
--------------------------------------------------------------------------------
/pylint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # This means you can run the script anywhere in the repo, but not outside
4 | WORKSPACE=$(git rev-parse --show-toplevel)
5 |
6 | # Calling pylint directly will not work correcly in a virtualenv if pylint is not installed in the venv
7 | # Using python with the pylint script will always work properly in a virtualenv
8 | PYLINT=`which pylint`
9 | echo $PYLINT
10 | $PYLINT --version
11 |
12 | # Add gpkit to the python path so that pylint can import gpkit when analyzing the examples directory
13 | export PYTHONPATH=$PYTHONPATH:$WORKSPACE/gpkit/
14 |
15 | python3 $PYLINT --rcfile=$WORKSPACE/.pylintrc $@ $WORKSPACE/gpkit/
16 |
17 | python3 $PYLINT --rcfile=$WORKSPACE/.pylintrc --disable=superfluous-parens,undefined-variable,no-member,not-callable,attribute-defined-outside-init,invalid-name,too-many-locals,redefined-outer-name,wrong-import-position $@ $WORKSPACE/docs/source/examples/*.py
18 |
--------------------------------------------------------------------------------
/rtd_requirements.txt:
--------------------------------------------------------------------------------
1 | pint
2 | adce
3 |
--------------------------------------------------------------------------------
/runtests.sh:
--------------------------------------------------------------------------------
1 | cp gpkit/env/settings .
2 | sed -i '1s/.*/installed_solvers : cvxopt/' gpkit/env/settings
3 | cat gpkit/env/settings
4 | python -c "import gpkit.tests; gpkit.tests.run()" && mv settings gpkit/env
5 | rm *.pkl
6 | rm *.pgz
7 | rm solution.*
8 | rm referencesplot.*
9 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | """Standard Python setup script for gpkit"""
2 | import os
3 | from distutils.core import setup
4 |
5 |
6 | LICENSE = """The MIT License (MIT)
7 |
8 | Copyright (c) 2022 Edward Burnell
9 |
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 |
17 | The above copyright notice and this permission notice shall be included in all
18 | copies or substantial portions of the Software.
19 |
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 | SOFTWARE."""
27 |
28 | # create blank settings file to replace anything cached
29 | THIS_DIR = os.path.dirname(__file__)
30 | try:
31 | with open(os.sep.join([THIS_DIR, "gpkit", "env", "settings"]), "w") as f:
32 | f.write("installed_solvers : ")
33 | except IOError:
34 | pass
35 |
36 | # read the README file
37 | with open(os.path.join(THIS_DIR, "README.md"), encoding="utf-8") as f:
38 | LONG_DESCRIPTION = f.read()
39 |
40 | setup(
41 | name="gpkit",
42 | description="Package for defining and manipulating geometric "
43 | "programming models.",
44 | author="Edward Burnell",
45 | author_email="gpkit@mit.edu",
46 | url="https://www.github.com/convexengineering/gpkit",
47 | python_requires=">=3.5.2",
48 | install_requires=["numpy >= 1.16.4", "pint >= 0.8.1", "plotly",
49 | "scipy", "adce", "cvxopt >= 1.1.8",
50 | "matplotlib"],
51 | version="1.1.1",
52 | packages=["gpkit", "gpkit.tools", "gpkit.interactive", "gpkit.constraints",
53 | "gpkit.nomials", "gpkit.tests", "gpkit.solvers"],
54 | package_data={"gpkit": ["env/settings"]},
55 | license=LICENSE,
56 | long_description=LONG_DESCRIPTION,
57 | long_description_content_type="text/markdown",
58 | )
59 |
--------------------------------------------------------------------------------