sleipnirgroup-jormungandr 0.0.1.dev475__tar.gz → 0.0.1.dev476__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/CMakeLists.txt +9 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/PKG-INFO +1 -1
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/optimization/solver/exit_status.hpp +11 -6
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/optimization/solver/interior_point.hpp +5 -1
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/cpp/docstrings.hpp +4 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/cpp/optimization/solver/bind_exit_status.cpp +2 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/optimization/nonlinear_problem_test.py +19 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/pyproject.toml +1 -1
- sleipnirgroup_jormungandr-0.0.1.dev476/src/optimization/bounds.hpp +220 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/optimization/problem.cpp +19 -1
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/optimization/solver/interior_point.cpp +9 -1
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/util/print_diagnostics.hpp +19 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/LICENSE.txt +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/README.md +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/SleipnirConfig.cmake.in +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/cmake/modules/BuildTypes.cmake +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/cmake/modules/CompilerFlags.cmake +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/cmake/modules/Pybind11Mkdoc.cmake +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/cmake/modules/SubdirList.cmake +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/.styleguide +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/autodiff/adjoint_expression_graph.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/autodiff/expression.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/autodiff/expression_graph.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/autodiff/expression_type.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/autodiff/gradient.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/autodiff/hessian.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/autodiff/jacobian.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/autodiff/slice.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/autodiff/variable.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/autodiff/variable_block.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/autodiff/variable_matrix.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/control/ocp.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/optimization/multistart.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/optimization/problem.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/optimization/solver/iteration_info.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/optimization/solver/newton.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/optimization/solver/options.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/optimization/solver/sqp.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/util/assert.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/util/concepts.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/util/function_ref.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/util/intrusive_shared_ptr.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/util/pool.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/util/print.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/util/spy.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/include/sleipnir/util/symbol_exports.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/__init__.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/autodiff/__init__.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/control/__init__.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/cpp/autodiff/bind_expression_type.cpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/cpp/autodiff/bind_gradient.cpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/cpp/autodiff/bind_hessian.cpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/cpp/autodiff/bind_jacobian.cpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/cpp/autodiff/bind_variable.cpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/cpp/autodiff/bind_variable_block.cpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/cpp/autodiff/bind_variable_matrix.cpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/cpp/binders.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/cpp/control/bind_ocp.cpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/cpp/main.cpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/cpp/optimization/bind_equality_constraints.cpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/cpp/optimization/bind_inequality_constraints.cpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/cpp/optimization/bind_problem.cpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/cpp/optimization/solver/bind_iteration_info.cpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/cpp/try_cast.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/optimization/__init__.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/autodiff/gradient_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/autodiff/hessian_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/autodiff/jacobian_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/autodiff/variable_matrix_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/autodiff/variable_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/cart_pole_util.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/control/cart_pole_ocp_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/control/differential_drive_ocp_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/control/flywheel_ocp_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/differential_drive_util.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/optimization/arm_on_elevator_problem_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/optimization/cart_pole_problem_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/optimization/constraints_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/optimization/decision_variable_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/optimization/differential_drive_problem_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/optimization/double_integrator_problem_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/optimization/exit_status_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/optimization/flywheel_problem_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/optimization/linear_problem_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/optimization/multistart_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/optimization/quadratic_problem_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/optimization/trivial_problem_test.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/jormungandr/test/rk4.py +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/.styleguide +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/autodiff/variable_matrix.cpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/optimization/inertia.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/optimization/regularized_ldlt.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/optimization/solver/newton.cpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/optimization/solver/sqp.cpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/optimization/solver/util/error_estimate.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/optimization/solver/util/filter.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/optimization/solver/util/fraction_to_the_boundary_rule.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/optimization/solver/util/is_locally_infeasible.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/optimization/solver/util/kkt_error.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/util/pool.cpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/util/scope_exit.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/util/scoped_profiler.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/util/setup_profiler.hpp +0 -0
- {sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/util/solve_profiler.hpp +0 -0
{sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/CMakeLists.txt
RENAMED
@@ -71,6 +71,11 @@ option(BUILD_BENCHMARKS "Build CasADi and Sleipnir benchmarks" OFF)
|
|
71
71
|
option(BUILD_EXAMPLES "Build examples" OFF)
|
72
72
|
option(BUILD_PYTHON "Build Python module" OFF)
|
73
73
|
option(DISABLE_DIAGNOSTICS "Disable diagnostics support at compile-time" OFF)
|
74
|
+
option(
|
75
|
+
ENABLE_BOUND_PROJECTION
|
76
|
+
"Enable projecting the state onto bound inequality constraints inside problem setup"
|
77
|
+
OFF
|
78
|
+
)
|
74
79
|
|
75
80
|
include(CompilerFlags)
|
76
81
|
|
@@ -104,6 +109,10 @@ if(DISABLE_DIAGNOSTICS)
|
|
104
109
|
target_compile_definitions(Sleipnir PUBLIC SLEIPNIR_DISABLE_DIAGNOSTICS)
|
105
110
|
endif()
|
106
111
|
|
112
|
+
if(ENABLE_BOUND_PROJECTION)
|
113
|
+
target_compile_definitions(Sleipnir PUBLIC SLEIPNIR_ENABLE_BOUND_PROJECTION)
|
114
|
+
endif()
|
115
|
+
|
107
116
|
# Eigen dependency
|
108
117
|
if(NOT USE_SYSTEM_EIGEN)
|
109
118
|
set(EIGEN_BUILD_CMAKE_PACKAGE TRUE)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: sleipnirgroup-jormungandr
|
3
|
-
Version: 0.0.1.
|
3
|
+
Version: 0.0.1.dev476
|
4
4
|
Summary: A linearity-exploiting sparse nonlinear constrained optimization problem solver that uses the interior-point method.
|
5
5
|
License: Copyright (c) Sleipnir contributors
|
6
6
|
|
@@ -22,21 +22,24 @@ enum class ExitStatus : int8_t {
|
|
22
22
|
TOO_FEW_DOFS = -1,
|
23
23
|
/// The solver determined the problem to be locally infeasible and gave up.
|
24
24
|
LOCALLY_INFEASIBLE = -2,
|
25
|
+
/// The problem setup frontend determined the problem to have an empty
|
26
|
+
/// feasible region.
|
27
|
+
GLOBALLY_INFEASIBLE = -3,
|
25
28
|
/// The linear system factorization failed.
|
26
|
-
FACTORIZATION_FAILED = -
|
29
|
+
FACTORIZATION_FAILED = -4,
|
27
30
|
/// The backtracking line search failed, and the problem isn't locally
|
28
31
|
/// infeasible.
|
29
|
-
LINE_SEARCH_FAILED = -
|
32
|
+
LINE_SEARCH_FAILED = -5,
|
30
33
|
/// The solver encountered nonfinite initial cost or constraints and gave up.
|
31
|
-
NONFINITE_INITIAL_COST_OR_CONSTRAINTS = -
|
34
|
+
NONFINITE_INITIAL_COST_OR_CONSTRAINTS = -6,
|
32
35
|
/// The solver encountered diverging primal iterates xₖ and/or sₖ and gave up.
|
33
|
-
DIVERGING_ITERATES = -
|
36
|
+
DIVERGING_ITERATES = -7,
|
34
37
|
/// The solver returned its solution so far after exceeding the maximum number
|
35
38
|
/// of iterations.
|
36
|
-
MAX_ITERATIONS_EXCEEDED = -
|
39
|
+
MAX_ITERATIONS_EXCEEDED = -8,
|
37
40
|
/// The solver returned its solution so far after exceeding the maximum
|
38
41
|
/// elapsed wall clock time.
|
39
|
-
TIMEOUT = -
|
42
|
+
TIMEOUT = -9,
|
40
43
|
};
|
41
44
|
|
42
45
|
/**
|
@@ -57,6 +60,8 @@ SLEIPNIR_DLLEXPORT constexpr std::string_view to_message(
|
|
57
60
|
return "too few degrees of freedom";
|
58
61
|
case LOCALLY_INFEASIBLE:
|
59
62
|
return "locally infeasible";
|
63
|
+
case GLOBALLY_INFEASIBLE:
|
64
|
+
return "globally infeasible";
|
60
65
|
case FACTORIZATION_FAILED:
|
61
66
|
return "factorization failed";
|
62
67
|
case LINE_SEARCH_FAILED:
|
@@ -223,6 +223,10 @@ SLEIPNIR_DLLEXPORT ExitStatus
|
|
223
223
|
interior_point(const InteriorPointMatrixCallbacks& matrix_callbacks,
|
224
224
|
std::span<std::function<bool(const IterationInfo& info)>>
|
225
225
|
iteration_callbacks,
|
226
|
-
const Options& options,
|
226
|
+
const Options& options,
|
227
|
+
#ifdef SLEIPNIR_ENABLE_BOUND_PROJECTION
|
228
|
+
const Eigen::ArrayX<bool>& bound_constraint_mask,
|
229
|
+
#endif
|
230
|
+
Eigen::VectorXd& x);
|
227
231
|
|
228
232
|
} // namespace slp
|
@@ -78,6 +78,10 @@ up.)doc";
|
|
78
78
|
|
79
79
|
static const char *__doc_slp_ExitStatus_FACTORIZATION_FAILED = R"doc(The linear system factorization failed.)doc";
|
80
80
|
|
81
|
+
static const char *__doc_slp_ExitStatus_GLOBALLY_INFEASIBLE =
|
82
|
+
R"doc(The problem setup frontend determined the problem to have an empty
|
83
|
+
feasible region.)doc";
|
84
|
+
|
81
85
|
static const char *__doc_slp_ExitStatus_LINE_SEARCH_FAILED =
|
82
86
|
R"doc(The backtracking line search failed, and the problem isn't locally
|
83
87
|
infeasible.)doc";
|
@@ -17,6 +17,8 @@ void bind_exit_status(nb::enum_<ExitStatus>& e) {
|
|
17
17
|
DOC(slp, ExitStatus, TOO_FEW_DOFS));
|
18
18
|
e.value("LOCALLY_INFEASIBLE", ExitStatus::LOCALLY_INFEASIBLE,
|
19
19
|
DOC(slp, ExitStatus, LOCALLY_INFEASIBLE));
|
20
|
+
e.value("GLOBALLY_INFEASIBLE", ExitStatus::GLOBALLY_INFEASIBLE,
|
21
|
+
DOC(slp, ExitStatus, GLOBALLY_INFEASIBLE));
|
20
22
|
e.value("FACTORIZATION_FAILED", ExitStatus::FACTORIZATION_FAILED,
|
21
23
|
DOC(slp, ExitStatus, FACTORIZATION_FAILED));
|
22
24
|
e.value("LINE_SEARCH_FAILED", ExitStatus::LINE_SEARCH_FAILED,
|
@@ -116,6 +116,25 @@ def test_minimum_2d_distance_with_linear_constraint():
|
|
116
116
|
assert y.value() == pytest.approx(2.5, abs=1e-2)
|
117
117
|
|
118
118
|
|
119
|
+
def test_conflicting_bounds():
|
120
|
+
problem = Problem()
|
121
|
+
|
122
|
+
x = problem.decision_variable()
|
123
|
+
y = problem.decision_variable()
|
124
|
+
|
125
|
+
problem.minimize(autodiff.hypot(x, y))
|
126
|
+
|
127
|
+
problem.subject_to(autodiff.hypot(x, y) <= 1)
|
128
|
+
problem.subject_to(x >= 0.5)
|
129
|
+
problem.subject_to(x <= -0.5)
|
130
|
+
|
131
|
+
assert problem.cost_function_type() == ExpressionType.NONLINEAR
|
132
|
+
assert problem.equality_constraint_type() == ExpressionType.NONE
|
133
|
+
assert problem.inequality_constraint_type() == ExpressionType.NONLINEAR
|
134
|
+
|
135
|
+
assert problem.solve(diagnostics=True) == ExitStatus.GLOBALLY_INFEASIBLE
|
136
|
+
|
137
|
+
|
119
138
|
def test_wachter_and_biegler_line_search_failure():
|
120
139
|
# See example 19.2 of [1]
|
121
140
|
|
{sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/pyproject.toml
RENAMED
@@ -1,7 +1,7 @@
|
|
1
1
|
[project]
|
2
2
|
name = "sleipnirgroup-jormungandr"
|
3
3
|
description = "A linearity-exploiting sparse nonlinear constrained optimization problem solver that uses the interior-point method."
|
4
|
-
version = "0.0.1.
|
4
|
+
version = "0.0.1.dev476"
|
5
5
|
readme = "README.md"
|
6
6
|
requires-python = ">=3.9"
|
7
7
|
dependencies = [ "matplotlib", "numpy", "scipy" ]
|
@@ -0,0 +1,220 @@
|
|
1
|
+
// Copyright (c) Sleipnir contributors
|
2
|
+
|
3
|
+
#pragma once
|
4
|
+
|
5
|
+
#include <algorithm>
|
6
|
+
#include <limits>
|
7
|
+
#include <span>
|
8
|
+
#include <utility>
|
9
|
+
|
10
|
+
#include <Eigen/Core>
|
11
|
+
#include <Eigen/SparseCore>
|
12
|
+
#include <gch/small_vector.hpp>
|
13
|
+
|
14
|
+
#include "sleipnir/autodiff/expression_type.hpp"
|
15
|
+
#include "sleipnir/autodiff/variable.hpp"
|
16
|
+
#include "sleipnir/util/assert.hpp"
|
17
|
+
|
18
|
+
// See docs/algorithms.md#Works_cited for citation definitions
|
19
|
+
|
20
|
+
namespace slp {
|
21
|
+
|
22
|
+
struct Bounds {
|
23
|
+
/// Which constraints, if any, are bound constraints.
|
24
|
+
Eigen::ArrayX<bool> bound_constraint_mask;
|
25
|
+
|
26
|
+
/// The tightest bounds on each decision variable.
|
27
|
+
gch::small_vector<std::pair<double, double>> bounds;
|
28
|
+
|
29
|
+
/// Whether or not the constraints are feasible (given previously encountered
|
30
|
+
/// bounds).
|
31
|
+
gch::small_vector<std::pair<Eigen::Index, Eigen::Index>>
|
32
|
+
conflicting_bound_indices;
|
33
|
+
};
|
34
|
+
|
35
|
+
/**
|
36
|
+
* A "bound constraint" is any linear constraint in one scalar variable.
|
37
|
+
*
|
38
|
+
* Computes which constraints, if any, are bound constraints, the tightest
|
39
|
+
* bounds on each decision variable, and whether or not they're feasible (given
|
40
|
+
* previously encountered bounds),
|
41
|
+
*
|
42
|
+
* @param decision_variables Decision variables corresponding to each column of
|
43
|
+
* A_i.
|
44
|
+
* @param inequality_constraints Variables representing the left-hand side of
|
45
|
+
* cᵢ(decision_variables) ≥ 0.
|
46
|
+
* @param A_i The Jacobian of inequality_constraints wrt decision_variables,
|
47
|
+
* evaluated anywhere, in *row-major* storage; in practice, since we typically
|
48
|
+
* store Jacobians column-major, the user of this function must perform a
|
49
|
+
* transpose.
|
50
|
+
*/
|
51
|
+
inline Bounds get_bounds(
|
52
|
+
std::span<Variable> decision_variables,
|
53
|
+
std::span<Variable> inequality_constraints,
|
54
|
+
const Eigen::SparseMatrix<double, Eigen::RowMajor>& A_i) {
|
55
|
+
// TODO: A blocked, out-of-place transpose should be much faster than
|
56
|
+
// traversing row major on a column major matrix unless we have few linear
|
57
|
+
// constraints (using a heuristic to choose between this and staying column
|
58
|
+
// major based on the number of constraints would be an easy performance
|
59
|
+
// improvement.)
|
60
|
+
|
61
|
+
// NB: Casting to long is unspecified if the size of decision_variable.size()
|
62
|
+
// is greater than the max long value, but then we wouldn't be able to fill
|
63
|
+
// A_i correctly anyway.
|
64
|
+
slp_assert(static_cast<Eigen::Index>(decision_variables.size()) ==
|
65
|
+
A_i.innerSize());
|
66
|
+
slp_assert(static_cast<Eigen::Index>(inequality_constraints.size()) ==
|
67
|
+
A_i.outerSize());
|
68
|
+
|
69
|
+
// Maps each decision variable's index to the indices of its upper and lower
|
70
|
+
// bounds if they exist, or NO_BOUND if they do not; used only for bookkeeping
|
71
|
+
// to compute conflicting bounds
|
72
|
+
constexpr Eigen::Index NO_BOUND = -1;
|
73
|
+
gch::small_vector<std::pair<Eigen::Index, Eigen::Index>>
|
74
|
+
decision_var_indices_to_constraint_indices{decision_variables.size(),
|
75
|
+
{NO_BOUND, NO_BOUND}};
|
76
|
+
// Lists pairs of indices of bound constraints in the inequality constraint
|
77
|
+
// list that conflict with each other
|
78
|
+
gch::small_vector<std::pair<Eigen::Index, Eigen::Index>>
|
79
|
+
conflicting_bound_indices;
|
80
|
+
|
81
|
+
// Maps each decision variable's index to its upper and lower bounds
|
82
|
+
gch::small_vector<std::pair<double, double>> decision_var_indices_to_bounds{
|
83
|
+
decision_variables.size(),
|
84
|
+
{-std::numeric_limits<double>::infinity(),
|
85
|
+
std::numeric_limits<double>::infinity()}};
|
86
|
+
|
87
|
+
// Vector corresponding to the inequality constraints where the i-th element
|
88
|
+
// is 1 if the i-th inequality constraint is a bound and 0 otherwise.
|
89
|
+
Eigen::ArrayX<bool> bound_constraint_mask{inequality_constraints.size()};
|
90
|
+
bound_constraint_mask.fill(false);
|
91
|
+
|
92
|
+
for (decltype(inequality_constraints)::size_type constraint_index = 0;
|
93
|
+
constraint_index < inequality_constraints.size(); ++constraint_index) {
|
94
|
+
// A constraint is a bound iff it is linear and its gradient has a
|
95
|
+
// single nonzero value.
|
96
|
+
if (inequality_constraints[constraint_index].type() !=
|
97
|
+
ExpressionType::LINEAR) {
|
98
|
+
continue;
|
99
|
+
}
|
100
|
+
const Eigen::SparseVector<double>& row_A_i =
|
101
|
+
A_i.innerVector(constraint_index);
|
102
|
+
const auto non_zeros = row_A_i.nonZeros();
|
103
|
+
slp_assert(non_zeros != 0);
|
104
|
+
if (non_zeros > 1) {
|
105
|
+
// Constraint is in more than one variable and therefore not a bound.
|
106
|
+
continue;
|
107
|
+
}
|
108
|
+
|
109
|
+
// Claim: The bound given by a bound constraint is the constraint evaluated
|
110
|
+
// at zero divided by the nonzero element of the constraint's gradient.
|
111
|
+
//
|
112
|
+
// Proof: If c(x) is a bound constraint, then by definition c is a linear
|
113
|
+
// function in one variable, hence there exist a, b ∈ ℝ s.t. c(x) = axᵢ + b
|
114
|
+
// and a ≠ 0. The gradient of c is then aeᵢ (where eᵢ denotes the i-th basis
|
115
|
+
// element), and c(0) = b. If c(x) ≥ 0, then since either a < 0 or a > 0, we
|
116
|
+
// have either x ≤ -b/a or x ≥ -b/a, respectively. ∎
|
117
|
+
Eigen::SparseVector<double>::InnerIterator row_iter(row_A_i);
|
118
|
+
const auto constraint_coefficient =
|
119
|
+
row_iter
|
120
|
+
.value(); // The nonzero value of the j-th constraint's gradient.
|
121
|
+
const auto decision_variable_index = row_iter.index();
|
122
|
+
const auto decision_variable_value =
|
123
|
+
decision_variables[decision_variable_index].value();
|
124
|
+
double constraint_constant;
|
125
|
+
// We need to evaluate this constraint *exactly* at zero.
|
126
|
+
if (decision_variable_value != 0.0) {
|
127
|
+
decision_variables[decision_variable_index].set_value(0.0);
|
128
|
+
constraint_constant = inequality_constraints[constraint_index].value();
|
129
|
+
decision_variables[decision_variable_index].set_value(
|
130
|
+
decision_variable_value);
|
131
|
+
} else {
|
132
|
+
constraint_constant = inequality_constraints[constraint_index].value();
|
133
|
+
}
|
134
|
+
|
135
|
+
// Shouldn't happen since the constraint is supposed to be linear and not a
|
136
|
+
// constant.
|
137
|
+
slp_assert(constraint_coefficient != 0.0);
|
138
|
+
|
139
|
+
// We should always get a finite value when evaluating the constraint at
|
140
|
+
// x = 0 since the constraint is linear.
|
141
|
+
slp_assert(std::isfinite(constraint_constant));
|
142
|
+
|
143
|
+
// This is possible if the user has provided a starting point at which their
|
144
|
+
// problem is ill-defined.
|
145
|
+
slp_assert(std::isfinite(constraint_coefficient));
|
146
|
+
|
147
|
+
// Update bounds; we assume constraints of the form c(x) ≥ 0.
|
148
|
+
auto& [lower_bound, upper_bound] =
|
149
|
+
decision_var_indices_to_bounds[decision_variable_index];
|
150
|
+
auto& [lower_index, upper_index] =
|
151
|
+
decision_var_indices_to_constraint_indices[decision_variable_index];
|
152
|
+
const auto detected_bound = -constraint_constant / constraint_coefficient;
|
153
|
+
if (constraint_coefficient < 0.0 && detected_bound < upper_bound) {
|
154
|
+
upper_bound = detected_bound;
|
155
|
+
upper_index = constraint_index;
|
156
|
+
} else if (constraint_coefficient > 0.0 && detected_bound > lower_bound) {
|
157
|
+
lower_bound = detected_bound;
|
158
|
+
lower_index = constraint_index;
|
159
|
+
}
|
160
|
+
|
161
|
+
// Update conflicting bounds
|
162
|
+
if (lower_bound > upper_bound) {
|
163
|
+
conflicting_bound_indices.emplace_back(lower_index, upper_index);
|
164
|
+
}
|
165
|
+
|
166
|
+
// Set the bound constraint mask appropriately.
|
167
|
+
bound_constraint_mask[constraint_index] = true;
|
168
|
+
}
|
169
|
+
return {bound_constraint_mask, decision_var_indices_to_bounds,
|
170
|
+
conflicting_bound_indices};
|
171
|
+
}
|
172
|
+
|
173
|
+
/**
|
174
|
+
* Projects the decision variables onto the given bounds, while ensuring some
|
175
|
+
* configurable distance from the boundary if possible. This is designed to
|
176
|
+
* match the algorithm given in section 3.6 of [2].
|
177
|
+
*
|
178
|
+
* @param x A vector of decision variables.
|
179
|
+
* @param decision_variable_indices_to_bounds An array of bounds (stored [lower,
|
180
|
+
* upper]) for each decision variable in x.
|
181
|
+
* @param κ_1 A constant controlling distance from the lower or upper bound when
|
182
|
+
* the difference between the upper and lower bound is small.
|
183
|
+
* @param κ_2 A constant controlling distance from the lower or upper bound when
|
184
|
+
* the difference between the upper and lower bound is large (including when
|
185
|
+
* one of the bounds is ±∞).
|
186
|
+
*/
|
187
|
+
template <typename Derived>
|
188
|
+
requires(static_cast<bool>(Eigen::DenseBase<Derived>::IsVectorAtCompileTime))
|
189
|
+
inline void project_onto_bounds(
|
190
|
+
Eigen::DenseBase<Derived>& x,
|
191
|
+
std::span<const std::pair<typename Eigen::DenseBase<Derived>::Scalar,
|
192
|
+
typename Eigen::DenseBase<Derived>::Scalar>>
|
193
|
+
decision_variable_indices_to_bounds,
|
194
|
+
const typename Eigen::DenseBase<Derived>::Scalar κ_1 = 1e-2,
|
195
|
+
const typename Eigen::DenseBase<Derived>::Scalar κ_2 = 1e-2) {
|
196
|
+
slp_assert(κ_1 > 0 && κ_2 > 0 && κ_2 < 0.5);
|
197
|
+
|
198
|
+
Eigen::Index decision_variable_idx = 0;
|
199
|
+
for (const auto& [lower, upper] : decision_variable_indices_to_bounds) {
|
200
|
+
typename Eigen::DenseBase<Derived>::Scalar& x_i =
|
201
|
+
x[decision_variable_idx++];
|
202
|
+
|
203
|
+
// We assume that bound infeasibility is handled elsewhere.
|
204
|
+
slp_assert(lower <= upper);
|
205
|
+
|
206
|
+
// See B.2 in [5] and section 3.6 in [2]
|
207
|
+
if (std::isfinite(lower) && std::isfinite(upper)) {
|
208
|
+
auto p_L =
|
209
|
+
std::min(κ_1 * std::max(1.0, std::abs(lower)), κ_2 * (upper - lower));
|
210
|
+
auto p_U =
|
211
|
+
std::min(κ_1 * std::max(1.0, std::abs(upper)), κ_2 * (upper - lower));
|
212
|
+
x_i = std::min(std::max(lower + p_L, x_i), upper - p_U);
|
213
|
+
} else if (std::isfinite(lower)) {
|
214
|
+
x_i = std::max(x_i, lower + κ_1 * std::max(1.0, std::abs(lower)));
|
215
|
+
} else if (std::isfinite(upper)) {
|
216
|
+
x_i = std::min(x_i, upper - κ_1 * std::max(1.0, std::abs(upper)));
|
217
|
+
}
|
218
|
+
}
|
219
|
+
}
|
220
|
+
} // namespace slp
|
@@ -13,6 +13,7 @@
|
|
13
13
|
#include <Eigen/SparseCore>
|
14
14
|
#include <gch/small_vector.hpp>
|
15
15
|
|
16
|
+
#include "optimization/bounds.hpp"
|
16
17
|
#include "sleipnir/autodiff/expression_type.hpp"
|
17
18
|
#include "sleipnir/autodiff/gradient.hpp"
|
18
19
|
#include "sleipnir/autodiff/hessian.hpp"
|
@@ -252,6 +253,19 @@ ExitStatus Problem::solve(const Options& options, [[maybe_unused]] bool spy) {
|
|
252
253
|
}
|
253
254
|
#endif
|
254
255
|
|
256
|
+
const auto [bound_constraint_mask, bounds, conflicting_bound_indices] =
|
257
|
+
get_bounds(m_decision_variables, m_inequality_constraints, A_i.value());
|
258
|
+
if (!conflicting_bound_indices.empty()) {
|
259
|
+
if (options.diagnostics) {
|
260
|
+
print_bound_constraint_global_infeasibility_error(
|
261
|
+
conflicting_bound_indices);
|
262
|
+
}
|
263
|
+
return ExitStatus::GLOBALLY_INFEASIBLE;
|
264
|
+
}
|
265
|
+
|
266
|
+
#ifdef SLEIPNIR_ENABLE_BOUND_PROJECTION
|
267
|
+
project_onto_bounds(x, bounds);
|
268
|
+
#endif
|
255
269
|
// Invoke interior-point method solver
|
256
270
|
status = interior_point(
|
257
271
|
InteriorPointMatrixCallbacks{
|
@@ -286,7 +300,11 @@ ExitStatus Problem::solve(const Options& options, [[maybe_unused]] bool spy) {
|
|
286
300
|
x_ad.set_value(x);
|
287
301
|
return A_i.value();
|
288
302
|
}},
|
289
|
-
m_iteration_callbacks, options,
|
303
|
+
m_iteration_callbacks, options,
|
304
|
+
#ifdef SLEIPNIR_ENABLE_BOUND_PROJECTION
|
305
|
+
bound_constraint_mask,
|
306
|
+
#endif
|
307
|
+
x);
|
290
308
|
}
|
291
309
|
|
292
310
|
#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
|
@@ -56,7 +56,11 @@ ExitStatus interior_point(
|
|
56
56
|
const InteriorPointMatrixCallbacks& matrix_callbacks,
|
57
57
|
std::span<std::function<bool(const IterationInfo& info)>>
|
58
58
|
iteration_callbacks,
|
59
|
-
const Options& options,
|
59
|
+
const Options& options,
|
60
|
+
#ifdef SLEIPNIR_ENABLE_BOUND_PROJECTION
|
61
|
+
const Eigen::ArrayX<bool>& bound_constraint_mask,
|
62
|
+
#endif
|
63
|
+
Eigen::VectorXd& x) {
|
60
64
|
const auto solve_start_time = std::chrono::steady_clock::now();
|
61
65
|
|
62
66
|
gch::small_vector<SolveProfiler> solve_profilers;
|
@@ -160,6 +164,10 @@ ExitStatus interior_point(
|
|
160
164
|
Eigen::SparseMatrix<double> A_i = matrices.A_i(x);
|
161
165
|
|
162
166
|
Eigen::VectorXd s = Eigen::VectorXd::Ones(num_inequality_constraints);
|
167
|
+
#ifdef SLEIPNIR_ENABLE_BOUND_PROJECTION
|
168
|
+
// We set sʲ = cᵢʲ(x) for each bound inequality constraint index j
|
169
|
+
s = bound_constraint_mask.select(c_i, s);
|
170
|
+
#endif
|
163
171
|
Eigen::VectorXd y = Eigen::VectorXd::Zero(num_equality_constraints);
|
164
172
|
Eigen::VectorXd z = Eigen::VectorXd::Ones(num_inequality_constraints);
|
165
173
|
|
@@ -149,6 +149,25 @@ inline void print_c_i_local_infeasibility_error(const Eigen::VectorXd& c_i) {
|
|
149
149
|
#define print_c_i_local_infeasibility_error(...)
|
150
150
|
#endif
|
151
151
|
|
152
|
+
#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
|
153
|
+
inline void print_bound_constraint_global_infeasibility_error(
|
154
|
+
const std::span<const std::pair<Eigen::Index, Eigen::Index>>
|
155
|
+
conflicting_lower_upper_bound_indices) {
|
156
|
+
slp::println(
|
157
|
+
"The problem is globally infeasible due to conflicting bound "
|
158
|
+
"constraints:");
|
159
|
+
for (const auto& [lower_bound_idx, upper_bound_idx] :
|
160
|
+
conflicting_lower_upper_bound_indices) {
|
161
|
+
slp::println(
|
162
|
+
" Inequality constraint {} gives a lower bound that is greater than "
|
163
|
+
"the upper bound given by inequality constraint {}",
|
164
|
+
lower_bound_idx, upper_bound_idx);
|
165
|
+
}
|
166
|
+
}
|
167
|
+
#else
|
168
|
+
#define print_bound_constraint_global_infeasibility_error(...)
|
169
|
+
#endif
|
170
|
+
|
152
171
|
#ifndef SLEIPNIR_DISABLE_DIAGNOSTICS
|
153
172
|
/**
|
154
173
|
* Prints diagnostics for the current iteration.
|
{sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/LICENSE.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/.styleguide
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{sleipnirgroup_jormungandr-0.0.1.dev475 → sleipnirgroup_jormungandr-0.0.1.dev476}/src/util/pool.cpp
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|