Skip to content

Commit 9dbcbf9

Browse files
committed
Abstraction of NonlinearEvaluator
Some new codes for cache_model
1 parent 18fc33e commit 9dbcbf9

File tree

8 files changed

+891
-598
lines changed

8 files changed

+891
-598
lines changed

CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,12 @@ set(POI_INSTALL_DIR ${SKBUILD_PLATLIB_DIR}/pyoptinterface/_src)
4141

4242
add_library(core STATIC)
4343
target_sources(core PRIVATE
44+
include/pyoptinterface/cache_model.hpp
4445
include/pyoptinterface/core.hpp
4546
include/pyoptinterface/container.hpp
4647
include/pyoptinterface/dylib.hpp
4748
include/pyoptinterface/solver_common.hpp
49+
lib/cache_model.cpp
4850
lib/core.cpp
4951
)
5052
target_include_directories(core PUBLIC include thirdparty)
@@ -63,7 +65,7 @@ target_sources(nleval PRIVATE
6365
include/pyoptinterface/nleval.hpp
6466
lib/nleval.cpp
6567
)
66-
target_link_libraries(nleval PUBLIC core)
68+
target_link_libraries(nleval PUBLIC nlexpr core)
6769

6870
add_library(cppad_interface STATIC)
6971
target_sources(cppad_interface PRIVATE
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#pragma once
2+
3+
#include <concepts>
4+
#include <vector>
5+
#include <span>
6+
7+
// This file defines some common utilities to store the optimization model in a compact way
8+
9+
template <std::integral ColumnIndexT, std::integral VariableIndexT,
10+
std::floating_point CoefficientT>
11+
struct LinearExpressionCache
12+
{
13+
std::vector<ColumnIndexT> column_ptr = {0};
14+
std::vector<VariableIndexT> variables;
15+
std::vector<CoefficientT> coefficients;
16+
17+
template <std::integral IT, std::floating_point FT>
18+
void add_row(std::span<const IT> row_variables, std::span<const FT> row_coefficients)
19+
{
20+
variables.insert(variables.end(), row_variables.begin(), row_variables.end());
21+
coefficients.insert(coefficients.end(), row_coefficients.begin(), row_coefficients.end());
22+
column_ptr.push_back(variables.size());
23+
}
24+
};
25+
26+
template <std::integral ColumnIndexT, std::integral VariableIndexT,
27+
std::floating_point CoefficientT>
28+
struct QuadraticExpressionCache
29+
{
30+
std::vector<ColumnIndexT> column_ptr = {0};
31+
std::vector<VariableIndexT> variable_1s;
32+
std::vector<VariableIndexT> variable_2s;
33+
std::vector<CoefficientT> coefficients;
34+
35+
std::vector<ColumnIndexT> lin_column_ptr = {0};
36+
std::vector<VariableIndexT> lin_variables;
37+
std::vector<CoefficientT> lin_coefficients;
38+
39+
template <std::integral IT, std::floating_point FT>
40+
void add_row(std::span<const IT> row_variable_1s, std::span<const IT> row_variable_2s,
41+
std::span<const FT> row_quadratic_coefficients,
42+
std::span<const IT> row_lin_variables, std::span<const FT> row_lin_coefficients)
43+
{
44+
variable_1s.insert(variable_1s.end(), row_variable_1s.begin(), row_variable_1s.end());
45+
variable_2s.insert(variable_2s.end(), row_variable_2s.begin(), row_variable_2s.end());
46+
coefficients.insert(coefficients.end(), row_quadratic_coefficients.begin(),
47+
row_quadratic_coefficients.end());
48+
column_ptr.push_back(variable_1s.size());
49+
50+
lin_variables.insert(lin_variables.end(), row_lin_variables.begin(),
51+
row_lin_variables.end());
52+
lin_coefficients.insert(lin_coefficients.end(), row_lin_coefficients.begin(),
53+
row_lin_coefficients.end());
54+
lin_column_ptr.push_back(lin_variables.size());
55+
}
56+
};
57+

include/pyoptinterface/ipopt_model.hpp

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -152,20 +152,20 @@ struct IpoptModel : public OnesideLinearConstraintMixin<IpoptModel>,
152152
} nl_objective_groups;
153153

