From b7d447e5ac095343418a819db23d6555fa705ace Mon Sep 17 00:00:00 2001 From: jtheinen Date: Tue, 27 Jun 2023 16:06:25 +0200 Subject: [PATCH 1/9] Timo's api format --- docs/source/_autosummary/pycollo.backend.rst | 34 ++++++++ docs/source/_autosummary/pycollo.bounds.rst | 57 +++++++++++++ docs/source/_autosummary/pycollo.compiled.rst | 29 +++++++ .../_autosummary/pycollo.expression_graph.rst | 36 +++++++++ docs/source/_autosummary/pycollo.guess.rst | 37 +++++++++ .../source/_autosummary/pycollo.iteration.rst | 31 ++++++++ docs/source/_autosummary/pycollo.mesh.rst | 30 +++++++ .../_autosummary/pycollo.mesh_refinement.rst | 30 +++++++ docs/source/_autosummary/pycollo.nlp.rst | 37 +++++++++ docs/source/_autosummary/pycollo.node.rst | 36 +++++++++ docs/source/_autosummary/pycollo.numbafy.rst | 31 ++++++++ .../_autosummary/pycollo.numbafy_hessian.rst | 30 +++++++ .../_autosummary/pycollo.operations.rst | 79 +++++++++++++++++++ .../pycollo.optimal_control_problem.rst | 36 +++++++++ docs/source/_autosummary/pycollo.phase.rst | 29 +++++++ .../_autosummary/pycollo.quadrature.rst | 29 +++++++ docs/source/_autosummary/pycollo.rst | 55 +++++++++++++ docs/source/_autosummary/pycollo.scaling.rst | 43 ++++++++++ docs/source/_autosummary/pycollo.settings.rst | 29 +++++++ .../pycollo.solution.casadi_solution.rst | 29 +++++++ .../pycollo.solution.pycollo_solution.rst | 23 ++++++ docs/source/_autosummary/pycollo.solution.rst | 35 ++++++++ .../pycollo.solution.solution_abc.rst | 32 ++++++++ .../pycollo.solution.sympy_solution.rst | 23 ++++++ docs/source/_autosummary/pycollo.sparse.rst | 29 +++++++ docs/source/_autosummary/pycollo.typing.rst | 33 ++++++++ docs/source/_autosummary/pycollo.utils.rst | 51 ++++++++++++ docs/source/_autosummary/pycollo.version.rst | 23 ++++++ docs/source/_autosummary/pycollo.vis.plot.rst | 34 ++++++++ docs/source/_autosummary/pycollo.vis.rst | 31 ++++++++ docs/source/_templates/autosummary/base.rst | 8 ++ docs/source/_templates/autosummary/class.rst | 32 ++++++++ docs/source/_templates/autosummary/module.rst | 74 +++++++++++++++++ docs/source/api_reference.rst | 13 +++ docs/source/conf.py | 16 +++- docs/source/index.rst | 2 +- 36 files changed, 1203 insertions(+), 3 deletions(-) create mode 100644 docs/source/_autosummary/pycollo.backend.rst create mode 100644 docs/source/_autosummary/pycollo.bounds.rst create mode 100644 docs/source/_autosummary/pycollo.compiled.rst create mode 100644 docs/source/_autosummary/pycollo.expression_graph.rst create mode 100644 docs/source/_autosummary/pycollo.guess.rst create mode 100644 docs/source/_autosummary/pycollo.iteration.rst create mode 100644 docs/source/_autosummary/pycollo.mesh.rst create mode 100644 docs/source/_autosummary/pycollo.mesh_refinement.rst create mode 100644 docs/source/_autosummary/pycollo.nlp.rst create mode 100644 docs/source/_autosummary/pycollo.node.rst create mode 100644 docs/source/_autosummary/pycollo.numbafy.rst create mode 100644 docs/source/_autosummary/pycollo.numbafy_hessian.rst create mode 100644 docs/source/_autosummary/pycollo.operations.rst create mode 100644 docs/source/_autosummary/pycollo.optimal_control_problem.rst create mode 100644 docs/source/_autosummary/pycollo.phase.rst create mode 100644 docs/source/_autosummary/pycollo.quadrature.rst create mode 100644 docs/source/_autosummary/pycollo.rst create mode 100644 docs/source/_autosummary/pycollo.scaling.rst create mode 100644 docs/source/_autosummary/pycollo.settings.rst create mode 100644 docs/source/_autosummary/pycollo.solution.casadi_solution.rst create mode 100644 docs/source/_autosummary/pycollo.solution.pycollo_solution.rst create mode 100644 docs/source/_autosummary/pycollo.solution.rst create mode 100644 docs/source/_autosummary/pycollo.solution.solution_abc.rst create mode 100644 docs/source/_autosummary/pycollo.solution.sympy_solution.rst create mode 100644 docs/source/_autosummary/pycollo.sparse.rst create mode 100644 docs/source/_autosummary/pycollo.typing.rst create mode 100644 docs/source/_autosummary/pycollo.utils.rst create mode 100644 docs/source/_autosummary/pycollo.version.rst create mode 100644 docs/source/_autosummary/pycollo.vis.plot.rst create mode 100644 docs/source/_autosummary/pycollo.vis.rst create mode 100644 docs/source/_templates/autosummary/base.rst create mode 100644 docs/source/_templates/autosummary/class.rst create mode 100644 docs/source/_templates/autosummary/module.rst create mode 100644 docs/source/api_reference.rst diff --git a/docs/source/_autosummary/pycollo.backend.rst b/docs/source/_autosummary/pycollo.backend.rst new file mode 100644 index 0000000..ccea0a5 --- /dev/null +++ b/docs/source/_autosummary/pycollo.backend.rst @@ -0,0 +1,34 @@ +pycollo.backend +=============== + +.. automodule:: pycollo.backend + + + + + + + + + + + + .. rubric:: Classes + + .. autosummary:: + + BackendABC + Casadi + Hsad + Pycollo + PycolloPhaseData + Sympy + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.bounds.rst b/docs/source/_autosummary/pycollo.bounds.rst new file mode 100644 index 0000000..d725864 --- /dev/null +++ b/docs/source/_autosummary/pycollo.bounds.rst @@ -0,0 +1,57 @@ +pycollo.bounds +============== + +.. automodule:: pycollo.bounds + + + + .. rubric:: Module Attributes + + .. autosummary:: + + PhaseInfo + BoundsInfo + + + + + + .. rubric:: Functions + + .. autosummary:: + + as_lower_upper_pair + check_lower_against_upper + check_lower_less_than_upper + check_lower_same_as_upper_to_tol + check_user_bound_missing + extract_variables_to_constants + get_bound_as_number + process_iterable_bounds_instance + process_mapping_bounds_instance + process_none_bounds_instance + process_single_type_of_values + + + + + + .. rubric:: Classes + + .. autosummary:: + + Bounds + BoundsABC + BoundsInfo + EndpointBounds + PhaseBounds + PhaseInfo + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.compiled.rst b/docs/source/_autosummary/pycollo.compiled.rst new file mode 100644 index 0000000..ae03216 --- /dev/null +++ b/docs/source/_autosummary/pycollo.compiled.rst @@ -0,0 +1,29 @@ +pycollo.compiled +================ + +.. automodule:: pycollo.compiled + + + + + + + + + + + + .. rubric:: Classes + + .. autosummary:: + + CompiledFunctions + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.expression_graph.rst b/docs/source/_autosummary/pycollo.expression_graph.rst new file mode 100644 index 0000000..c3a3a08 --- /dev/null +++ b/docs/source/_autosummary/pycollo.expression_graph.rst @@ -0,0 +1,36 @@ +pycollo.expression\_graph +========================= + +.. automodule:: pycollo.expression_graph + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + cout + kill + + + + + + .. rubric:: Classes + + .. autosummary:: + + ExpressionGraph + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.guess.rst b/docs/source/_autosummary/pycollo.guess.rst new file mode 100644 index 0000000..803cc31 --- /dev/null +++ b/docs/source/_autosummary/pycollo.guess.rst @@ -0,0 +1,37 @@ +pycollo.guess +============= + +.. automodule:: pycollo.guess + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + assert_increasing + + + + + + .. rubric:: Classes + + .. autosummary:: + + EndpointGuess + Guess + PhaseGuess + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.iteration.rst b/docs/source/_autosummary/pycollo.iteration.rst new file mode 100644 index 0000000..5c7fc2b --- /dev/null +++ b/docs/source/_autosummary/pycollo.iteration.rst @@ -0,0 +1,31 @@ +pycollo.iteration +================= + +.. automodule:: pycollo.iteration + + + + + + + + + + + + .. rubric:: Classes + + .. autosummary:: + + Iteration + IterationOld + MeshIterationResult + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.mesh.rst b/docs/source/_autosummary/pycollo.mesh.rst new file mode 100644 index 0000000..ce343bc --- /dev/null +++ b/docs/source/_autosummary/pycollo.mesh.rst @@ -0,0 +1,30 @@ +pycollo.mesh +============ + +.. automodule:: pycollo.mesh + + + + + + + + + + + + .. rubric:: Classes + + .. autosummary:: + + Mesh + PhaseMesh + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.mesh_refinement.rst b/docs/source/_autosummary/pycollo.mesh_refinement.rst new file mode 100644 index 0000000..07fb487 --- /dev/null +++ b/docs/source/_autosummary/pycollo.mesh_refinement.rst @@ -0,0 +1,30 @@ +pycollo.mesh\_refinement +======================== + +.. automodule:: pycollo.mesh_refinement + + + + + + + + + + + + .. rubric:: Classes + + .. autosummary:: + + MeshRefinementABC + PattersonRaoMeshRefinement + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.nlp.rst b/docs/source/_autosummary/pycollo.nlp.rst new file mode 100644 index 0000000..1975d03 --- /dev/null +++ b/docs/source/_autosummary/pycollo.nlp.rst @@ -0,0 +1,37 @@ +pycollo.nlp +=========== + +.. automodule:: pycollo.nlp + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + initialise_nlp_backend + + + + + + .. rubric:: Classes + + .. autosummary:: + + IPOPTProblem + NLPProblem + NLPSettings + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.node.rst b/docs/source/_autosummary/pycollo.node.rst new file mode 100644 index 0000000..853223d --- /dev/null +++ b/docs/source/_autosummary/pycollo.node.rst @@ -0,0 +1,36 @@ +pycollo.node +============ + +.. automodule:: pycollo.node + + + + + + + + + + + + .. rubric:: Classes + + .. autosummary:: + + Cached + ConstantNode + ExpressionNodeABC + IntermediateNode + Node + NumberNode + RootNode + VariableNode + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.numbafy.rst b/docs/source/_autosummary/pycollo.numbafy.rst new file mode 100644 index 0000000..15dc568 --- /dev/null +++ b/docs/source/_autosummary/pycollo.numbafy.rst @@ -0,0 +1,31 @@ +pycollo.numbafy +=============== + +.. automodule:: pycollo.numbafy + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + cout + kill + numbafy + + + + + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.numbafy_hessian.rst b/docs/source/_autosummary/pycollo.numbafy_hessian.rst new file mode 100644 index 0000000..0780ca6 --- /dev/null +++ b/docs/source/_autosummary/pycollo.numbafy_hessian.rst @@ -0,0 +1,30 @@ +pycollo.numbafy\_hessian +======================== + +.. automodule:: pycollo.numbafy_hessian + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + numbafy_continuous_hessian + numbafy_endpoint_hessian + + + + + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.operations.rst b/docs/source/_autosummary/pycollo.operations.rst new file mode 100644 index 0000000..b7ca2e5 --- /dev/null +++ b/docs/source/_autosummary/pycollo.operations.rst @@ -0,0 +1,79 @@ +pycollo.operations +================== + +.. automodule:: pycollo.operations + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + determine_operation + is_sympy_log + is_sympy_mul + is_sympy_pow + is_sympy_sym + + + + + + .. rubric:: Classes + + .. autosummary:: + + PycolloAdd + PycolloArccos + PycolloArccosec + PycolloArccosech + PycolloArccosh + PycolloArccot + PycolloArccoth + PycolloArcsec + PycolloArcsech + PycolloArcsin + PycolloArcsinh + PycolloArctan + PycolloArctanh + PycolloBinaryMul + PycolloCos + PycolloCosec + PycolloCosech + PycolloCosh + PycolloCot + PycolloCoth + PycolloCube + PycolloCuberoot + PycolloExp + PycolloLn + PycolloLog + PycolloMul + PycolloNullOp + PycolloOp + PycolloPow + PycolloReciprocal + PycolloSec + PycolloSech + PycolloSin + PycolloSinh + PycolloSquare + PycolloSquareReciprocal + PycolloSquareroot + PycolloTan + PycolloTanh + PycolloTernaryMul + PycolloUnsetOp + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.optimal_control_problem.rst b/docs/source/_autosummary/pycollo.optimal_control_problem.rst new file mode 100644 index 0000000..57ae085 --- /dev/null +++ b/docs/source/_autosummary/pycollo.optimal_control_problem.rst @@ -0,0 +1,36 @@ +pycollo.optimal\_control\_problem +================================= + +.. automodule:: pycollo.optimal_control_problem + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + cout + kill + + + + + + .. rubric:: Classes + + .. autosummary:: + + OptimalControlProblem + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.phase.rst b/docs/source/_autosummary/pycollo.phase.rst new file mode 100644 index 0000000..f4087be --- /dev/null +++ b/docs/source/_autosummary/pycollo.phase.rst @@ -0,0 +1,29 @@ +pycollo.phase +============= + +.. automodule:: pycollo.phase + + + + + + + + + + + + .. rubric:: Classes + + .. autosummary:: + + Phase + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.quadrature.rst b/docs/source/_autosummary/pycollo.quadrature.rst new file mode 100644 index 0000000..a5e805c --- /dev/null +++ b/docs/source/_autosummary/pycollo.quadrature.rst @@ -0,0 +1,29 @@ +pycollo.quadrature +================== + +.. automodule:: pycollo.quadrature + + + + + + + + + + + + .. rubric:: Classes + + .. autosummary:: + + Quadrature + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.rst b/docs/source/_autosummary/pycollo.rst new file mode 100644 index 0000000..1b3b94f --- /dev/null +++ b/docs/source/_autosummary/pycollo.rst @@ -0,0 +1,55 @@ +pycollo +======= + +.. automodule:: pycollo + + + + + + + + + + + + + + + + + + + +.. rubric:: Modules + +.. autosummary:: + :toctree: + :recursive: + + pycollo.backend + pycollo.bounds + pycollo.compiled + pycollo.expression_graph + pycollo.guess + pycollo.iteration + pycollo.mesh + pycollo.mesh_refinement + pycollo.nlp + pycollo.node + pycollo.numbafy + pycollo.numbafy_hessian + pycollo.operations + pycollo.optimal_control_problem + pycollo.phase + pycollo.quadrature + pycollo.scaling + pycollo.settings + pycollo.solution + pycollo.sparse + pycollo.sparsity + pycollo.typing + pycollo.utils + pycollo.version + pycollo.vis + diff --git a/docs/source/_autosummary/pycollo.scaling.rst b/docs/source/_autosummary/pycollo.scaling.rst new file mode 100644 index 0000000..d528196 --- /dev/null +++ b/docs/source/_autosummary/pycollo.scaling.rst @@ -0,0 +1,43 @@ +pycollo.scaling +=============== + +.. automodule:: pycollo.scaling + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + np_print + + + + + + .. rubric:: Classes + + .. autosummary:: + + CasadiIterationScaling + EndpointScaling + HsadIterationScaling + IterationScaling + PhaseScaling + PycolloIterationScaling + Scaling + ScalingABC + SympyIterationScaling + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.settings.rst b/docs/source/_autosummary/pycollo.settings.rst new file mode 100644 index 0000000..36b5556 --- /dev/null +++ b/docs/source/_autosummary/pycollo.settings.rst @@ -0,0 +1,29 @@ +pycollo.settings +================ + +.. automodule:: pycollo.settings + + + + + + + + + + + + .. rubric:: Classes + + .. autosummary:: + + Settings + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.solution.casadi_solution.rst b/docs/source/_autosummary/pycollo.solution.casadi_solution.rst new file mode 100644 index 0000000..581960e --- /dev/null +++ b/docs/source/_autosummary/pycollo.solution.casadi_solution.rst @@ -0,0 +1,29 @@ +pycollo.solution.casadi\_solution +================================= + +.. automodule:: pycollo.solution.casadi_solution + + + + + + + + + + + + .. rubric:: Classes + + .. autosummary:: + + CasadiSolution + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.solution.pycollo_solution.rst b/docs/source/_autosummary/pycollo.solution.pycollo_solution.rst new file mode 100644 index 0000000..d2d75dd --- /dev/null +++ b/docs/source/_autosummary/pycollo.solution.pycollo_solution.rst @@ -0,0 +1,23 @@ +pycollo.solution.pycollo\_solution +================================== + +.. automodule:: pycollo.solution.pycollo_solution + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.solution.rst b/docs/source/_autosummary/pycollo.solution.rst new file mode 100644 index 0000000..01726b3 --- /dev/null +++ b/docs/source/_autosummary/pycollo.solution.rst @@ -0,0 +1,35 @@ +pycollo.solution +================ + +.. automodule:: pycollo.solution + + + + + + + + + + + + + + + + + + + +.. rubric:: Modules + +.. autosummary:: + :toctree: + :recursive: + + pycollo.solution.casadi_solution + pycollo.solution.hsad_solution + pycollo.solution.pycollo_solution + pycollo.solution.solution_abc + pycollo.solution.sympy_solution + diff --git a/docs/source/_autosummary/pycollo.solution.solution_abc.rst b/docs/source/_autosummary/pycollo.solution.solution_abc.rst new file mode 100644 index 0000000..fa78dbc --- /dev/null +++ b/docs/source/_autosummary/pycollo.solution.solution_abc.rst @@ -0,0 +1,32 @@ +pycollo.solution.solution\_abc +============================== + +.. automodule:: pycollo.solution.solution_abc + + + + + + + + + + + + .. rubric:: Classes + + .. autosummary:: + + NlpResult + PhaseSolutionData + Polys + SolutionABC + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.solution.sympy_solution.rst b/docs/source/_autosummary/pycollo.solution.sympy_solution.rst new file mode 100644 index 0000000..9863ee0 --- /dev/null +++ b/docs/source/_autosummary/pycollo.solution.sympy_solution.rst @@ -0,0 +1,23 @@ +pycollo.solution.sympy\_solution +================================ + +.. automodule:: pycollo.solution.sympy_solution + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.sparse.rst b/docs/source/_autosummary/pycollo.sparse.rst new file mode 100644 index 0000000..24fac32 --- /dev/null +++ b/docs/source/_autosummary/pycollo.sparse.rst @@ -0,0 +1,29 @@ +pycollo.sparse +============== + +.. automodule:: pycollo.sparse + + + + + + + + + + + + .. rubric:: Classes + + .. autosummary:: + + SparseCOOMatrix + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.typing.rst b/docs/source/_autosummary/pycollo.typing.rst new file mode 100644 index 0000000..b2aa51b --- /dev/null +++ b/docs/source/_autosummary/pycollo.typing.rst @@ -0,0 +1,33 @@ +pycollo.typing +============== + +.. automodule:: pycollo.typing + + + + .. rubric:: Module Attributes + + .. autosummary:: + + SympyType + OptionalBoundsType + OptionalExprsType + OptionalSymsType + TupleSymsType + + + + + + + + + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.utils.rst b/docs/source/_autosummary/pycollo.utils.rst new file mode 100644 index 0000000..78debe9 --- /dev/null +++ b/docs/source/_autosummary/pycollo.utils.rst @@ -0,0 +1,51 @@ +pycollo.utils +============= + +.. automodule:: pycollo.utils + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + casadi_substitute + check_sym_name_clash + console_out + dict_merge + fast_sympify + format_as_named_tuple + format_case + format_for_output + format_multiple_items_for_output + format_time + needed_to_tuple + parse_arg_type + parse_parameter_var + symbol_name + symbol_primitives + sympy_to_casadi + + + + + + .. rubric:: Classes + + .. autosummary:: + + cachedproperty + dcdxInfo + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.version.rst b/docs/source/_autosummary/pycollo.version.rst new file mode 100644 index 0000000..d199a26 --- /dev/null +++ b/docs/source/_autosummary/pycollo.version.rst @@ -0,0 +1,23 @@ +pycollo.version +=============== + +.. automodule:: pycollo.version + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.vis.plot.rst b/docs/source/_autosummary/pycollo.vis.plot.rst new file mode 100644 index 0000000..5fefb3d --- /dev/null +++ b/docs/source/_autosummary/pycollo.vis.plot.rst @@ -0,0 +1,34 @@ +pycollo.vis.plot +================ + +.. automodule:: pycollo.vis.plot + + + + + + + + .. rubric:: Functions + + .. autosummary:: + + interpolate_x_solution + plot_buffered_renders + plot_mesh + plot_phase_mesh + plot_solution + render_x_solution + + + + + + + + + + + + + diff --git a/docs/source/_autosummary/pycollo.vis.rst b/docs/source/_autosummary/pycollo.vis.rst new file mode 100644 index 0000000..5788363 --- /dev/null +++ b/docs/source/_autosummary/pycollo.vis.rst @@ -0,0 +1,31 @@ +pycollo.vis +=========== + +.. automodule:: pycollo.vis + + + + + + + + + + + + + + + + + + + +.. rubric:: Modules + +.. autosummary:: + :toctree: + :recursive: + + pycollo.vis.plot + diff --git a/docs/source/_templates/autosummary/base.rst b/docs/source/_templates/autosummary/base.rst new file mode 100644 index 0000000..073fe3f --- /dev/null +++ b/docs/source/_templates/autosummary/base.rst @@ -0,0 +1,8 @@ +.. + base.rst + +{{ fullname | escape | underline }} + +.. currentmodule:: {{ module }} + +.. auto{{ objtype }}:: {{ objname }} diff --git a/docs/source/_templates/autosummary/class.rst b/docs/source/_templates/autosummary/class.rst new file mode 100644 index 0000000..999cd90 --- /dev/null +++ b/docs/source/_templates/autosummary/class.rst @@ -0,0 +1,32 @@ +.. + class.rst + +{{ fullname | escape | underline }} + +.. currentmodule:: {{ module }} + +.. autoclass:: {{ objname }} + :members: + :show-inheritance: + :inherited-members: + :special-members: + + {% block methods %} + {% if methods %} + .. rubric:: {{ _('Attributes') }} + + .. autosummary:: + {% for item in attributes %} + ~{{ name }}.{{ item }} + {%- endfor %} + {% endif %} + {% if methods %} + .. rubric:: {{ _('Methods') }} + + .. autosummary:: + :nosignatures: + {% for item in methods %} + ~{{ name }}.{{ item }} + {%- endfor %} + {% endif %} + {% endblock %} diff --git a/docs/source/_templates/autosummary/module.rst b/docs/source/_templates/autosummary/module.rst new file mode 100644 index 0000000..818f2e9 --- /dev/null +++ b/docs/source/_templates/autosummary/module.rst @@ -0,0 +1,74 @@ +.. + module.rst + +{{ fullname | escape | underline }} + +.. automodule:: {{ fullname }} + + {% block attributes %} + {% if attributes %} + .. rubric:: Module Attributes + + .. autosummary:: + :toctree: + {% for item in attributes %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block functions %} + {% if functions %} + .. rubric:: {{ _('Functions') }} + + .. autosummary:: + :toctree: + :nosignatures: + :template: autosummary/base.rst + {% for item in functions %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block classes %} + {% if classes %} + .. rubric:: {{ _('Classes') }} + + .. autosummary:: + :toctree: + :nosignatures: + :template: autosummary/class.rst + {% for item in classes %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block exceptions %} + {% if exceptions %} + .. rubric:: {{ _('Exceptions') }} + + .. autosummary:: + :toctree: + :nosignatures: + :template: autosummary/base.rst + {% for item in exceptions %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + +{% block modules %} + {% if modules %} + .. rubric:: Modules + + .. autosummary:: + :toctree: + :template: autosummary/module.rst + :recursive: + {% for item in modules %} + {{ item }} + {%- endfor %} + {% endif %} +{% endblock %} diff --git a/docs/source/api_reference.rst b/docs/source/api_reference.rst new file mode 100644 index 0000000..f6de39c --- /dev/null +++ b/docs/source/api_reference.rst @@ -0,0 +1,13 @@ +.. _api_reference: + +============= +API Reference +============= + +.. autosummary:: + :toctree: _autosummary + :recursive: + + pycollo.optimal_control_problem + + diff --git a/docs/source/conf.py b/docs/source/conf.py index b925c33..6efde75 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -5,6 +5,10 @@ # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information +import os +import sys + +sys.path.insert(0, os.path.abspath("..")) project = "Pycollo" copyright = "2023, Sam Brockie" # noqa: A001 @@ -17,12 +21,15 @@ "sphinx.ext.napoleon", "sphinx.ext.intersphinx", "sphinx.ext.autodoc", + "sphinx.ext.autosummary", "sphinx.ext.mathjax", "sphinx.ext.viewcode", ] -templates_path = ["_templates"] -exclude_patterns = [] +templates_path = ["source/_templates"] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] + +napoleon_numpy_docstring = True intersphinx_mapping = { "cyipopt": ("https://cyipopt.readthedocs.io/en/stable/", None), @@ -48,4 +55,9 @@ "master_doc": False, # Doesn't show duplicate title "nav_links": [{"href": "index", "internal": True, "title": "Home"}], } + +html_sidebars = { + "**": ["logo-text.html", "globaltoc.html", "localtoc.html", "searchbox.html"] +} + html_static_path = ["_static"] diff --git a/docs/source/index.rst b/docs/source/index.rst index 43bafcc..515436f 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -10,7 +10,7 @@ Welcome to Pycollo's documentation! :maxdepth: 2 :caption: Contents: - + api_reference Indices and tables ================== From 0593d9f7352deff61d21691400900462c55466b6 Mon Sep 17 00:00:00 2001 From: jtheinen Date: Wed, 28 Jun 2023 11:17:24 +0200 Subject: [PATCH 2/9] API ref structure + tidying OCP --- _docs/Makefile | 20 +++++ {docs => _docs}/requirements.txt | 0 .../source/_templates/autosummary/base.rst | 0 .../source/_templates/autosummary/class.rst | 0 .../source/_templates/autosummary/module.rst | 0 {docs => _docs}/source/api_reference.rst | 2 +- {docs => _docs}/source/conf.py | 18 +---- {docs => _docs}/source/index.rst | 0 docs/Makefile | 40 +++++----- ..._control_problem.OptimalControlProblem.rst | 54 +++++++++++++ .../pycollo.optimal_control_problem.cout.rst | 9 +++ .../pycollo.optimal_control_problem.kill.rst | 9 +++ .../pycollo.optimal_control_problem.rst | 45 +++++++++++ docs/_autosummary/pycollo.phase.Phase.rst | 56 +++++++++++++ docs/_autosummary/pycollo.phase.rst | 35 ++++++++ docs/_templates/autosummary/base.rst | 8 ++ docs/_templates/autosummary/class.rst | 32 ++++++++ docs/_templates/autosummary/module.rst | 74 +++++++++++++++++ docs/api_reference.rst | 13 +++ docs/conf.py | 66 ++++++++++++++++ docs/index.rst | 10 +++ docs/make.bat | 35 ++++++++ docs/source/_autosummary/pycollo.backend.rst | 34 -------- docs/source/_autosummary/pycollo.bounds.rst | 57 ------------- docs/source/_autosummary/pycollo.compiled.rst | 29 ------- .../_autosummary/pycollo.expression_graph.rst | 36 --------- docs/source/_autosummary/pycollo.guess.rst | 37 --------- .../source/_autosummary/pycollo.iteration.rst | 31 -------- docs/source/_autosummary/pycollo.mesh.rst | 30 ------- .../_autosummary/pycollo.mesh_refinement.rst | 30 ------- docs/source/_autosummary/pycollo.nlp.rst | 37 --------- docs/source/_autosummary/pycollo.node.rst | 36 --------- docs/source/_autosummary/pycollo.numbafy.rst | 31 -------- .../_autosummary/pycollo.numbafy_hessian.rst | 30 ------- .../_autosummary/pycollo.operations.rst | 79 ------------------- .../pycollo.optimal_control_problem.rst | 36 --------- docs/source/_autosummary/pycollo.phase.rst | 29 ------- .../_autosummary/pycollo.quadrature.rst | 29 ------- docs/source/_autosummary/pycollo.rst | 55 ------------- docs/source/_autosummary/pycollo.scaling.rst | 43 ---------- docs/source/_autosummary/pycollo.settings.rst | 29 ------- .../pycollo.solution.casadi_solution.rst | 29 ------- .../pycollo.solution.pycollo_solution.rst | 23 ------ docs/source/_autosummary/pycollo.solution.rst | 35 -------- .../pycollo.solution.solution_abc.rst | 32 -------- .../pycollo.solution.sympy_solution.rst | 23 ------ docs/source/_autosummary/pycollo.sparse.rst | 29 ------- docs/source/_autosummary/pycollo.typing.rst | 33 -------- docs/source/_autosummary/pycollo.utils.rst | 51 ------------ docs/source/_autosummary/pycollo.version.rst | 23 ------ docs/source/_autosummary/pycollo.vis.plot.rst | 34 -------- docs/source/_autosummary/pycollo.vis.rst | 31 -------- pycollo/optimal_control_problem.py | 50 ++++++------ 53 files changed, 511 insertions(+), 1126 deletions(-) create mode 100644 _docs/Makefile rename {docs => _docs}/requirements.txt (100%) rename {docs => _docs}/source/_templates/autosummary/base.rst (100%) rename {docs => _docs}/source/_templates/autosummary/class.rst (100%) rename {docs => _docs}/source/_templates/autosummary/module.rst (100%) rename {docs => _docs}/source/api_reference.rst (78%) rename {docs => _docs}/source/conf.py (71%) rename {docs => _docs}/source/index.rst (100%) create mode 100644 docs/_autosummary/pycollo.optimal_control_problem.OptimalControlProblem.rst create mode 100644 docs/_autosummary/pycollo.optimal_control_problem.cout.rst create mode 100644 docs/_autosummary/pycollo.optimal_control_problem.kill.rst create mode 100644 docs/_autosummary/pycollo.optimal_control_problem.rst create mode 100644 docs/_autosummary/pycollo.phase.Phase.rst create mode 100644 docs/_autosummary/pycollo.phase.rst create mode 100644 docs/_templates/autosummary/base.rst create mode 100644 docs/_templates/autosummary/class.rst create mode 100644 docs/_templates/autosummary/module.rst create mode 100644 docs/api_reference.rst create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/make.bat delete mode 100644 docs/source/_autosummary/pycollo.backend.rst delete mode 100644 docs/source/_autosummary/pycollo.bounds.rst delete mode 100644 docs/source/_autosummary/pycollo.compiled.rst delete mode 100644 docs/source/_autosummary/pycollo.expression_graph.rst delete mode 100644 docs/source/_autosummary/pycollo.guess.rst delete mode 100644 docs/source/_autosummary/pycollo.iteration.rst delete mode 100644 docs/source/_autosummary/pycollo.mesh.rst delete mode 100644 docs/source/_autosummary/pycollo.mesh_refinement.rst delete mode 100644 docs/source/_autosummary/pycollo.nlp.rst delete mode 100644 docs/source/_autosummary/pycollo.node.rst delete mode 100644 docs/source/_autosummary/pycollo.numbafy.rst delete mode 100644 docs/source/_autosummary/pycollo.numbafy_hessian.rst delete mode 100644 docs/source/_autosummary/pycollo.operations.rst delete mode 100644 docs/source/_autosummary/pycollo.optimal_control_problem.rst delete mode 100644 docs/source/_autosummary/pycollo.phase.rst delete mode 100644 docs/source/_autosummary/pycollo.quadrature.rst delete mode 100644 docs/source/_autosummary/pycollo.rst delete mode 100644 docs/source/_autosummary/pycollo.scaling.rst delete mode 100644 docs/source/_autosummary/pycollo.settings.rst delete mode 100644 docs/source/_autosummary/pycollo.solution.casadi_solution.rst delete mode 100644 docs/source/_autosummary/pycollo.solution.pycollo_solution.rst delete mode 100644 docs/source/_autosummary/pycollo.solution.rst delete mode 100644 docs/source/_autosummary/pycollo.solution.solution_abc.rst delete mode 100644 docs/source/_autosummary/pycollo.solution.sympy_solution.rst delete mode 100644 docs/source/_autosummary/pycollo.sparse.rst delete mode 100644 docs/source/_autosummary/pycollo.typing.rst delete mode 100644 docs/source/_autosummary/pycollo.utils.rst delete mode 100644 docs/source/_autosummary/pycollo.version.rst delete mode 100644 docs/source/_autosummary/pycollo.vis.plot.rst delete mode 100644 docs/source/_autosummary/pycollo.vis.rst diff --git a/_docs/Makefile b/_docs/Makefile new file mode 100644 index 0000000..d0c3cbf --- /dev/null +++ b/_docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/requirements.txt b/_docs/requirements.txt similarity index 100% rename from docs/requirements.txt rename to _docs/requirements.txt diff --git a/docs/source/_templates/autosummary/base.rst b/_docs/source/_templates/autosummary/base.rst similarity index 100% rename from docs/source/_templates/autosummary/base.rst rename to _docs/source/_templates/autosummary/base.rst diff --git a/docs/source/_templates/autosummary/class.rst b/_docs/source/_templates/autosummary/class.rst similarity index 100% rename from docs/source/_templates/autosummary/class.rst rename to _docs/source/_templates/autosummary/class.rst diff --git a/docs/source/_templates/autosummary/module.rst b/_docs/source/_templates/autosummary/module.rst similarity index 100% rename from docs/source/_templates/autosummary/module.rst rename to _docs/source/_templates/autosummary/module.rst diff --git a/docs/source/api_reference.rst b/_docs/source/api_reference.rst similarity index 78% rename from docs/source/api_reference.rst rename to _docs/source/api_reference.rst index f6de39c..8cd4bc6 100644 --- a/docs/source/api_reference.rst +++ b/_docs/source/api_reference.rst @@ -8,6 +8,6 @@ API Reference :toctree: _autosummary :recursive: - pycollo.optimal_control_problem + ../pycollo diff --git a/docs/source/conf.py b/_docs/source/conf.py similarity index 71% rename from docs/source/conf.py rename to _docs/source/conf.py index 6efde75..ccfe55e 100644 --- a/docs/source/conf.py +++ b/_docs/source/conf.py @@ -27,7 +27,7 @@ ] templates_path = ["source/_templates"] -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store","_templates"] napoleon_numpy_docstring = True @@ -44,20 +44,6 @@ # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output -html_theme = "sphinx_material" -html_theme_options = { - "base_url": "https://brocksam.github.io/pycollo/", - "color_primary": "teal", - "color_accent": "deep-orange", # hover color of hyperlinks - "repo_name": "Pycollo", - "repo_url": "https://github.com/brocksam/pycollo/", - "logo_icon": "", - "master_doc": False, # Doesn't show duplicate title - "nav_links": [{"href": "index", "internal": True, "title": "Home"}], -} - -html_sidebars = { - "**": ["logo-text.html", "globaltoc.html", "localtoc.html", "searchbox.html"] -} +html_theme = "furo" html_static_path = ["_static"] diff --git a/docs/source/index.rst b/_docs/source/index.rst similarity index 100% rename from docs/source/index.rst rename to _docs/source/index.rst diff --git a/docs/Makefile b/docs/Makefile index d0c3cbf..73a28c7 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,20 +1,20 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = source -BUILDDIR = build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/_autosummary/pycollo.optimal_control_problem.OptimalControlProblem.rst b/docs/_autosummary/pycollo.optimal_control_problem.OptimalControlProblem.rst new file mode 100644 index 0000000..e74755c --- /dev/null +++ b/docs/_autosummary/pycollo.optimal_control_problem.OptimalControlProblem.rst @@ -0,0 +1,54 @@ +.. + class.rst + +pycollo.optimal\_control\_problem.OptimalControlProblem +======================================================= + +.. currentmodule:: pycollo.optimal_control_problem + +.. autoclass:: OptimalControlProblem + :members: + :show-inheritance: + :inherited-members: + :special-members: + + + + .. rubric:: Attributes + + .. autosummary:: + + ~OptimalControlProblem.auxiliary_data + ~OptimalControlProblem.bounds + ~OptimalControlProblem.endpoint_constraints + ~OptimalControlProblem.guess + ~OptimalControlProblem.mesh_iterations + ~OptimalControlProblem.name + ~OptimalControlProblem.num_mesh_iterations + ~OptimalControlProblem.number_endpoint_constraints + ~OptimalControlProblem.number_parameter_variables + ~OptimalControlProblem.number_phases + ~OptimalControlProblem.objective_function + ~OptimalControlProblem.parameter_variables + ~OptimalControlProblem.phases + ~OptimalControlProblem.scaling + ~OptimalControlProblem.settings + ~OptimalControlProblem.solution + ~OptimalControlProblem.time_symbol + + + .. rubric:: Methods + + .. autosummary:: + :nosignatures: + + ~OptimalControlProblem.__init__ + ~OptimalControlProblem.add_phase + ~OptimalControlProblem.add_phases + ~OptimalControlProblem.initialise + ~OptimalControlProblem.new_phase + ~OptimalControlProblem.new_phase_like + ~OptimalControlProblem.new_phases_like + ~OptimalControlProblem.solve + + \ No newline at end of file diff --git a/docs/_autosummary/pycollo.optimal_control_problem.cout.rst b/docs/_autosummary/pycollo.optimal_control_problem.cout.rst new file mode 100644 index 0000000..7da63b5 --- /dev/null +++ b/docs/_autosummary/pycollo.optimal_control_problem.cout.rst @@ -0,0 +1,9 @@ +.. + base.rst + +pycollo.optimal\_control\_problem.cout +====================================== + +.. currentmodule:: pycollo.optimal_control_problem + +.. autofunction:: cout \ No newline at end of file diff --git a/docs/_autosummary/pycollo.optimal_control_problem.kill.rst b/docs/_autosummary/pycollo.optimal_control_problem.kill.rst new file mode 100644 index 0000000..3ebc802 --- /dev/null +++ b/docs/_autosummary/pycollo.optimal_control_problem.kill.rst @@ -0,0 +1,9 @@ +.. + base.rst + +pycollo.optimal\_control\_problem.kill +====================================== + +.. currentmodule:: pycollo.optimal_control_problem + +.. autofunction:: kill \ No newline at end of file diff --git a/docs/_autosummary/pycollo.optimal_control_problem.rst b/docs/_autosummary/pycollo.optimal_control_problem.rst new file mode 100644 index 0000000..bb23450 --- /dev/null +++ b/docs/_autosummary/pycollo.optimal_control_problem.rst @@ -0,0 +1,45 @@ +.. + module.rst + +pycollo.optimal\_control\_problem +================================= + +.. automodule:: pycollo.optimal_control_problem + + + + + + + + .. rubric:: Functions + + .. autosummary:: + :toctree: + :nosignatures: + :template: autosummary/base.rst + + cout + kill + + + + + + .. rubric:: Classes + + .. autosummary:: + :toctree: + :nosignatures: + :template: autosummary/class.rst + + OptimalControlProblem + + + + + + + + + diff --git a/docs/_autosummary/pycollo.phase.Phase.rst b/docs/_autosummary/pycollo.phase.Phase.rst new file mode 100644 index 0000000..3dd7bb5 --- /dev/null +++ b/docs/_autosummary/pycollo.phase.Phase.rst @@ -0,0 +1,56 @@ +.. + class.rst + +pycollo.phase.Phase +=================== + +.. currentmodule:: pycollo.phase + +.. autoclass:: Phase + :members: + :show-inheritance: + :inherited-members: + :special-members: + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Phase.bounds + ~Phase.control_variables + ~Phase.final_state_variables + ~Phase.final_time_variable + ~Phase.guess + ~Phase.initial_state_variables + ~Phase.initial_time_variable + ~Phase.integral_variables + ~Phase.integrand_functions + ~Phase.mesh + ~Phase.name + ~Phase.number_control_variables + ~Phase.number_integral_variables + ~Phase.number_integrand_functions + ~Phase.number_path_constraints + ~Phase.number_state_equations + ~Phase.number_state_variables + ~Phase.optimal_control_problem + ~Phase.path_constraints + ~Phase.phase_number + ~Phase.scaling + ~Phase.state_equations + ~Phase.state_variables + ~Phase.time_variables + + + .. rubric:: Methods + + .. autosummary:: + :nosignatures: + + ~Phase.__init__ + ~Phase.create_new_copy + ~Phase.create_new_copy_like + + \ No newline at end of file diff --git a/docs/_autosummary/pycollo.phase.rst b/docs/_autosummary/pycollo.phase.rst new file mode 100644 index 0000000..3182855 --- /dev/null +++ b/docs/_autosummary/pycollo.phase.rst @@ -0,0 +1,35 @@ +.. + module.rst + +pycollo.phase +============= + +.. automodule:: pycollo.phase + + + + + + + + + + + + .. rubric:: Classes + + .. autosummary:: + :toctree: + :nosignatures: + :template: autosummary/class.rst + + Phase + + + + + + + + + diff --git a/docs/_templates/autosummary/base.rst b/docs/_templates/autosummary/base.rst new file mode 100644 index 0000000..5f64949 --- /dev/null +++ b/docs/_templates/autosummary/base.rst @@ -0,0 +1,8 @@ +.. + base.rst + +{{ fullname | escape | underline }} + +.. currentmodule:: {{ module }} + +.. auto{{ objtype }}:: {{ objname }} diff --git a/docs/_templates/autosummary/class.rst b/docs/_templates/autosummary/class.rst new file mode 100644 index 0000000..c283f48 --- /dev/null +++ b/docs/_templates/autosummary/class.rst @@ -0,0 +1,32 @@ +.. + class.rst + +{{ fullname | escape | underline }} + +.. currentmodule:: {{ module }} + +.. autoclass:: {{ objname }} + :members: + :show-inheritance: + :inherited-members: + :special-members: + + {% block methods %} + {% if methods %} + .. rubric:: {{ _('Attributes') }} + + .. autosummary:: + {% for item in attributes %} + ~{{ name }}.{{ item }} + {%- endfor %} + {% endif %} + {% if methods %} + .. rubric:: {{ _('Methods') }} + + .. autosummary:: + :nosignatures: + {% for item in methods %} + ~{{ name }}.{{ item }} + {%- endfor %} + {% endif %} + {% endblock %} diff --git a/docs/_templates/autosummary/module.rst b/docs/_templates/autosummary/module.rst new file mode 100644 index 0000000..341ea4c --- /dev/null +++ b/docs/_templates/autosummary/module.rst @@ -0,0 +1,74 @@ +.. + module.rst + +{{ fullname | escape | underline }} + +.. automodule:: {{ fullname }} + + {% block attributes %} + {% if attributes %} + .. rubric:: Module Attributes + + .. autosummary:: + :toctree: + {% for item in attributes %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block functions %} + {% if functions %} + .. rubric:: {{ _('Functions') }} + + .. autosummary:: + :toctree: + :nosignatures: + :template: autosummary/base.rst + {% for item in functions %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block classes %} + {% if classes %} + .. rubric:: {{ _('Classes') }} + + .. autosummary:: + :toctree: + :nosignatures: + :template: autosummary/class.rst + {% for item in classes %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block exceptions %} + {% if exceptions %} + .. rubric:: {{ _('Exceptions') }} + + .. autosummary:: + :toctree: + :nosignatures: + :template: autosummary/base.rst + {% for item in exceptions %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + +{% block modules %} + {% if modules %} + .. rubric:: Modules + + .. autosummary:: + :toctree: + :template: autosummary/module.rst + :recursive: + {% for item in modules %} + {{ item }} + {%- endfor %} + {% endif %} +{% endblock %} diff --git a/docs/api_reference.rst b/docs/api_reference.rst new file mode 100644 index 0000000..3a6ad05 --- /dev/null +++ b/docs/api_reference.rst @@ -0,0 +1,13 @@ +.. _api_reference: + +============= +API Reference +============= + +.. autosummary:: + :toctree: _autosummary + :recursive: + + pycollo.optimal_control_problem + pycollo.phase + diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..c40ed71 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,66 @@ +"""Configuration file for the Sphinx documentation builder. + +For the full list of built-in configuration values, see the documentation: +https://www.sphinx-doc.org/en/master/usage/configuration.html +""" +import os +import sys + +# Add source folder to path for autodoc +sys.path.insert(0, os.path.abspath("..")) + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = "Pycollo" +copyright = "2023, Sam Brockie" # noqa: A001 +author = "Sam Brockie" + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + "sphinx.ext.napoleon", + "sphinx.ext.intersphinx", + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.mathjax", + "sphinx.ext.viewcode", +] + +templates_path = ["_templates"] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] + +napoleon_google_docstring = True +napoleon_custom_sections = [("Explanation", "notes_style")] + +intersphinx_mapping = { + "cyipopt": ("https://cyipopt.readthedocs.io/en/stable/", None), + "matplotlib": ("https://matplotlib.org/stable/", None), + "numba": ("https://numba.readthedocs.io/en/stable/", None), + "numpy": ("https://numpy.org/doc/stable/", None), + "scipy": ("https://docs.scipy.org/doc/scipy/", None), + "sympy": ("https://docs.sympy.org/latest/", None), +} + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "furo" +# html_theme_options = { +# "base_url": "https://brocksam.github.io/pycollo/", +# "color_primary": "teal", +# "color_accent": "deep-orange", # hover color of hyperlinks +# "repo_name": "Pycollo", +# "repo_url": "https://github.com/brocksam/pycollo/", +# "logo_icon": "", +# "master_doc": False, # Doesn't show duplicate title +# "nav_links": [{"href": "index", "internal": True, "title": "Home"}], +# } + +# html_sidebars = { +# "**": ["logo-text.html", "globaltoc.html", "localtoc.html", "searchbox.html"] +# } + +html_static_path = ["_static"] diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..8732541 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,10 @@ +===================== +Pycollo Documentation +===================== +Pycollo: an Open-Source Package for Multi Phase Direct Collocation. + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + api_reference diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..32bb245 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/source/_autosummary/pycollo.backend.rst b/docs/source/_autosummary/pycollo.backend.rst deleted file mode 100644 index ccea0a5..0000000 --- a/docs/source/_autosummary/pycollo.backend.rst +++ /dev/null @@ -1,34 +0,0 @@ -pycollo.backend -=============== - -.. automodule:: pycollo.backend - - - - - - - - - - - - .. rubric:: Classes - - .. autosummary:: - - BackendABC - Casadi - Hsad - Pycollo - PycolloPhaseData - Sympy - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.bounds.rst b/docs/source/_autosummary/pycollo.bounds.rst deleted file mode 100644 index d725864..0000000 --- a/docs/source/_autosummary/pycollo.bounds.rst +++ /dev/null @@ -1,57 +0,0 @@ -pycollo.bounds -============== - -.. automodule:: pycollo.bounds - - - - .. rubric:: Module Attributes - - .. autosummary:: - - PhaseInfo - BoundsInfo - - - - - - .. rubric:: Functions - - .. autosummary:: - - as_lower_upper_pair - check_lower_against_upper - check_lower_less_than_upper - check_lower_same_as_upper_to_tol - check_user_bound_missing - extract_variables_to_constants - get_bound_as_number - process_iterable_bounds_instance - process_mapping_bounds_instance - process_none_bounds_instance - process_single_type_of_values - - - - - - .. rubric:: Classes - - .. autosummary:: - - Bounds - BoundsABC - BoundsInfo - EndpointBounds - PhaseBounds - PhaseInfo - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.compiled.rst b/docs/source/_autosummary/pycollo.compiled.rst deleted file mode 100644 index ae03216..0000000 --- a/docs/source/_autosummary/pycollo.compiled.rst +++ /dev/null @@ -1,29 +0,0 @@ -pycollo.compiled -================ - -.. automodule:: pycollo.compiled - - - - - - - - - - - - .. rubric:: Classes - - .. autosummary:: - - CompiledFunctions - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.expression_graph.rst b/docs/source/_autosummary/pycollo.expression_graph.rst deleted file mode 100644 index c3a3a08..0000000 --- a/docs/source/_autosummary/pycollo.expression_graph.rst +++ /dev/null @@ -1,36 +0,0 @@ -pycollo.expression\_graph -========================= - -.. automodule:: pycollo.expression_graph - - - - - - - - .. rubric:: Functions - - .. autosummary:: - - cout - kill - - - - - - .. rubric:: Classes - - .. autosummary:: - - ExpressionGraph - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.guess.rst b/docs/source/_autosummary/pycollo.guess.rst deleted file mode 100644 index 803cc31..0000000 --- a/docs/source/_autosummary/pycollo.guess.rst +++ /dev/null @@ -1,37 +0,0 @@ -pycollo.guess -============= - -.. automodule:: pycollo.guess - - - - - - - - .. rubric:: Functions - - .. autosummary:: - - assert_increasing - - - - - - .. rubric:: Classes - - .. autosummary:: - - EndpointGuess - Guess - PhaseGuess - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.iteration.rst b/docs/source/_autosummary/pycollo.iteration.rst deleted file mode 100644 index 5c7fc2b..0000000 --- a/docs/source/_autosummary/pycollo.iteration.rst +++ /dev/null @@ -1,31 +0,0 @@ -pycollo.iteration -================= - -.. automodule:: pycollo.iteration - - - - - - - - - - - - .. rubric:: Classes - - .. autosummary:: - - Iteration - IterationOld - MeshIterationResult - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.mesh.rst b/docs/source/_autosummary/pycollo.mesh.rst deleted file mode 100644 index ce343bc..0000000 --- a/docs/source/_autosummary/pycollo.mesh.rst +++ /dev/null @@ -1,30 +0,0 @@ -pycollo.mesh -============ - -.. automodule:: pycollo.mesh - - - - - - - - - - - - .. rubric:: Classes - - .. autosummary:: - - Mesh - PhaseMesh - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.mesh_refinement.rst b/docs/source/_autosummary/pycollo.mesh_refinement.rst deleted file mode 100644 index 07fb487..0000000 --- a/docs/source/_autosummary/pycollo.mesh_refinement.rst +++ /dev/null @@ -1,30 +0,0 @@ -pycollo.mesh\_refinement -======================== - -.. automodule:: pycollo.mesh_refinement - - - - - - - - - - - - .. rubric:: Classes - - .. autosummary:: - - MeshRefinementABC - PattersonRaoMeshRefinement - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.nlp.rst b/docs/source/_autosummary/pycollo.nlp.rst deleted file mode 100644 index 1975d03..0000000 --- a/docs/source/_autosummary/pycollo.nlp.rst +++ /dev/null @@ -1,37 +0,0 @@ -pycollo.nlp -=========== - -.. automodule:: pycollo.nlp - - - - - - - - .. rubric:: Functions - - .. autosummary:: - - initialise_nlp_backend - - - - - - .. rubric:: Classes - - .. autosummary:: - - IPOPTProblem - NLPProblem - NLPSettings - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.node.rst b/docs/source/_autosummary/pycollo.node.rst deleted file mode 100644 index 853223d..0000000 --- a/docs/source/_autosummary/pycollo.node.rst +++ /dev/null @@ -1,36 +0,0 @@ -pycollo.node -============ - -.. automodule:: pycollo.node - - - - - - - - - - - - .. rubric:: Classes - - .. autosummary:: - - Cached - ConstantNode - ExpressionNodeABC - IntermediateNode - Node - NumberNode - RootNode - VariableNode - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.numbafy.rst b/docs/source/_autosummary/pycollo.numbafy.rst deleted file mode 100644 index 15dc568..0000000 --- a/docs/source/_autosummary/pycollo.numbafy.rst +++ /dev/null @@ -1,31 +0,0 @@ -pycollo.numbafy -=============== - -.. automodule:: pycollo.numbafy - - - - - - - - .. rubric:: Functions - - .. autosummary:: - - cout - kill - numbafy - - - - - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.numbafy_hessian.rst b/docs/source/_autosummary/pycollo.numbafy_hessian.rst deleted file mode 100644 index 0780ca6..0000000 --- a/docs/source/_autosummary/pycollo.numbafy_hessian.rst +++ /dev/null @@ -1,30 +0,0 @@ -pycollo.numbafy\_hessian -======================== - -.. automodule:: pycollo.numbafy_hessian - - - - - - - - .. rubric:: Functions - - .. autosummary:: - - numbafy_continuous_hessian - numbafy_endpoint_hessian - - - - - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.operations.rst b/docs/source/_autosummary/pycollo.operations.rst deleted file mode 100644 index b7ca2e5..0000000 --- a/docs/source/_autosummary/pycollo.operations.rst +++ /dev/null @@ -1,79 +0,0 @@ -pycollo.operations -================== - -.. automodule:: pycollo.operations - - - - - - - - .. rubric:: Functions - - .. autosummary:: - - determine_operation - is_sympy_log - is_sympy_mul - is_sympy_pow - is_sympy_sym - - - - - - .. rubric:: Classes - - .. autosummary:: - - PycolloAdd - PycolloArccos - PycolloArccosec - PycolloArccosech - PycolloArccosh - PycolloArccot - PycolloArccoth - PycolloArcsec - PycolloArcsech - PycolloArcsin - PycolloArcsinh - PycolloArctan - PycolloArctanh - PycolloBinaryMul - PycolloCos - PycolloCosec - PycolloCosech - PycolloCosh - PycolloCot - PycolloCoth - PycolloCube - PycolloCuberoot - PycolloExp - PycolloLn - PycolloLog - PycolloMul - PycolloNullOp - PycolloOp - PycolloPow - PycolloReciprocal - PycolloSec - PycolloSech - PycolloSin - PycolloSinh - PycolloSquare - PycolloSquareReciprocal - PycolloSquareroot - PycolloTan - PycolloTanh - PycolloTernaryMul - PycolloUnsetOp - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.optimal_control_problem.rst b/docs/source/_autosummary/pycollo.optimal_control_problem.rst deleted file mode 100644 index 57ae085..0000000 --- a/docs/source/_autosummary/pycollo.optimal_control_problem.rst +++ /dev/null @@ -1,36 +0,0 @@ -pycollo.optimal\_control\_problem -================================= - -.. automodule:: pycollo.optimal_control_problem - - - - - - - - .. rubric:: Functions - - .. autosummary:: - - cout - kill - - - - - - .. rubric:: Classes - - .. autosummary:: - - OptimalControlProblem - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.phase.rst b/docs/source/_autosummary/pycollo.phase.rst deleted file mode 100644 index f4087be..0000000 --- a/docs/source/_autosummary/pycollo.phase.rst +++ /dev/null @@ -1,29 +0,0 @@ -pycollo.phase -============= - -.. automodule:: pycollo.phase - - - - - - - - - - - - .. rubric:: Classes - - .. autosummary:: - - Phase - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.quadrature.rst b/docs/source/_autosummary/pycollo.quadrature.rst deleted file mode 100644 index a5e805c..0000000 --- a/docs/source/_autosummary/pycollo.quadrature.rst +++ /dev/null @@ -1,29 +0,0 @@ -pycollo.quadrature -================== - -.. automodule:: pycollo.quadrature - - - - - - - - - - - - .. rubric:: Classes - - .. autosummary:: - - Quadrature - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.rst b/docs/source/_autosummary/pycollo.rst deleted file mode 100644 index 1b3b94f..0000000 --- a/docs/source/_autosummary/pycollo.rst +++ /dev/null @@ -1,55 +0,0 @@ -pycollo -======= - -.. automodule:: pycollo - - - - - - - - - - - - - - - - - - - -.. rubric:: Modules - -.. autosummary:: - :toctree: - :recursive: - - pycollo.backend - pycollo.bounds - pycollo.compiled - pycollo.expression_graph - pycollo.guess - pycollo.iteration - pycollo.mesh - pycollo.mesh_refinement - pycollo.nlp - pycollo.node - pycollo.numbafy - pycollo.numbafy_hessian - pycollo.operations - pycollo.optimal_control_problem - pycollo.phase - pycollo.quadrature - pycollo.scaling - pycollo.settings - pycollo.solution - pycollo.sparse - pycollo.sparsity - pycollo.typing - pycollo.utils - pycollo.version - pycollo.vis - diff --git a/docs/source/_autosummary/pycollo.scaling.rst b/docs/source/_autosummary/pycollo.scaling.rst deleted file mode 100644 index d528196..0000000 --- a/docs/source/_autosummary/pycollo.scaling.rst +++ /dev/null @@ -1,43 +0,0 @@ -pycollo.scaling -=============== - -.. automodule:: pycollo.scaling - - - - - - - - .. rubric:: Functions - - .. autosummary:: - - np_print - - - - - - .. rubric:: Classes - - .. autosummary:: - - CasadiIterationScaling - EndpointScaling - HsadIterationScaling - IterationScaling - PhaseScaling - PycolloIterationScaling - Scaling - ScalingABC - SympyIterationScaling - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.settings.rst b/docs/source/_autosummary/pycollo.settings.rst deleted file mode 100644 index 36b5556..0000000 --- a/docs/source/_autosummary/pycollo.settings.rst +++ /dev/null @@ -1,29 +0,0 @@ -pycollo.settings -================ - -.. automodule:: pycollo.settings - - - - - - - - - - - - .. rubric:: Classes - - .. autosummary:: - - Settings - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.solution.casadi_solution.rst b/docs/source/_autosummary/pycollo.solution.casadi_solution.rst deleted file mode 100644 index 581960e..0000000 --- a/docs/source/_autosummary/pycollo.solution.casadi_solution.rst +++ /dev/null @@ -1,29 +0,0 @@ -pycollo.solution.casadi\_solution -================================= - -.. automodule:: pycollo.solution.casadi_solution - - - - - - - - - - - - .. rubric:: Classes - - .. autosummary:: - - CasadiSolution - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.solution.pycollo_solution.rst b/docs/source/_autosummary/pycollo.solution.pycollo_solution.rst deleted file mode 100644 index d2d75dd..0000000 --- a/docs/source/_autosummary/pycollo.solution.pycollo_solution.rst +++ /dev/null @@ -1,23 +0,0 @@ -pycollo.solution.pycollo\_solution -================================== - -.. automodule:: pycollo.solution.pycollo_solution - - - - - - - - - - - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.solution.rst b/docs/source/_autosummary/pycollo.solution.rst deleted file mode 100644 index 01726b3..0000000 --- a/docs/source/_autosummary/pycollo.solution.rst +++ /dev/null @@ -1,35 +0,0 @@ -pycollo.solution -================ - -.. automodule:: pycollo.solution - - - - - - - - - - - - - - - - - - - -.. rubric:: Modules - -.. autosummary:: - :toctree: - :recursive: - - pycollo.solution.casadi_solution - pycollo.solution.hsad_solution - pycollo.solution.pycollo_solution - pycollo.solution.solution_abc - pycollo.solution.sympy_solution - diff --git a/docs/source/_autosummary/pycollo.solution.solution_abc.rst b/docs/source/_autosummary/pycollo.solution.solution_abc.rst deleted file mode 100644 index fa78dbc..0000000 --- a/docs/source/_autosummary/pycollo.solution.solution_abc.rst +++ /dev/null @@ -1,32 +0,0 @@ -pycollo.solution.solution\_abc -============================== - -.. automodule:: pycollo.solution.solution_abc - - - - - - - - - - - - .. rubric:: Classes - - .. autosummary:: - - NlpResult - PhaseSolutionData - Polys - SolutionABC - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.solution.sympy_solution.rst b/docs/source/_autosummary/pycollo.solution.sympy_solution.rst deleted file mode 100644 index 9863ee0..0000000 --- a/docs/source/_autosummary/pycollo.solution.sympy_solution.rst +++ /dev/null @@ -1,23 +0,0 @@ -pycollo.solution.sympy\_solution -================================ - -.. automodule:: pycollo.solution.sympy_solution - - - - - - - - - - - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.sparse.rst b/docs/source/_autosummary/pycollo.sparse.rst deleted file mode 100644 index 24fac32..0000000 --- a/docs/source/_autosummary/pycollo.sparse.rst +++ /dev/null @@ -1,29 +0,0 @@ -pycollo.sparse -============== - -.. automodule:: pycollo.sparse - - - - - - - - - - - - .. rubric:: Classes - - .. autosummary:: - - SparseCOOMatrix - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.typing.rst b/docs/source/_autosummary/pycollo.typing.rst deleted file mode 100644 index b2aa51b..0000000 --- a/docs/source/_autosummary/pycollo.typing.rst +++ /dev/null @@ -1,33 +0,0 @@ -pycollo.typing -============== - -.. automodule:: pycollo.typing - - - - .. rubric:: Module Attributes - - .. autosummary:: - - SympyType - OptionalBoundsType - OptionalExprsType - OptionalSymsType - TupleSymsType - - - - - - - - - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.utils.rst b/docs/source/_autosummary/pycollo.utils.rst deleted file mode 100644 index 78debe9..0000000 --- a/docs/source/_autosummary/pycollo.utils.rst +++ /dev/null @@ -1,51 +0,0 @@ -pycollo.utils -============= - -.. automodule:: pycollo.utils - - - - - - - - .. rubric:: Functions - - .. autosummary:: - - casadi_substitute - check_sym_name_clash - console_out - dict_merge - fast_sympify - format_as_named_tuple - format_case - format_for_output - format_multiple_items_for_output - format_time - needed_to_tuple - parse_arg_type - parse_parameter_var - symbol_name - symbol_primitives - sympy_to_casadi - - - - - - .. rubric:: Classes - - .. autosummary:: - - cachedproperty - dcdxInfo - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.version.rst b/docs/source/_autosummary/pycollo.version.rst deleted file mode 100644 index d199a26..0000000 --- a/docs/source/_autosummary/pycollo.version.rst +++ /dev/null @@ -1,23 +0,0 @@ -pycollo.version -=============== - -.. automodule:: pycollo.version - - - - - - - - - - - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.vis.plot.rst b/docs/source/_autosummary/pycollo.vis.plot.rst deleted file mode 100644 index 5fefb3d..0000000 --- a/docs/source/_autosummary/pycollo.vis.plot.rst +++ /dev/null @@ -1,34 +0,0 @@ -pycollo.vis.plot -================ - -.. automodule:: pycollo.vis.plot - - - - - - - - .. rubric:: Functions - - .. autosummary:: - - interpolate_x_solution - plot_buffered_renders - plot_mesh - plot_phase_mesh - plot_solution - render_x_solution - - - - - - - - - - - - - diff --git a/docs/source/_autosummary/pycollo.vis.rst b/docs/source/_autosummary/pycollo.vis.rst deleted file mode 100644 index 5788363..0000000 --- a/docs/source/_autosummary/pycollo.vis.rst +++ /dev/null @@ -1,31 +0,0 @@ -pycollo.vis -=========== - -.. automodule:: pycollo.vis - - - - - - - - - - - - - - - - - - - -.. rubric:: Modules - -.. autosummary:: - :toctree: - :recursive: - - pycollo.vis.plot - diff --git a/pycollo/optimal_control_problem.py b/pycollo/optimal_control_problem.py index 039120d..7c515fd 100644 --- a/pycollo/optimal_control_problem.py +++ b/pycollo/optimal_control_problem.py @@ -54,10 +54,7 @@ class OptimalControlProblem(): - """The main class for Pycollo optimal control problems - - Attributes: - """ + """The main class for Pycollo optimal control problems""" def __init__(self, name, @@ -74,7 +71,7 @@ def __init__(self, """Initialise the optimal control problem with user-passed objects. Args: - phases (:obj:`Iterable` of :obj:`Phase`, optional): Phases to be + phases (:obj:`Iterable` of :class:`~.Phase`, optional): Phases to be associated with the optimal control problem at initialisation. Defaults to None. parameter_variables () @@ -104,7 +101,7 @@ def name(self) -> str: Pycollo console output. This is particularly useful in cases where the user may wish to instantiate multiple :obj:`OptimalControlProblem` objects within a single script, or instantiates other Pycollo objects - without providing a valid `optimal_control_problem` argument for them + without providing a valid :class:`~.optimal_control_problem` argument for them to be linked to at initialisation. """ return self._name @@ -117,37 +114,37 @@ def name(self, name: AnyStr): def phases(self) -> Tuple[Phase, ...]: """A tuple of all phases associated with the optimal control problem. - Phase numbers (`Phase.number`) are integers beginning at 1 and are + :meth:`~.phase_number` are integers beginning at 1 and are ordered corresponding to the order that they were added to the optimal control problem. As Python uses zero-based indexing the phase numbers - do not directly map to the indexes of phases within `self.phases`. + do not directly map to the indexes of phases within :class:`~.phases`. Phases are however ordered sequentially corresponding to the cronological order they were added to the optimal control problem. """ return self._phases def add_phase(self, phase: Iterable[Phase]) -> Phase: - """Add an already instantiated `Phase` to this optimal control problem. + """Add an already instantiated :class:`~.Phase` to this optimal control problem. - This method is needed as `self.phases` is read only ("private") and - therefore users cannot manually add `Phase` objects to an optimal - control problem. `self.phases` is required to be read only as it is an - iterable of `Phase` objects and must be protected from accidental errors + This method is needed as :class:`~.phases` is read only ("private") and + therefore users cannot manually add :class:`~.Phase` objects to an optimal + control problem. :class:`~.phases` is required to be read only as it is an + iterable of :class:`~.Phase` objects and must be protected from accidental errors introduced by user interacting with it incorrectly. Args: phase (Phase): The phase to be added to the optimal control problem Returns: - Phase: the phase that has been added. It is the same + the phase that has been added. It is the same """ phase.optimal_control_problem = self return self.phases[-1] def add_phases(self, phases: Iterable[Phase]) -> Tuple[Phase, ...]: - """Associate multiple already instantiated `Phase` objects. + """Associate multiple already instantiated :class:`~.Phase` objects. - This is a convinience method to allow the user to add multiple `Phase` + This is a convinience method to allow the user to add multiple :class:`~.Phase` objects to the optimal control problem in one go. """ return tuple(self.add_phase(phase) for phase in phases) @@ -156,10 +153,10 @@ def new_phase(self, name: str, state_variables: OptionalSymsType = None, control_variables: OptionalSymsType = None) -> Phase: - """Create a new :obj:`Phase` and add to this optimal control problem. + """Create a new :obj:`~.Phase` and add to this optimal control problem. - Provides the same behaviour as manually creating a :obj:`Phase` called - `phase` and calling `self.add_phase(phase)`. + Provides the same behaviour as manually creating a :obj:`.~Phase` called + `phase` and calling :meth:`~.add_phase`. """ new_phase = Phase(name, optimal_control_problem=self, state_variables=state_variables, @@ -177,7 +174,7 @@ def new_phases_like(self, """Creates multiple new phases like an already instantiated phase. For a list of key word arguments and default values see the docstring - for the `OptimalControlProblem.new_phase_like` method. + for the :meth:`~.new_phase_like` method. Returns: The newly instantiated and associated phases. @@ -322,10 +319,8 @@ def initialise(self): The initialisation of the optimal control problem involves the following stages: - * 1. Check that for each phase there are the same number of state - variables as there are state equations. - * 2. Check that for each phase the user-supplied bounds are - permissible, and check point bounds on optimal control problem. + * 1. Check that for each phase there are the same number of state variables as there are state equations. + * 2. Check that for each phase the user-supplied bounds are permissible, and check point bounds on optimal control problem. * 3. Process bounds that need processing. """ @@ -396,8 +391,7 @@ def solve(self, display_progress=False): method is called to initialise the optimal control problem. Parameters: - ----------- - display_progress : bool + display_progress : bool Option for whether progress updates should be outputted to the console during solving. Defaults to False. """ @@ -417,8 +411,7 @@ def _check_if_initialisation_required_before_solve(self): def _solve_iteration(self): """Solve a single mesh iteration. - Return - ------ + Return: bool True is mesh tolerance is met or if maximum number of mesh iterations has been reached. @@ -561,6 +554,7 @@ def time_results(): time_results() def __str__(self): + """Returns name of OCP""" return self.name def __repr__(self): From 1822c76854ef0e3868203f32b85d340208732aea Mon Sep 17 00:00:00 2001 From: jtheinen Date: Wed, 28 Jun 2023 11:19:05 +0200 Subject: [PATCH 3/9] delete old _docs folder --- _docs/Makefile | 20 ----- _docs/requirements.txt | 2 - _docs/source/_templates/autosummary/base.rst | 8 -- _docs/source/_templates/autosummary/class.rst | 32 -------- .../source/_templates/autosummary/module.rst | 74 ------------------- _docs/source/api_reference.rst | 13 ---- _docs/source/conf.py | 49 ------------ _docs/source/index.rst | 20 ----- 8 files changed, 218 deletions(-) delete mode 100644 _docs/Makefile delete mode 100644 _docs/requirements.txt delete mode 100644 _docs/source/_templates/autosummary/base.rst delete mode 100644 _docs/source/_templates/autosummary/class.rst delete mode 100644 _docs/source/_templates/autosummary/module.rst delete mode 100644 _docs/source/api_reference.rst delete mode 100644 _docs/source/conf.py delete mode 100644 _docs/source/index.rst diff --git a/_docs/Makefile b/_docs/Makefile deleted file mode 100644 index d0c3cbf..0000000 --- a/_docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = source -BUILDDIR = build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/_docs/requirements.txt b/_docs/requirements.txt deleted file mode 100644 index 7ce3248..0000000 --- a/_docs/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -sphinx>=6.1.3 -sphinx-material>=0.0.35 diff --git a/_docs/source/_templates/autosummary/base.rst b/_docs/source/_templates/autosummary/base.rst deleted file mode 100644 index 073fe3f..0000000 --- a/_docs/source/_templates/autosummary/base.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. - base.rst - -{{ fullname | escape | underline }} - -.. currentmodule:: {{ module }} - -.. auto{{ objtype }}:: {{ objname }} diff --git a/_docs/source/_templates/autosummary/class.rst b/_docs/source/_templates/autosummary/class.rst deleted file mode 100644 index 999cd90..0000000 --- a/_docs/source/_templates/autosummary/class.rst +++ /dev/null @@ -1,32 +0,0 @@ -.. - class.rst - -{{ fullname | escape | underline }} - -.. currentmodule:: {{ module }} - -.. autoclass:: {{ objname }} - :members: - :show-inheritance: - :inherited-members: - :special-members: - - {% block methods %} - {% if methods %} - .. rubric:: {{ _('Attributes') }} - - .. autosummary:: - {% for item in attributes %} - ~{{ name }}.{{ item }} - {%- endfor %} - {% endif %} - {% if methods %} - .. rubric:: {{ _('Methods') }} - - .. autosummary:: - :nosignatures: - {% for item in methods %} - ~{{ name }}.{{ item }} - {%- endfor %} - {% endif %} - {% endblock %} diff --git a/_docs/source/_templates/autosummary/module.rst b/_docs/source/_templates/autosummary/module.rst deleted file mode 100644 index 818f2e9..0000000 --- a/_docs/source/_templates/autosummary/module.rst +++ /dev/null @@ -1,74 +0,0 @@ -.. - module.rst - -{{ fullname | escape | underline }} - -.. automodule:: {{ fullname }} - - {% block attributes %} - {% if attributes %} - .. rubric:: Module Attributes - - .. autosummary:: - :toctree: - {% for item in attributes %} - {{ item }} - {%- endfor %} - {% endif %} - {% endblock %} - - {% block functions %} - {% if functions %} - .. rubric:: {{ _('Functions') }} - - .. autosummary:: - :toctree: - :nosignatures: - :template: autosummary/base.rst - {% for item in functions %} - {{ item }} - {%- endfor %} - {% endif %} - {% endblock %} - - {% block classes %} - {% if classes %} - .. rubric:: {{ _('Classes') }} - - .. autosummary:: - :toctree: - :nosignatures: - :template: autosummary/class.rst - {% for item in classes %} - {{ item }} - {%- endfor %} - {% endif %} - {% endblock %} - - {% block exceptions %} - {% if exceptions %} - .. rubric:: {{ _('Exceptions') }} - - .. autosummary:: - :toctree: - :nosignatures: - :template: autosummary/base.rst - {% for item in exceptions %} - {{ item }} - {%- endfor %} - {% endif %} - {% endblock %} - -{% block modules %} - {% if modules %} - .. rubric:: Modules - - .. autosummary:: - :toctree: - :template: autosummary/module.rst - :recursive: - {% for item in modules %} - {{ item }} - {%- endfor %} - {% endif %} -{% endblock %} diff --git a/_docs/source/api_reference.rst b/_docs/source/api_reference.rst deleted file mode 100644 index 8cd4bc6..0000000 --- a/_docs/source/api_reference.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. _api_reference: - -============= -API Reference -============= - -.. autosummary:: - :toctree: _autosummary - :recursive: - - ../pycollo - - diff --git a/_docs/source/conf.py b/_docs/source/conf.py deleted file mode 100644 index ccfe55e..0000000 --- a/_docs/source/conf.py +++ /dev/null @@ -1,49 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# For the full list of built-in configuration values, see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Project information ----------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information -import os -import sys - -sys.path.insert(0, os.path.abspath("..")) - -project = "Pycollo" -copyright = "2023, Sam Brockie" # noqa: A001 -author = "Sam Brockie" - -# -- General configuration --------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration - -extensions = [ - "sphinx.ext.napoleon", - "sphinx.ext.intersphinx", - "sphinx.ext.autodoc", - "sphinx.ext.autosummary", - "sphinx.ext.mathjax", - "sphinx.ext.viewcode", -] - -templates_path = ["source/_templates"] -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store","_templates"] - -napoleon_numpy_docstring = True - -intersphinx_mapping = { - "cyipopt": ("https://cyipopt.readthedocs.io/en/stable/", None), - "matplotlib": ("https://matplotlib.org/stable/", None), - "numba": ("https://numba.readthedocs.io/en/stable/", None), - "numpy": ("https://numpy.org/doc/stable/", None), - "scipy": ("https://docs.scipy.org/doc/scipy/", None), - "sympy": ("https://docs.sympy.org/latest/", None), -} - - -# -- Options for HTML output ------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output - -html_theme = "furo" - -html_static_path = ["_static"] diff --git a/_docs/source/index.rst b/_docs/source/index.rst deleted file mode 100644 index 515436f..0000000 --- a/_docs/source/index.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. Pycollo documentation master file, created by - sphinx-quickstart on Tue Feb 14 19:27:48 2023. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to Pycollo's documentation! -=================================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - api_reference - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` From 39e4af06c7f31fc307f46e7013a83f41bc1cc570 Mon Sep 17 00:00:00 2001 From: jtheinen Date: Thu, 29 Jun 2023 01:11:01 +0200 Subject: [PATCH 4/9] updated phases and optimal_control_problem docstrings --- docs/conf.py | 19 ++------ pycollo/optimal_control_problem.py | 35 ++++++++------- pycollo/phase.py | 72 +++++++++++------------------- 3 files changed, 49 insertions(+), 77 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index c40ed71..2eb99b4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -32,7 +32,6 @@ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] napoleon_google_docstring = True -napoleon_custom_sections = [("Explanation", "notes_style")] intersphinx_mapping = { "cyipopt": ("https://cyipopt.readthedocs.io/en/stable/", None), @@ -41,26 +40,14 @@ "numpy": ("https://numpy.org/doc/stable/", None), "scipy": ("https://docs.scipy.org/doc/scipy/", None), "sympy": ("https://docs.sympy.org/latest/", None), + "py3": ("http://docs.python.org/3",None) } - # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output html_theme = "furo" -# html_theme_options = { -# "base_url": "https://brocksam.github.io/pycollo/", -# "color_primary": "teal", -# "color_accent": "deep-orange", # hover color of hyperlinks -# "repo_name": "Pycollo", -# "repo_url": "https://github.com/brocksam/pycollo/", -# "logo_icon": "", -# "master_doc": False, # Doesn't show duplicate title -# "nav_links": [{"href": "index", "internal": True, "title": "Home"}], -# } - -# html_sidebars = { -# "**": ["logo-text.html", "globaltoc.html", "localtoc.html", "searchbox.html"] -# } html_static_path = ["_static"] + +napoleon_include_private_with_doc = True diff --git a/pycollo/optimal_control_problem.py b/pycollo/optimal_control_problem.py index 7c515fd..b594a38 100644 --- a/pycollo/optimal_control_problem.py +++ b/pycollo/optimal_control_problem.py @@ -7,7 +7,6 @@ See the ``Notes`` section for a full list of symbols used. Notes: ------- * t: independent parameter (time). * x = [y, u, q, t0, tf, s]: vector of problem variables. * y: vector state variables (which are functions of time). @@ -71,9 +70,7 @@ def __init__(self, """Initialise the optimal control problem with user-passed objects. Args: - phases (:obj:`Iterable` of :class:`~.Phase`, optional): Phases to be - associated with the optimal control problem at initialisation. - Defaults to None. + phases (``Iterable`` of :class:`~.Phase`, optional): Phases to be associated with the optimal control problem at initialisation. Defaults to None. parameter_variables () """ @@ -95,14 +92,13 @@ def __init__(self, @property def name(self) -> str: """The name associated with the optimal control problem. For setter - behaviour, the supplied `name` is cast to a str. + behaviour, the supplied `name` is cast to a :class:`str`. The name is not strictly needed, however it improves the usefulness of Pycollo console output. This is particularly useful in cases where the user may wish to instantiate multiple :obj:`OptimalControlProblem` objects within a single script, or instantiates other Pycollo objects - without providing a valid :class:`~.optimal_control_problem` argument for them - to be linked to at initialisation. + without providing a valid :class:`~.optimal_control_problem` argument for them to be linked to at initialisation. """ return self._name @@ -112,12 +108,12 @@ def name(self, name: AnyStr): @property def phases(self) -> Tuple[Phase, ...]: - """A tuple of all phases associated with the optimal control problem. + """A :class:`tuple` of all phases associated with the optimal control problem. :meth:`~.phase_number` are integers beginning at 1 and are ordered corresponding to the order that they were added to the optimal control problem. As Python uses zero-based indexing the phase numbers - do not directly map to the indexes of phases within :class:`~.phases`. + do not directly map to the indexes of phases within :attr:`~.phases`. Phases are however ordered sequentially corresponding to the cronological order they were added to the optimal control problem. """ @@ -126,9 +122,9 @@ def phases(self) -> Tuple[Phase, ...]: def add_phase(self, phase: Iterable[Phase]) -> Phase: """Add an already instantiated :class:`~.Phase` to this optimal control problem. - This method is needed as :class:`~.phases` is read only ("private") and + This method is needed as :attr:`~.phases` is read only ("private") and therefore users cannot manually add :class:`~.Phase` objects to an optimal - control problem. :class:`~.phases` is required to be read only as it is an + control problem. :attr:`~.phases` is required to be read only as it is an iterable of :class:`~.Phase` objects and must be protected from accidental errors introduced by user interacting with it incorrectly. @@ -155,7 +151,7 @@ def new_phase(self, control_variables: OptionalSymsType = None) -> Phase: """Create a new :obj:`~.Phase` and add to this optimal control problem. - Provides the same behaviour as manually creating a :obj:`.~Phase` called + Provides the same behaviour as manually creating a :obj:`~.Phase` called `phase` and calling :meth:`~.add_phase`. """ new_phase = Phase(name, optimal_control_problem=self, @@ -164,6 +160,8 @@ def new_phase(self, return new_phase def new_phase_like(self, phase_for_copying: Phase, name: str, **kwargs): + """Creates new phase while copying all implemented values from `phase_for_copying` + """ return phase_for_copying.create_new_copy(name, **kwargs) def new_phases_like(self, @@ -174,7 +172,7 @@ def new_phases_like(self, """Creates multiple new phases like an already instantiated phase. For a list of key word arguments and default values see the docstring - for the :meth:`~.new_phase_like` method. + for the :func:`new_phase_like` method. Returns: The newly instantiated and associated phases. @@ -198,10 +196,10 @@ def number_phases(self) -> int: @property def time_symbol(self): """ - + Symbol for time + Raises: - NotImplementedError: Whenever called to inform the user that these - types of problem are not currently supported. + NotImplementedError: Whenever called to inform the user that these types of problem are not currently supported. """ msg = ("Pycollo do not currently support dynamic, path or integral " "constraints that are explicit functions of continuous time.") @@ -209,6 +207,11 @@ def time_symbol(self): @property def parameter_variables(self): + """Static parameter variables which are optimized within given bounds. + + As described in Betts, JT (2010). Bounds and guesses are implemented with :func:`~.bounds` and :func:`~.guess`. + + """ return self._s_var_user @parameter_variables.setter diff --git a/pycollo/phase.py b/pycollo/phase.py index b79d8e7..85097c0 100644 --- a/pycollo/phase.py +++ b/pycollo/phase.py @@ -1,9 +1,4 @@ -"""Everything needed for defining phases within an optimal control problem. - -Classes: - Phase -""" - +"""Everything needed for defining phases within an optimal control problem.""" import copy from typing import Optional, Tuple @@ -22,26 +17,8 @@ class Phase: """A single continuous time phase as part of an optimal control problem. - - Attributes: - name: The name associated with a problem. Should be something short - like 'A'. - optimal_control_problem: The :obj:`OptimalControlProblem` with which - this phase is to be associated. - state_variables: The continuous time state variables in this phase. - control_variables: The continuous time control variables in this phase. - state_equations: The dynamical state equations associated with this - state variables in this phase. - integrand_functions: The integrand functions corresponding to the - integral variables in this phase. - path_constraints: The continuous time path constraints associated with - this phase. - bounds: The phase bounds on this phase. See :obj:PhaseBounds for more - details. - scaling: The phase scaling on this phase. See :obj:PhaseScaling for - more details. - guess: The initial guess at which this phase is to be solved. - mesh: This initial mesh on which this phase is to be solved. + + Attributes: _name: Protected version of :attr:`name`. _ocp: Protected version of :attr:`optimal_control_problem`. _phase_number: Protected integer number associated with this phase. If @@ -85,7 +62,7 @@ def __init__(self, Args: name: The name associated with a problem. Should be something short like 'A'. - optimal_control_problem: The :obj:`OptimalControlProblem` with + optimal_control_problem: The OptimalControlProblem with which this phase is to be associated. Default value is None in which case the phase remain uninitialised to an optimal control problem. @@ -218,12 +195,12 @@ def create_new_copy_like(phase_for_copying: "Phase", name: str, **kwargs): @property def name(self): - """Name of the phase.""" + """The name associated with a problem. Should be something short like 'A'.""" return self._name @property def optimal_control_problem(self) -> Optional["OptimalControlProblem"]: - """The optimal control problem with which this phase is associated. + """The :obj:`~.OptimalControlProblem` with which this phase is associated. There are two allowable scenarios. In the first scenario a phase may be instantiated without being associated with an optimal control problem. @@ -234,7 +211,7 @@ def optimal_control_problem(self) -> Optional["OptimalControlProblem"]: optimal control problem or is associated with an optimal control problem after the first type of instantiation. In this case the phase is appended to the protected `_phases` attribute of the - :obj:`OptimalControlProblem`, the phase number is set according to its + :obj:`~.OptimalControlProblem`, the phase number is set according to its position in the order of addition to the optimal controls problem's phases, and its phase suffix is set as a string version of the phase number. Finally a replacement of any symbols that may have been used in @@ -247,16 +224,16 @@ def optimal_control_problem(self) -> Optional["OptimalControlProblem"]: accessed after having already been set then an `AttributeError` is raised (see below). The reason this class works like that is to avoid having to allow phases to be disassociated from an - :obj:`OptimalControlProblem` and thus having to handled the complexities + :obj:`~.OptimalControlProblem` and thus having to handled the complexities that would come with the phase renumbering and substitution of any phase-related information that has already been given to the optimal control problem. Raises: - AttributeError: If an :obj:`OptimalControlProblem` has already been + AttributeError: If an :obj:`~.OptimalControlProblem` has already been associated with `self`. If a argument of any type other than - :obj:`OptimalControlProblem` is passed to the - `optimal_control_problem` property setter. + :obj:`~.OptimalControlProblem` is passed to the + :mod:`~.optimal_control_problem` property setter. """ return self._ocp @@ -325,7 +302,7 @@ def initial_state_variables(self) -> TupleSymsType: Raises: AttributeError: If `optimal_control_problem` property has not yet been set to a not None value. See docstring for - `state_variables` for details about why. + :attr:`~.state_variables` for details about why. """ try: return self._y_t0_user @@ -341,7 +318,7 @@ def final_state_variables(self) -> TupleSymsType: Raises: AttributeError: If `optimal_control_problem` property has not yet been set to a not None value. See docstring for - `state_variables` for details about why. + :attr:`~.state_variables` for details about why. """ try: return self._y_tF_user @@ -352,11 +329,13 @@ def final_state_variables(self) -> TupleSymsType: @property def state_variables(self) -> TupleSymsType: - """Symbols for this phase's state variables in order added by user. + """ :class:`Symbol` for this phase's state variables in order added by user. + + The continuous time state variables in this phase. The user may supply either a single symbol or an iterable of symbols. The supplied argument is handled by the `format_as_tuple` method from - the `utils` module. Additional protected attributes `_y_t0_user` and + the :mod:`.~utils` module. Additional protected attributes `_y_t0_user` and `_y_tF_user` are set by post-appending either '_PX(t0)' or '_PX(tF)' to the user supplied symbols where the X is replaced by the phase suffix. As such if this phase has not yet been associated with an optimal @@ -411,11 +390,11 @@ def number_state_variables(self) -> int: @property def control_variables(self) -> TupleSymsType: - """Symbols for this phase's control variables in order added by user. + """:class:`Symbols` for this phase's continious time control variables in order added by user. The user may supply either a single symbol or an iterable of symbols. The supplied argument is handled by the `format_as_tuple` method from - the `utils` module. + the :mod:`.~utils` module. """ return self._u_var_user @@ -484,6 +463,7 @@ def number_state_equations(self) -> int: @property def path_constraints(self): + """The continuous time path constraints associated with this phase.""" return self._c_con_user @path_constraints.setter @@ -500,6 +480,7 @@ def number_path_constraints(self): @property def integrand_functions(self): + """The integrand functions corresponding to the integral variables in this phase.""" return self._q_fnc_user @integrand_functions.setter @@ -518,6 +499,7 @@ def number_integrand_functions(self): @property def bounds(self): + """The phase bounds on this phase. See :obj:`~.PhaseBounds` for more details.""" return self._bounds @bounds.setter @@ -529,6 +511,7 @@ def bounds(self, bounds): @property def scaling(self): + """The phase scaling on this phase. See :obj:`~.PhaseScaling` for more details.""" return self._scaling @scaling.setter @@ -540,6 +523,7 @@ def scaling(self, scaling): @property def mesh(self): + """This initial mesh on which this phase is to be solved.""" return self._mesh @mesh.setter @@ -551,6 +535,7 @@ def mesh(self, mesh): @property def guess(self): + """The initial guess at which this phase is to be solved.""" return self._guess @guess.setter @@ -572,11 +557,8 @@ def _check_variables_and_equations(self): warning to the user describing what is wrong about the supplied state variables and state equations. - Raises - ------ - ValueError - If the state variables and symbols associated with the state - equations are not the same. + Raises: + ValueError: If the state variables and symbols associated with the state equations are not the same. """ try: From 4617149d5c3b8a626d5468cc73cee7ab6e8dd77d Mon Sep 17 00:00:00 2001 From: jtheinen Date: Thu, 29 Jun 2023 18:09:14 +0200 Subject: [PATCH 5/9] OCP untill line 217 --- docs/conf.py | 2 +- pycollo/optimal_control_problem.py | 60 ++++++++++++++++++------------ 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index ea2ac6a..7dfa39f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -42,7 +42,7 @@ "numpy": ("https://numpy.org/doc/stable/", None), "scipy": ("https://docs.scipy.org/doc/scipy/", None), "sympy": ("https://docs.sympy.org/latest/", None), - "py3": ("http://docs.python.org/3",None) + "python": ("http://docs.python.org/3",None) } # -- Options for HTML output ------------------------------------------------- diff --git a/pycollo/optimal_control_problem.py b/pycollo/optimal_control_problem.py index 37aeec8..6d14515 100644 --- a/pycollo/optimal_control_problem.py +++ b/pycollo/optimal_control_problem.py @@ -33,7 +33,7 @@ """ -from typing import AnyStr, Iterable, Tuple +from typing import AnyStr, Iterable, Tuple, Optional import numpy as np @@ -56,23 +56,29 @@ class OptimalControlProblem(): """The main class for Pycollo optimal control problems""" def __init__(self, - name, + name: str, parameter_variables=None, *, - bounds=None, - guess=None, - scaling=None, - endpoint_constraints=None, - objective_function=None, - settings=None, - auxiliary_data=None, - ): + bounds: Optional[EndpointBounds]=None, + guess: Optional[EndpointGuess]=None, + scaling: Optional[EndpointScaling]=None, + endpoint_constraints: Optional=None, + objective_function: Optional[sym.Expr]=None, + settings: Optional[Settings]=None, + auxiliary_data: Optional[dict]=None, + ) -> None: """Initialise the optimal control problem with user-passed objects. Args: - phases (``Iterable`` of :class:`~.Phase`, optional): Phases to be associated with the optimal control problem at initialisation. Defaults to None. - - parameter_variables () + name: Minimally required to initialise + parameter_variables: + bounds: + guess: + scaling: + endpoint_constraints: + objective_function: + settings: + auxiliary_data: """ self.name = name @@ -100,7 +106,7 @@ def name(self) -> str: user may wish to instantiate multiple :obj:`OptimalControlProblem` objects within a single script, or instantiates other Pycollo objects - without providing a valid :class:`~.optimal_control_problem` argument for them to be linked to at initialisation. + without providing a valid :mod:`~.optimal_control_problem` argument for them to be linked to at initialisation. """ return self._name @@ -117,7 +123,7 @@ def phases(self) -> Tuple[Phase, ...]: control problem. As Python uses zero-based indexing the phase numbers do not directly map to the indexes of phases within :attr:`~.phases`. Phases are however ordered sequentially corresponding to the - cronological order they were added to the optimal control problem. + chronological order they were added to the optimal control problem. """ return self._phases @@ -131,10 +137,10 @@ def add_phase(self, phase: Iterable[Phase]) -> Phase: introduced by user interacting with it incorrectly. Args: - phase (Phase): The phase to be added to the optimal control problem + phase (:class:`~.Phase`): The phase to be added to the optimal control problem Returns: - the phase that has been added. It is the same + the phase that has been added. It is the same """ phase.optimal_control_problem = self return self.phases[-1] @@ -177,11 +183,11 @@ def new_phases_like(self, for the :func:`new_phase_like` method. Returns: - The newly instantiated and associated phases. + The newly instantiated and associated phases. Raises: - ValueError: If the same number of names are not supplied as the - number of specified new phases. + ValueError: If the same number of names are not supplied as the + number of specified new phases. """ if len(names) != int(number): msg = ("Must supply a name for each new phase.") @@ -197,11 +203,11 @@ def number_phases(self) -> int: @property def time_symbol(self): - """ - Symbol for time + """Dynamic time symbol, not yet supported Raises: - NotImplementedError: Whenever called to inform the user that these types of problem are not currently supported. + NotImplementedError: Whenever called to inform the user that these + types of problem are not currently supported. """ msg = ("Pycollo do not currently support dynamic, path or integral " "constraints that are explicit functions of continuous time.") @@ -211,7 +217,10 @@ def time_symbol(self): def parameter_variables(self): """Static parameter variables which are optimized within given bounds. - As described in Betts, JT (2010). Bounds and guesses are implemented with :func:`~.bounds` and :func:`~.guess`. + When the instance OCP is created you can supply the parameter variables by OCP_instance.parameter_variables = :class:`tuple` [:class:`Symbol`,...] | :class:`list` [:class:`Symbol`,..] | :obj:`numpy.array` [:class:`Symbol`,...] + + As described in Betts, JT (2010). Bounds and guesses need to be implemented. See :obj:`~.EndPointBounds` and :class:`~.EndPointGuess` how to implement them. + """ return self._s_var_user @@ -227,6 +236,9 @@ def number_parameter_variables(self): @property def endpoint_constraints(self): + """Constraints that are implemented at the initial or final time of phases + + """ return self._b_con_user @endpoint_constraints.setter From 1a7a1d0d4c31888cfc3eb42d649635ebe36821e6 Mon Sep 17 00:00:00 2001 From: jtheinen Date: Fri, 30 Jun 2023 12:23:41 +0200 Subject: [PATCH 6/9] OCP done --- docs/api_reference.rst | 4 +- docs/code_structure.png | Bin 0 -> 187873 bytes pycollo/optimal_control_problem.py | 58 ++++++++++++++++++++++------- 3 files changed, 47 insertions(+), 15 deletions(-) create mode 100644 docs/code_structure.png diff --git a/docs/api_reference.rst b/docs/api_reference.rst index 3a6ad05..64664a1 100644 --- a/docs/api_reference.rst +++ b/docs/api_reference.rst @@ -4,10 +4,12 @@ API Reference ============= +.. image:: code_structure.png + :width: 800 + .. autosummary:: :toctree: _autosummary :recursive: pycollo.optimal_control_problem pycollo.phase - diff --git a/docs/code_structure.png b/docs/code_structure.png new file mode 100644 index 0000000000000000000000000000000000000000..526fa373dfd304ef119f256865632796840826aa GIT binary patch literal 187873 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 -Fj8Xa1J~Q$4lp)W2U%+&#)yu_~cu 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 ZKLf+-E72G8_MB$`0#8>zmvv4FO#q6UT#*0( literal 0 HcmV?d00001 diff --git a/pycollo/optimal_control_problem.py b/pycollo/optimal_control_problem.py index 6d14515..a458eae 100644 --- a/pycollo/optimal_control_problem.py +++ b/pycollo/optimal_control_problem.py @@ -1,10 +1,10 @@ """The main way to define and interact with a Pycollo optimal control problem. -This module contains the main class that the user will interact with to define -and run their optimal control problem when working with Pycollo. Terminolgy is -loosely defined in accordance with "Betts, JT (2010). Practical Methods for -Optimal Control and Estimiation Using Nonlinear Programming (Second Edition)". -See the ``Notes`` section for a full list of symbols used. +Method is used to define the objective function, endpoint constraints, and parameter variables. Each :class:`~.OptimalControlProblem` instance is associated with one or more :class:`~.Phase` instance. + +OCP require bounds and initial guesses to be prescribed before they can numerically be solved, handeled in :mod:`~.bounds` and :mod:`~.guess`. + +Terminolgy is loosely defined in accordance with "Betts, JT (2010). Practical Methods for Optimal Control and Estimiation Using Nonlinear Programming (Second Edition)": Notes: * t: independent parameter (time). @@ -198,7 +198,7 @@ def new_phases_like(self, @property def number_phases(self) -> int: - """Number of phases associated with this optimal control problem.""" + """Returns number of phases associated with this optimal control problem.""" return len(self.phases) @property @@ -220,8 +220,6 @@ def parameter_variables(self): When the instance OCP is created you can supply the parameter variables by OCP_instance.parameter_variables = :class:`tuple` [:class:`Symbol`,...] | :class:`list` [:class:`Symbol`,..] | :obj:`numpy.array` [:class:`Symbol`,...] As described in Betts, JT (2010). Bounds and guesses need to be implemented. See :obj:`~.EndPointBounds` and :class:`~.EndPointGuess` how to implement them. - - """ return self._s_var_user @@ -236,8 +234,11 @@ def number_parameter_variables(self): @property def endpoint_constraints(self): - """Constraints that are implemented at the initial or final time of phases + """Inequality constraints consisting of endpoint variables. + + These constraints are the glue in between the phases. For example, when variables need to be continious throughout multiple phases you can set the y_F of phase A equal to y_0 of phase B. More complex formulations are allowed for example for handeling discontinuities. They are formulated as inequality constraint, but by clever formulating can be handeled as equality constraints (A-B > [0,0]) + Bounds should be implemented. See :obj:`~.EndPointBounds` how to implement them. """ return self._b_con_user @@ -250,11 +251,16 @@ def endpoint_constraints(self, b_cons): ) @property - def number_endpoint_constraints(self): + def number_endpoint_constraints(self) -> int: + """Returns number of endpoint constraints""" return len(self._b_con_user) @property def objective_function(self): + """Formula to be minimised during the optimization. + + It is a `Bolza` objective function which may be a function of endpoint variables or parameter variables (:attr:`~.integral_variables`, :attr:`~.initial_time_variable`, :attr:`~.final_time_variable`, :attr:`~.initial_state_variable, and :attr:`~.final_state_variable or :attr:`~.parameter_variables` ). + """ return self._J_user @objective_function.setter @@ -264,6 +270,9 @@ def objective_function(self, J): @property def auxiliary_data(self): + """:class:`dict` containing extra provided data. + + When a symbolic variable (:class:`Symbol`) is indetermined, make sure to assign it to a numerical value or symbolic formulation with this function """ return self._aux_data_user @auxiliary_data.setter @@ -271,7 +280,8 @@ def auxiliary_data(self, aux_data): self._aux_data_user = dict(aux_data) @property - def bounds(self): + def bounds(self) -> EndpointBounds: + """Attribute to provide bounds to :attr:`~.parameter_variables`, and :attr:`~.endpoint_constraints`""" return self._bounds @bounds.setter @@ -283,7 +293,8 @@ def bounds(self, bounds): self._bounds._ocp = self @property - def guess(self): + def guess(self) -> EndpointGuess: + """Attribute to provide initial guess to :attr:`~.parameter_variables`, and :attr:`~.endpoint_constraints`""" return self._guess @guess.setter @@ -311,11 +322,15 @@ def mesh_iterations(self): return self._mesh_iterations @property - def num_mesh_iterations(self): + def num_mesh_iterations(self) -> int: + """Returns number of mesh iterations""" return len(self._backend.mesh_iterations) @property - def settings(self): + def settings(self) -> Settings: + """Attribute to overwrite default settings. + + See :mod:`~.settings` for all settings options""" return self._settings @settings.setter @@ -328,6 +343,21 @@ def settings(self, settings): @property def solution(self): + """ Attribute where all solutions are found after solving the OCP (:func:`~.solve`). + + Solutions are provided by indexing. OCP_instance.solution.attribute[x][y] refers to the y`th attribute in phase x + + Attributes: + objective: Numerical solution of :attr:`~.objective_function` + initial_time: Initial times of phases of solved OCP + final_time: Final times of phases of solved OCP + state: Numerical solution of state_variables` + state_derivative: Numerical solution of :attr:`~.state_equations` + control: Numerical solution of :attr:`~.control` + integral: Numerical solution of :attr:`~.integrand_function` + time: Numerical solution of time + parameter: Numerical solution of :attr:`~.parameter_variables` + """ return self._backend.mesh_iterations[-1].solution def initialise(self): From aae39726b12e2d45a74a1a8790b5123b663b6782 Mon Sep 17 00:00:00 2001 From: jtheinen Date: Fri, 30 Jun 2023 16:29:01 +0200 Subject: [PATCH 7/9] Phase done, added typehinting for phase and ocp --- pycollo/optimal_control_problem.py | 61 +++++---- pycollo/phase.py | 204 ++++++++++++----------------- 2 files changed, 118 insertions(+), 147 deletions(-) diff --git a/pycollo/optimal_control_problem.py b/pycollo/optimal_control_problem.py index a458eae..6f90583 100644 --- a/pycollo/optimal_control_problem.py +++ b/pycollo/optimal_control_problem.py @@ -46,7 +46,7 @@ from .phase import Phase from .scaling import EndpointScaling from .settings import Settings -from .typing import OptionalSymsType +from .typing import OptionalSymsType, OptionalExprsType, OptionalBoundsType, TupleSymsType from .utils import check_sym_name_clash, console_out, format_as_data_container __all__ = ["OptimalControlProblem"] @@ -71,14 +71,18 @@ def __init__(self, Args: name: Minimally required to initialise - parameter_variables: - bounds: - guess: + parameter_variables: Optimised variables which will solve to single + numerical number over all phases. + bounds: Problem specific bounds. See :obj:`.~EndpointBounds` for + more details. Default value is None in which case an empty + :obj:`.~EndpointBounds` object is instantiated and associated with the OCP. + guess: The initial guess at which this OCP is to be solved. + Default value is None in which case an empty :obj:`EndpointGuess` object is instantiated. scaling: - endpoint_constraints: - objective_function: - settings: - auxiliary_data: + endpoint_constraints: Endpoint constraints which bound this OCP. Default to None + objective_function: Instance to be minimised. Defaults to None. + settings: All OCP settings. Defaults to default settings in :class:`~.Settings`. + auxiliary_data: Extra data provided by user. Defaults to empty :class:`dict`. """ self.name = name @@ -111,7 +115,7 @@ def name(self) -> str: return self._name @name.setter - def name(self, name: AnyStr): + def name(self, name: AnyStr) -> None: self._name = str(name) @property @@ -167,7 +171,7 @@ def new_phase(self, control_variables=control_variables) return new_phase - def new_phase_like(self, phase_for_copying: Phase, name: str, **kwargs): + def new_phase_like(self, phase_for_copying: Phase, name: str, **kwargs) -> Phase: """Creates new phase while copying all implemented values from `phase_for_copying` """ return phase_for_copying.create_new_copy(name, **kwargs) @@ -214,7 +218,7 @@ def time_symbol(self): raise NotImplementedError(msg) @property - def parameter_variables(self): + def parameter_variables(self) -> TupleSymsType: """Static parameter variables which are optimized within given bounds. When the instance OCP is created you can supply the parameter variables by OCP_instance.parameter_variables = :class:`tuple` [:class:`Symbol`,...] | :class:`list` [:class:`Symbol`,..] | :obj:`numpy.array` [:class:`Symbol`,...] @@ -224,7 +228,7 @@ def parameter_variables(self): return self._s_var_user @parameter_variables.setter - def parameter_variables(self, s_vars): + def parameter_variables(self, s_vars: OptionalSymsType) -> None: self._s_var_user = format_as_data_container("ParameterVariables", s_vars) _ = check_sym_name_clash(self._s_var_user) @@ -233,7 +237,7 @@ def number_parameter_variables(self): len(self._s_var_user) @property - def endpoint_constraints(self): + def endpoint_constraints(self) -> OptionalExprsType: """Inequality constraints consisting of endpoint variables. These constraints are the glue in between the phases. For example, when variables need to be continious throughout multiple phases you can set the y_F of phase A equal to y_0 of phase B. More complex formulations are allowed for example for handeling discontinuities. They are formulated as inequality constraint, but by clever formulating can be handeled as equality constraints (A-B > [0,0]) @@ -243,7 +247,7 @@ def endpoint_constraints(self): return self._b_con_user @endpoint_constraints.setter - def endpoint_constraints(self, b_cons): + def endpoint_constraints(self, b_cons: OptionalExprsType) -> None: self._b_con_user = format_as_data_container( "EndpointConstraints", b_cons, @@ -256,7 +260,7 @@ def number_endpoint_constraints(self) -> int: return len(self._b_con_user) @property - def objective_function(self): + def objective_function(self) -> OptionalExprsType: """Formula to be minimised during the optimization. It is a `Bolza` objective function which may be a function of endpoint variables or parameter variables (:attr:`~.integral_variables`, :attr:`~.initial_time_variable`, :attr:`~.final_time_variable`, :attr:`~.initial_state_variable, and :attr:`~.final_state_variable or :attr:`~.parameter_variables` ). @@ -264,19 +268,19 @@ def objective_function(self): return self._J_user @objective_function.setter - def objective_function(self, J): + def objective_function(self, J: OptionalExprsType) -> None: self._J_user = sym.sympify(J) # self._forward_dynamics = True if self._J_user == 1 else False @property - def auxiliary_data(self): + def auxiliary_data(self) -> dict[OptionalSymsType]: """:class:`dict` containing extra provided data. When a symbolic variable (:class:`Symbol`) is indetermined, make sure to assign it to a numerical value or symbolic formulation with this function """ return self._aux_data_user @auxiliary_data.setter - def auxiliary_data(self, aux_data): + def auxiliary_data(self, aux_data: dict[OptionalSymsType, int]) -> None: self._aux_data_user = dict(aux_data) @property @@ -285,7 +289,7 @@ def bounds(self) -> EndpointBounds: return self._bounds @bounds.setter - def bounds(self, bounds): + def bounds(self, bounds: OptionalBoundsType) -> None: if bounds is None: self._bounds = EndpointBounds(optimal_control_problem=self) else: @@ -298,7 +302,7 @@ def guess(self) -> EndpointGuess: return self._guess @guess.setter - def guess(self, guess): + def guess(self, guess: OptionalBoundsType) -> None: if guess is None: self._guess = EndpointGuess(optimal_control_problem=self) else: @@ -306,11 +310,11 @@ def guess(self, guess): self._guess.optimal_control_problem = self @property - def scaling(self): + def scaling(self) -> EndpointScaling: return self._scaling @scaling.setter - def scaling(self, scaling): + def scaling(self, scaling: EndpointScaling) -> None: if scaling is None: self._scaling = EndpointScaling(optimal_control_problem=self) else: @@ -334,7 +338,7 @@ def settings(self) -> Settings: return self._settings @settings.setter - def settings(self, settings): + def settings(self, settings: Settings) -> None: if settings is None: self._settings = Settings(optimal_control_problem=self) else: @@ -360,7 +364,7 @@ def solution(self): """ return self._backend.mesh_iterations[-1].solution - def initialise(self): + def initialise(self) -> None: """Initialise the optimal control problem before solving. The initialisation of the optimal control problem involves the @@ -431,7 +435,7 @@ def _initialise_initial_mesh(self): def _initialise_first_mesh_iteration(self): self._backend.create_mesh_iterations() - def solve(self, display_progress=False): + def solve(self, display_progress=False) -> None: """Solve the optimal control problem. If the initialisation flag is not set to True then the initialisation @@ -455,11 +459,10 @@ def _check_if_initialisation_required_before_solve(self): if not self._is_initialised: self.initialise() - def _solve_iteration(self): + def _solve_iteration(self) -> bool: """Solve a single mesh iteration. - Return: - bool + Return(bool): True is mesh tolerance is met or if maximum number of mesh iterations has been reached. @@ -600,7 +603,7 @@ def time_results(): mesh_results() time_results() - def __str__(self): + def __str__(self) -> str: """Returns name of OCP""" return self.name diff --git a/pycollo/phase.py b/pycollo/phase.py index 85097c0..d34398c 100644 --- a/pycollo/phase.py +++ b/pycollo/phase.py @@ -1,7 +1,7 @@ """Everything needed for defining phases within an optimal control problem.""" import copy -from typing import Optional, Tuple +from typing import Optional, Tuple, Iterable import sympy as sym @@ -9,7 +9,7 @@ from .guess import PhaseGuess from .mesh import PhaseMesh from .scaling import PhaseScaling -from .typing import OptionalExprsType, OptionalSymsType, TupleSymsType +from .typing import OptionalExprsType, OptionalSymsType, TupleSymsType, OptionalBoundsType from .utils import check_sym_name_clash, format_as_data_container __all__ = ["Phase"] @@ -18,30 +18,8 @@ class Phase: """A single continuous time phase as part of an optimal control problem. - Attributes: - _name: Protected version of :attr:`name`. - _ocp: Protected version of :attr:`optimal_control_problem`. - _phase_number: Protected integer number associated with this phase. If - not associated with any optimal control problem then defaults to - None until one is associated. These are ordered sequentially - starting at '0' in the order with which phases are added to an - optimal control problem. - _phase_suffix: Protected str which is used in the naming of auto- - generated Pycollo variables such as the endpoint state variables. - _y_var_user: Protected version of :attr:`state_variables`. - _u_var_user: Protected version of :attr:`control_variables`. - _q_var_user: Protected version of :attr:`integral_variables`. - _t_var_user: Protected version of :attr:`time_variables`. - _y_eqn_user: Protected version of :attr:`state_equations`. - _c_con_user: Protected version of :attr:`path_constraints`. - _q_fnc_user: Protected version of :attr:`integrand_functions`. - _t0_USER: Protected version of :attr:`initial_time_variable`. - _tF_USER: Protected version of :attr:`final_time_variable`. - _t0: Internal Pycollo symbol for phase initial time. - _tF: Internal Pycollo symbol for phase final time. - _STRETCH: Convenience expression for phase time scaling stretch. - _SHIFT: Convenience expression for phase time scaling shift. - """ + State, control, integral and time variables are defined per phase. + Also state equations, path constraints, integrand functions and state endpoint constraints are defined here.""" def __init__(self, name: str, @@ -56,47 +34,47 @@ def __init__(self, scaling: Optional[PhaseScaling] = None, guess: Optional[PhaseGuess] = None, mesh: Optional[PhaseMesh] = None, - ): + ) -> None: """Initialise the Phase object with minimum a name. Args: - name: The name associated with a problem. Should be something short - like 'A'. - optimal_control_problem: The OptimalControlProblem with - which this phase is to be associated. Default value is None in - which case the phase remain uninitialised to an optimal control - problem. - state_variables: The continuous time state variables in this phase. - Default value is None in which case the phase has no associated - state variables and no phase-specific endpoint time or state - variables are created. - control_variables: The continuous time control variables in this - phase. Default value is None in which case the phase has no - associated control variables. - state_equations: The dynamical state equations associated with this - state variables in this phase. Default value is None in which - case no dynamical equations have been added to the phase yet. - integrand_functions: The integrand functions corresponding to the - integral variables in this phase. Default value is None in - which case the phase has no integrand functions associated with - it and no phase-specific integral variables are created. - path_constraints: The continuous time path constraints associated - with this phase. Default value is None in which case the phase - has no path constraints associated with it. - bounds: The phase bounds on this phase. See :obj:PhaseBounds for - more details. Default value is None in which case an empty - :obj:`PhaseBounds` object is instantiated and associated with - the phase. - scaling: The phase scaling on this phase. See :obj:PhaseScaling for - more details. Default value is None in which case an empty - :obj:`PhaseScaling` object is instantiated and associated with - the phase. - guess: The initial guess at which this phase is to be solved. - Default value is None in which case an empty :obj:`PhaseGuess` - object is instantiated and associated with the phase. - mesh: This initial mesh on which this phase is to be solved. - Default value is None in which case an empty :obj:`PhaseMesh` - object is instantiated and associated with the phase. + name: The name associated with a problem. Should be something short + like 'A'. + optimal_control_problem: The OptimalControlProblem with + which this phase is to be associated. Default value is None in + which case the phase remain uninitialised to an optimal control + problem. + state_variables: The continuous time state variables in this phase. + Default value is None in which case the phase has no associated + state variables and no phase-specific endpoint time or state + variables are created. + control_variables: The continuous time control variables in this + phase. Default value is None in which case the phase has no + associated control variables. + state_equations: The dynamical state equations associated with this + state variables in this phase. Default value is None in which + case no dynamical equations have been added to the phase yet. + integrand_functions: The integrand functions corresponding to the + integral variables in this phase. Default value is None in + which case the phase has no integrand functions associated with + it and no phase-specific integral variables are created. + path_constraints: The continuous time path constraints associated + with this phase. Default value is None in which case the phase + has no path constraints associated with it. + bounds: The phase bounds on this phase. See :obj:`.~PhaseBounds` for + more details. Default value is None in which case an empty + :obj:`.~PhaseBounds` object is instantiated and associated with + the phase. + scaling: The phase scaling on this phase. See :obj:PhaseScaling for + more details. Default value is None in which case an empty + :obj:`~.PhaseScaling` object is instantiated and associated with + the phase. + guess: The initial guess at which this phase is to be solved. + Default value is None in which case an empty :obj:`PhaseGuess` + object is instantiated and associated with the phase. + mesh: This initial mesh on which this phase is to be solved. + Default value is None in which case an empty :obj:`PhaseMesh` + object is instantiated and associated with the phase. """ self._name = str(name) @@ -143,8 +121,8 @@ def create_new_copy(self, copy_mesh: bool = True, copy_scaling: bool = True, copy_guess: bool = True, - ): - + ) -> "Phase": + """Creates copy of a Phase instance. Use :meth:`~.create_new_copy_like` to automatically add Phase to OCP instance""" self._check_variables_and_equations() new_phase = Phase(name, optimal_control_problem=self.optimal_control_problem) @@ -194,7 +172,7 @@ def create_new_copy_like(phase_for_copying: "Phase", name: str, **kwargs): return phase_for_copying.create_new_copy(name, **kwargs) @property - def name(self): + def name(self) -> str: """The name associated with a problem. Should be something short like 'A'.""" return self._name @@ -230,15 +208,13 @@ def optimal_control_problem(self) -> Optional["OptimalControlProblem"]: control problem. Raises: - AttributeError: If an :obj:`~.OptimalControlProblem` has already been - associated with `self`. If a argument of any type other than - :obj:`~.OptimalControlProblem` is passed to the - :mod:`~.optimal_control_problem` property setter. + AttributeError: If an :obj:`~.OptimalControlProblem` has already + been associated with `self`. If a argument of any type other than :obj:`~.OptimalControlProblem` is passed to the :mod:`~.optimal_control_problem` property setter. """ return self._ocp @optimal_control_problem.setter - def optimal_control_problem(self, ocp): + def optimal_control_problem(self, ocp) -> None: if self._ocp is not None: msg = ('Optimal control problem is already set for this phase and ' 'cannot be reset.') @@ -300,9 +276,7 @@ def initial_state_variables(self) -> TupleSymsType: """Symbols for this phase's state variables at the initial time. Raises: - AttributeError: If `optimal_control_problem` property has not yet - been set to a not None value. See docstring for - :attr:`~.state_variables` for details about why. + AttributeError: If :attr:`~.optimal_control_problem` property has not yet been set to a not None value. See docstring for :attr:`~.state_variables` for details about why. """ try: return self._y_t0_user @@ -316,9 +290,8 @@ def final_state_variables(self) -> TupleSymsType: """Symbols for this phase's state variables at the final time. Raises: - AttributeError: If `optimal_control_problem` property has not yet - been set to a not None value. See docstring for - :attr:`~.state_variables` for details about why. + AttributeError: If `optimal_control_problem` property has not yet + been set to a not None value. See docstring for :attr:`~.state_variables` for details about why. """ try: return self._y_tF_user @@ -329,24 +302,16 @@ def final_state_variables(self) -> TupleSymsType: @property def state_variables(self) -> TupleSymsType: - """ :class:`Symbol` for this phase's state variables in order added by user. + """:class:`Symbols` for this phase's continuous time state variables in order added by user. - The continuous time state variables in this phase. - The user may supply either a single symbol or an iterable of symbols. The supplied argument is handled by the `format_as_tuple` method from - the :mod:`.~utils` module. Additional protected attributes `_y_t0_user` and - `_y_tF_user` are set by post-appending either '_PX(t0)' or '_PX(tF)' to - the user supplied symbols where the X is replaced by the phase suffix. - As such if this phase has not yet been associated with an optimal - control problem yet then `self` will not have attributes `_y_t0_user` - and `_y_tF_user` and accessing either the `initial_state` or - `final_state` property will raise an AttributeError. + the :mod:`.~utils` module. Additional protected attributes `_y_t0_user` and `_y_tF_user` are set by post-appending either '_PX(t0)' or '_PX(tF)' to the user supplied symbols where the X is replaced by the phase suffix. As such if this phase has not yet been associated with an optimal control problem yet then `self` will not have attributes `_y_t0_user` and `_y_tF_user` and accessing either the `initial_state` or `final_state` property will raise an AttributeError. """ return self._y_var_user @state_variables.setter - def state_variables(self, y_vars: OptionalSymsType): + def state_variables(self, y_vars: OptionalSymsType) -> None: self._y_var_user = format_as_data_container("StateVariables", y_vars) check_sym_name_clash(self._y_var_user) @@ -385,7 +350,7 @@ def state_variables(self, y_vars: OptionalSymsType): @property def number_state_variables(self) -> int: - """Integer number of state variables in the phase.""" + """Returns number of state variables in the phase.""" return len(self._y_var_user) @property @@ -399,21 +364,18 @@ def control_variables(self) -> TupleSymsType: return self._u_var_user @control_variables.setter - def control_variables(self, u_vars: OptionalSymsType): + def control_variables(self, u_vars: OptionalSymsType) -> None: self._u_var_user = format_as_data_container("ControlVariables", u_vars) check_sym_name_clash(self._u_var_user) @property def number_control_variables(self) -> int: - """Integer number of control variables in the phase.""" + """Returns number of control variables in the phase.""" return len(self._u_var_user) @property def integral_variables(self) -> TupleSymsType: - """Symbols for this phase's integral variables. - - These symbols are auto generated as required by the user-supplied - integrand functions. + """Auto generated integral_variablessymbols as required by the user-supplied integrand functions. """ return self._q_var_user @@ -424,23 +386,23 @@ def time_variables(self) -> TupleSymsType: @property def number_integral_variables(self) -> int: - """Integer number of integral variables in the phase.""" + """Returns number of integral variables in this phase.""" return len(self._q_var_user) @property def state_equations(self) -> Tuple[sym.Expr, ...]: """User-supplied dynamical equations in the phase. - - These equations are the dynamical equations associated with each of the + + These dynamical equations are associated with each of the state variables in the phase. There should therefore be exactly one - state equation for each dynamics symbol. + state equation for each state variable. - State equations can be supplied in a compact form by the user defining additional auxiliary symbols and + State equations can be supplied in a compact form by the user defining additional auxiliary symbols. """ return self._y_eqn_user @state_equations.setter - def state_equations(self, y_eqns: OptionalExprsType): + def state_equations(self, y_eqns: OptionalExprsType) -> None: try: identifiers = self._y_var_user._field_names except AttributeError: @@ -454,7 +416,7 @@ def state_equations(self, y_eqns: OptionalExprsType): @property def number_state_equations(self) -> int: - """Integer number of state equations in the phase. + """Returns number of state equations in the phase. Should be the same as the number of state variables, i.e. there should be a direct mapping between the two. @@ -462,12 +424,17 @@ def number_state_equations(self) -> int: return len(self._y_eqn_user) @property - def path_constraints(self): - """The continuous time path constraints associated with this phase.""" + def path_constraints(self) -> TupleSymsType: + """The continuous time path constraints associated with this phase. + + Path constraints are inequality constraints as a function of continious time variables (i.e. state variables, control variables). Bounds need to be applied. + The introduction of additional path constraints is not ideal as these increase the complexity of the NLP and its di culty to solve, and should be avoided if possible. + They are formulated as inequality constraint, but by clever formulating can be handeled as equality constraints (A-B > [0,0]) + """ return self._c_con_user @path_constraints.setter - def path_constraints(self, c_cons): + def path_constraints(self, c_con: OptionalExprsType) -> None: self._c_con_user = format_as_data_container( "PathConstraints", c_cons, @@ -475,16 +442,17 @@ def path_constraints(self, c_cons): ) @property - def number_path_constraints(self): + def number_path_constraints(self) -> int: + """Returns number of path constraints""" return len(self._c_con_user) @property - def integrand_functions(self): + def integrand_functions(self) -> TupleSymsType: """The integrand functions corresponding to the integral variables in this phase.""" return self._q_fnc_user @integrand_functions.setter - def integrand_functions(self, integrands): + def integrand_functions(self, integrands: OptionalExprsType) -> None: self._q_fnc_user = format_as_data_container( "IntegrandFunctions", integrands, @@ -494,52 +462,52 @@ def integrand_functions(self, integrands): for i_q, _ in enumerate(self._q_fnc_user)) @property - def number_integrand_functions(self): + def number_integrand_functions(self) -> int: return len(self._q_fnc_user) @property - def bounds(self): + def bounds(self) -> PhaseBounds: """The phase bounds on this phase. See :obj:`~.PhaseBounds` for more details.""" return self._bounds @bounds.setter - def bounds(self, bounds): + def bounds(self, bounds: OptionalBoundsType) -> None: if bounds is None: self._bounds = PhaseBounds(phase=self) else: self._bounds = bounds @property - def scaling(self): + def scaling(self) -> PhaseScaling: """The phase scaling on this phase. See :obj:`~.PhaseScaling` for more details.""" return self._scaling @scaling.setter - def scaling(self, scaling): + def scaling(self, scaling: PhaseScaling) -> None: if scaling is None: self._scaling = PhaseScaling(phase=self) else: self._scaling = scaling @property - def mesh(self): + def mesh(self) -> PhaseMesh: """This initial mesh on which this phase is to be solved.""" return self._mesh @mesh.setter - def mesh(self, mesh): + def mesh(self, mesh: PhaseMesh) -> None: if mesh is None: self._mesh = PhaseMesh(phase=self) else: self._mesh = mesh @property - def guess(self): + def guess(self) -> PhaseGuess: """The initial guess at which this phase is to be solved.""" return self._guess @guess.setter - def guess(self, guess): + def guess(self, guess: PhaseGuess) -> None: if guess is None: self._guess = PhaseGuess(phase=self) else: From 0e2daa930aaf55e8aa947a4f418d41d4c18ed65b Mon Sep 17 00:00:00 2001 From: jtheinen Date: Thu, 17 Aug 2023 16:33:23 +0200 Subject: [PATCH 8/9] typehint resolved, hide __weakref__ --- .../pycollo.optimal_control_problem.OptimalControlProblem.rst | 3 ++- docs/_autosummary/pycollo.phase.Phase.rst | 3 ++- docs/_templates/autosummary/class.rst | 1 + docs/conf.py | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/_autosummary/pycollo.optimal_control_problem.OptimalControlProblem.rst b/docs/_autosummary/pycollo.optimal_control_problem.OptimalControlProblem.rst index e74755c..70960c9 100644 --- a/docs/_autosummary/pycollo.optimal_control_problem.OptimalControlProblem.rst +++ b/docs/_autosummary/pycollo.optimal_control_problem.OptimalControlProblem.rst @@ -1,4 +1,4 @@ -.. +.. class.rst pycollo.optimal\_control\_problem.OptimalControlProblem @@ -11,6 +11,7 @@ pycollo.optimal\_control\_problem.OptimalControlProblem :show-inheritance: :inherited-members: :special-members: + :exclude-members: __weakref__ diff --git a/docs/_autosummary/pycollo.phase.Phase.rst b/docs/_autosummary/pycollo.phase.Phase.rst index 3dd7bb5..f7f9f70 100644 --- a/docs/_autosummary/pycollo.phase.Phase.rst +++ b/docs/_autosummary/pycollo.phase.Phase.rst @@ -1,4 +1,4 @@ -.. +.. class.rst pycollo.phase.Phase @@ -11,6 +11,7 @@ pycollo.phase.Phase :show-inheritance: :inherited-members: :special-members: + :exclude-members: __weakref__ diff --git a/docs/_templates/autosummary/class.rst b/docs/_templates/autosummary/class.rst index c283f48..e192c84 100644 --- a/docs/_templates/autosummary/class.rst +++ b/docs/_templates/autosummary/class.rst @@ -10,6 +10,7 @@ :show-inheritance: :inherited-members: :special-members: + :exclude-members: __weakref__ {% block methods %} {% if methods %} diff --git a/docs/conf.py b/docs/conf.py index a7f3222..ae5bffb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -24,6 +24,7 @@ "sphinx.ext.napoleon", "sphinx.ext.intersphinx", "sphinx.ext.autodoc", + "sphinx_autodoc_typehints", "sphinx.ext.autosummary", "sphinx.ext.mathjax", "sphinx.ext.viewcode", From 710364e89d64c9816a04c5e5d244fe92ebe572a1 Mon Sep 17 00:00:00 2001 From: jtheinen Date: Sun, 27 Aug 2023 23:42:33 +0200 Subject: [PATCH 9/9] hiding __repr__ and __str__ --- docs/_templates/autosummary/class.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_templates/autosummary/class.rst b/docs/_templates/autosummary/class.rst index e192c84..f7e7609 100644 --- a/docs/_templates/autosummary/class.rst +++ b/docs/_templates/autosummary/class.rst @@ -10,7 +10,7 @@ :show-inheritance: :inherited-members: :special-members: - :exclude-members: __weakref__ + :exclude-members: __weakref__, __repr__, __str__ {% block methods %} {% if methods %}