154154
int add_graph_index();
155-
void record_graph_hash(size_t graph_index, const ExpressionGraph &graph);
156-
int aggregate_graph_constraint_groups();
157-
int get_graph_constraint_group_representative(int group_index) const;
158-
int aggregate_graph_objective_groups();
159-
int get_graph_objective_group_representative(int group_index) const;
160-
161-
void assign_constraint_group_autodiff_structure(int group_index,
162-
const AutodiffSymbolicStructure &structure);
163-
void assign_constraint_group_autodiff_evaluator(int group_index,
164-
const ConstraintAutodiffEvaluator &evaluator);
165-
void assign_objective_group_autodiff_structure(int group_index,
166-
const AutodiffSymbolicStructure &structure);
167-
void assign_objective_group_autodiff_evaluator(int group_index,
168-
const ObjectiveAutodiffEvaluator &evaluator);
155+
void finalize_graph_instance(size_t graph_index, const ExpressionGraph &graph);
156+
int aggregate_nl_constraint_groups();
157+
int get_nl_constraint_group_representative(int group_index) const;
158+
int aggregate_nl_objective_groups();
159+
int get_nl_objective_group_representative(int group_index) const;
160+
161+
void assign_nl_constraint_group_autodiff_structure(int group_index,
162+
const AutodiffSymbolicStructure &structure);
163+
void assign_nl_constraint_group_autodiff_evaluator(
164+
int group_index, const ConstraintAutodiffEvaluator &evaluator);
165+
void assign_nl_objective_group_autodiff_structure(int group_index,
166+
const AutodiffSymbolicStructure &structure);
167+
void assign_nl_objective_group_autodiff_evaluator(int group_index,
168+
const ObjectiveAutodiffEvaluator &evaluator);
169169

170170
ConstraintIndex add_single_nl_constraint(size_t graph_index, const ExpressionGraph &graph,
171171
double lb, double ub);
@@ -193,13 +193,18 @@ struct IpoptModel : public OnesideLinearConstraintMixin<IpoptModel>,
193193
* constraint) to the reordered one (linear, quadratic, NL group 0 -> con0, con1 ,..., conN0, NL
194194
* group1 -> con0, con1,..., conN1)
195195
*/
196-
// these two vectors are maintained when adding NL constraint
197-
// which graph instance this constraint belongs to
198-
std::vector<int> nl_constraint_graph_instance_indices;
199-
// the order of this constraint in the graph instance
200-
std::vector<int> nl_constraint_graph_instance_orders;
196+
// this is maintained when adding NL constraint
197+
struct ConstraintGraphMembership
198+
{
199+
// which graph it belongs to
200+
int graph;
201+
// the rank in that graph
202+
int rank;
203+
};
204+
// record the graph a nonlinear constraint belongs to
205+
std::vector<ConstraintGraphMembership> nl_constraint_graph_memberships;
201206

202-
// these two vectors are constructed before optimization
207+
// this vector is constructed before optimization
203208
// ext means the external monotonic order
204209
// int means the internal order that passes to Ipopt
205210
std::vector<int> nl_constraint_map_ext2int;
@@ -227,6 +232,8 @@ struct IpoptModel : public OnesideLinearConstraintMixin<IpoptModel>,
227232
std::optional<LinearEvaluator> m_linear_obj_evaluator;
228233
std::optional<QuadraticEvaluator> m_quadratic_obj_evaluator;
229234

235+
NonlinearEvaluator m_nl_evaluator;
236+
230237
// The options of the Ipopt solver, we cache them before constructing the m_problem
231238
Hashmap<std::string, int> m_options_int;
232239
Hashmap<std::string, double> m_options_num;

include/pyoptinterface/nleval.hpp

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
#include <cstdint>
44
#include <vector>
55

6-
#include "core.hpp"
6+
#include "pyoptinterface/core.hpp"
7+
#include "pyoptinterface/nlexpr.hpp"
78

89
enum class HessianSparsityType
910
{
@@ -157,4 +158,120 @@ struct QuadraticEvaluator
157158
Hashmap<std::tuple<int, int>, int> &hessian_index_map,
158159
HessianSparsityType hessian_type);
159160
void eval_lagrangian_hessian(const double *restrict lambda, double *restrict hessian) const;
161+
};
162+
163+
struct NonlinearEvaluator
164+
{
165+
// How many graph instances are there
166+
size_t n_graph_instances = 0;
167+
// record the inputs of graph instances
168+
struct GraphInput
169+
{
170+
std::vector<int> variables;
171+
std::vector<double> constants;
172+
};
173+
std::vector<GraphInput> graph_inputs;
174+
// record graph instances with constraint output and objective output
175+
struct GraphHash
176+
{
177+
// hash of this graph instance
178+
uint64_t hash;
179+
// index of this graph instance
180+
int index;
181+
};
182+
struct GraphHashes
183+
{
184+
std::vector<GraphHash> hashes;
185+
size_t n_hashes_since_last_aggregation;
186+
} constraint_graph_hashes, objective_graph_hashes;
187+
188+
// length = n_graph_instances
189+
// record which group this graph instance belongs to
190+
struct GraphGroupMembership
191+
{
192+
// which group it belongs to
193+
int group;
194+
// the rank in that group
195+
int rank;
196+
};
197+
std::vector<GraphGroupMembership> constraint_group_memberships, objective_group_memberships;
198+
// record which index of constraint this graph starts
199+
std::vector<int> constraint_indices_offsets;
200+
201+
// graph groups
202+
struct ConstraintGraphGroup
203+
{
204+
std::vector<int> instance_indices;
205+
AutodiffSymbolicStructure autodiff_structure;
206+
ConstraintAutodiffEvaluator autodiff_evaluator;
207+
208+
// where to store the hessian matrix
209+
// length = instance_indices.size() * hessian_nnz
210+
std::vector<int> hessian_indices;
211+
};
212+
std::vector<ConstraintGraphGroup> constraint_groups;
213+
Hashmap<uint64_t, int> hash_to_constraint_group;
214+
215+
struct ObjectiveGraphGroup
216+
{
217+
std::vector<int> instance_indices;
218+
AutodiffSymbolicStructure autodiff_structure;
219+
ObjectiveAutodiffEvaluator autodiff_evaluator;
220+
// where to store the gradient vector
221+
// length = instance_indices.size() * jacobian_nnz
222+
std::vector<int> gradient_indices;
223+
// where to store the hessian matrix
224+
// length = instance_indices.size() * hessian_nnz
225+
std::vector<int> hessian_indices;
226+
};
227+
std::vector<ObjectiveGraphGroup> objective_groups;
228+
Hashmap<uint64_t, int> hash_to_objective_group;
229+
230+
int add_graph_instance();
231+
void finalize_graph_instance(size_t graph_index, const ExpressionGraph &graph);
232+
int aggregate_constraint_groups();
233+
int get_constraint_group_representative(int group_index) const;
234+
int aggregate_objective_groups();
235+
int get_objective_group_representative(int group_index) const;
236+
237+
void assign_constraint_group_autodiff_structure(int group_index,
238+
const AutodiffSymbolicStructure &structure);
239+
void assign_constraint_group_autodiff_evaluator(int group_index,
240+
const ConstraintAutodiffEvaluator &evaluator);
241+
void assign_objective_group_autodiff_structure(int group_index,
242+
const AutodiffSymbolicStructure &structure);
243+
void assign_objective_group_autodiff_evaluator(int group_index,
244+
const ObjectiveAutodiffEvaluator &evaluator);
245+
246+
void calculate_constraint_graph_instances_offset();
247+
248+
// functions to evaluate the nonlinear constraints and objectives
249+
250+
// f
251+
void eval_constraints(const double *restrict x, double *restrict f) const;
252+
double eval_objective(const double *restrict x) const;
253+
254+
// first order derivative
255+
void analyze_constraints_jacobian_structure(size_t row_base, size_t &global_jacobian_nnz,
256+
std::vector<int> &global_jacobian_rows,
257+
std::vector<int> &global_jacobian_cols);
258+
void analyze_objective_gradient_structure(std::vector<int> &global_gradient_cols,
259+
Hashmap<int, int> &sparse_gradient_map);
260+
261+
void eval_constraints_jacobian(const double *restrict x, double *restrict jacobian) const;
262+
void eval_objective_gradient(const double *restrict x, double *restrict grad_f) const;
263+
264+
// second order derivative
265+
void analyze_constraints_hessian_structure(
266+
size_t &global_hessian_nnz, std::vector<int> &global_hessian_rows,
267+
std::vector<int> &global_hessian_cols,
268+
Hashmap<std::tuple<int, int>, int> &hessian_index_map, HessianSparsityType hessian_type);
269+
void analyze_objective_hessian_structure(size_t &global_hessian_nnz,
270+
std::vector<int> &global_hessian_rows,
271+
std::vector<int> &global_hessian_cols,
272+
Hashmap<std::tuple<int, int>, int> &hessian_index_map,
273+
HessianSparsityType hessian_type);
274+
275+
void eval_lagrangian_hessian(const double *restrict x, const double *restrict lambda,
276+
const double sigma, double *restrict hessian) const;
160277
};

0 commit comments

Comments
 (0)