Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
D
dune-solvers
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
agnumpde
dune-solvers
Commits
9b4fff48
Commit
9b4fff48
authored
9 years ago
by
Jonathan Youett
Browse files
Options
Downloads
Patches
Plain Diff
Add IpOpt wrapper for linear problems with bound- and linear constraints
parent
9a075dfe
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
dune/solvers/solvers/linearipopt.hh
+604
-0
604 additions, 0 deletions
dune/solvers/solvers/linearipopt.hh
with
604 additions
and
0 deletions
dune/solvers/solvers/linearipopt.hh
0 → 100644
+
604
−
0
View file @
9b4fff48
// -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=8 sw=4 sts=4:
#ifndef DUNE_SOLVERS_SOLVERS_LINEAR_IPOPT_SOLVER_HH
#define DUNE_SOLVERS_SOLVERS_LINEAR_IPOPT_SOLVER_HH
/** \file
\brief A wrapper for the IPOpt solver for linear optimization problem
with box constraints and linear constraints
*/
#include
<algorithm>
#include
<vector>
#include
<dune/common/exceptions.hh>
#include
<dune/common/bitsetvector.hh>
#include
<dune/common/fmatrix.hh>
#include
<dune/common/shared_ptr.hh>
#include
<dune/istl/bcrsmatrix.hh>
#include
<dune/istl/bvector.hh>
#include
<dune/solvers/common/boxconstraint.hh>
#include
<dune/solvers/common/canignore.hh>
#include
<dune/solvers/solvers/iterativesolver.hh>
#include
"IpTNLP.hpp"
#include
"IpIpoptApplication.hpp"
/** \brief Implementation class used to pipe linear problems to
the IPOpt interior-point solver
\tparam JacobianType The type of the jacobian of the linear constraints
*/
template
<
class
VectorType
,
class
JacobianType
>
class
LinearIPOptProblem
:
public
Ipopt
::
TNLP
{
enum
{
blocksize
=
VectorType
::
block_type
::
dimension
};
enum
{
constraintBlocksize
=
JacobianType
::
block_type
::
rows
};
typedef
typename
VectorType
::
field_type
field_type
;
public
:
/** Setup problem if no linear constraints are present */
LinearIPOptProblem
(
VectorType
*
x
,
const
VectorType
*
rhs
,
const
Dune
::
BitSetVector
<
blocksize
>*
dirichletNodes
,
std
::
vector
<
BoxConstraint
<
field_type
,
blocksize
>
>*
obstacles
)
:
x_
(
x
),
rhs_
(
rhs
),
dirichletNodes_
(
dirichletNodes
),
obstacles_
(
obstacles
),
constraintMatrix_
(
nullptr
),
constraintObstacles_
(
nullptr
),
jacobianCutoff_
(
1e-8
)
{}
/** Setup problem full problem */
LinearIPOptProblem
(
VectorType
*
x
,
const
VectorType
*
rhs
,
const
Dune
::
BitSetVector
<
blocksize
>*
dirichletNodes
,
std
::
vector
<
BoxConstraint
<
field_type
,
blocksize
>
>*
boundObstacles
,
std
::
shared_ptr
<
const
JacobianType
>
constraintMatrix
,
std
::
shared_ptr
<
const
std
::
vector
<
BoxConstraint
<
field_type
,
constraintBlocksize
>
>
>
constraintObstacles
)
:
x_
(
x
),
rhs_
(
rhs
),
dirichletNodes_
(
dirichletNodes
),
obstacles_
(
boundObstacles
),
constraintMatrix_
(
constraintMatrix
),
constraintObstacles_
(
constraintObstacles
),
jacobianCutoff_
(
1e-8
)
{}
/** default destructor */
virtual
~
LinearIPOptProblem
()
{}
/**@name Overloaded from TNLP */
//@{
/** Method to return some info about the nlp */
virtual
bool
get_nlp_info
(
Ipopt
::
Index
&
n
,
Ipopt
::
Index
&
m
,
Ipopt
::
Index
&
nnz_jac_g
,
Ipopt
::
Index
&
nnz_h_lag
,
IndexStyleEnum
&
index_style
);
/** Method to return the bounds for my problem */
virtual
bool
get_bounds_info
(
Ipopt
::
Index
n
,
Ipopt
::
Number
*
x_l
,
Ipopt
::
Number
*
x_u
,
Ipopt
::
Index
m
,
Ipopt
::
Number
*
g_l
,
Ipopt
::
Number
*
g_u
);
/** Method to return the starting point for the algorithm */
virtual
bool
get_starting_point
(
Ipopt
::
Index
n
,
bool
init_x
,
Ipopt
::
Number
*
x
,
bool
init_z
,
Ipopt
::
Number
*
z_L
,
Ipopt
::
Number
*
z_U
,
Ipopt
::
Index
m
,
bool
init_lambda
,
Ipopt
::
Number
*
lambda
);
/** Method to return the objective value */
virtual
bool
eval_f
(
Ipopt
::
Index
n
,
const
Ipopt
::
Number
*
x
,
bool
new_x
,
Ipopt
::
Number
&
obj_value
);
/** Method to return the gradient of the objective */
virtual
bool
eval_grad_f
(
Ipopt
::
Index
n
,
const
Ipopt
::
Number
*
x
,
bool
new_x
,
Ipopt
::
Number
*
grad_f
);
/** Method to return the constraint residuals */
virtual
bool
eval_g
(
Ipopt
::
Index
n
,
const
Ipopt
::
Number
*
x
,
bool
new_x
,
Ipopt
::
Index
m
,
Ipopt
::
Number
*
g
);
/** Method to return:
* 1) The structure of the jacobian (if "values" is NULL)
* 2) The values of the jacobian (if "values" is not NULL)
*/
virtual
bool
eval_jac_g
(
Ipopt
::
Index
n
,
const
Ipopt
::
Number
*
x
,
bool
new_x
,
Ipopt
::
Index
m
,
Ipopt
::
Index
nele_jac
,
Ipopt
::
Index
*
iRow
,
Ipopt
::
Index
*
jCol
,
Ipopt
::
Number
*
values
);
/** Method to return:
* 1) The structure of the hessian of the lagrangian (if "values" is NULL)
* 2) The values of the hessian of the lagrangian (if "values" is not NULL)
*/
virtual
bool
eval_h
(
Ipopt
::
Index
n
,
const
Ipopt
::
Number
*
x
,
bool
new_x
,
Ipopt
::
Number
obj_factor
,
Ipopt
::
Index
m
,
const
Ipopt
::
Number
*
lambda
,
bool
new_lambda
,
Ipopt
::
Index
nele_hess
,
Ipopt
::
Index
*
iRow
,
Ipopt
::
Index
*
jCol
,
Ipopt
::
Number
*
values
);
//@}
/** @name Solution Methods */
//@{
/** This method is called when the algorithm is complete so the TNLP can store/write the solution */
virtual
void
finalize_solution
(
Ipopt
::
SolverReturn
status
,
Ipopt
::
Index
n
,
const
Ipopt
::
Number
*
x
,
const
Ipopt
::
Number
*
z_L
,
const
Ipopt
::
Number
*
z_U
,
Ipopt
::
Index
m
,
const
Ipopt
::
Number
*
g
,
const
Ipopt
::
Number
*
lambda
,
Ipopt
::
Number
obj_value
,
const
Ipopt
::
IpoptData
*
ip_data
,
Ipopt
::
IpoptCalculatedQuantities
*
ip_cq
);
//@}
// /////////////////////////////////
// Data
// /////////////////////////////////
//! Vector to store the solution
VectorType
*
x_
;
//! The linear term of the linear energy
const
VectorType
*
rhs_
;
const
Dune
::
BitSetVector
<
blocksize
>*
dirichletNodes_
;
//! Vector containing the bound constraints of the variables
// Can stay unset when no bound constraints exist
std
::
vector
<
BoxConstraint
<
field_type
,
blocksize
>
>*
obstacles_
;
//! The matrix corresponding to linear constraints
// Can stay unset when no linear constraints exist
std
::
shared_ptr
<
const
JacobianType
>
constraintMatrix_
;
//! IpOpt expects constraints to be of the type g_l <= g(x) <= g_u
// Can stay unset when no linear constraints exist
std
::
shared_ptr
<
const
std
::
vector
<
BoxConstraint
<
field_type
,
constraintBlocksize
>
>
>
constraintObstacles_
;
private
:
const
field_type
jacobianCutoff_
;
/**@name Methods to block default compiler methods.*/
//@{
LinearIPOptProblem
(
const
LinearIPOptProblem
&
);
LinearIPOptProblem
&
operator
=
(
const
LinearIPOptProblem
&
);
//@}
};
// returns the size of the problem
template
<
class
VectorType
,
class
JacobianType
>
bool
LinearIPOptProblem
<
VectorType
,
JacobianType
>::
get_nlp_info
(
Ipopt
::
Index
&
n
,
Ipopt
::
Index
&
m
,
Ipopt
::
Index
&
nnz_jac_g
,
Ipopt
::
Index
&
nnz_h_lag
,
Ipopt
::
TNLP
::
IndexStyleEnum
&
index_style
)
{
// use the C style indexing (0-based)
index_style
=
Ipopt
::
TNLP
::
C_STYLE
;
// Number of variables
n
=
x_
->
dim
();
// Number of constraints
// Dirichlet conditions are actually bound inequality constraints
// bound constraints are handled differently by IpOpt
m
=
0
;
// hence the constraint jacobian is empty
nnz_jac_g
=
0
;
// energy is linear, thus the hessian is zero
nnz_h_lag
=
0
;
// We only need the lower left corner of the Hessian (since it is symmetric)
if
(
constraintMatrix_
==
nullptr
)
return
true
;
assert
(
constraintMatrix_
->
N
()
==
constraintObstacles_
->
size
());
// only change the constraint information
m
=
constraintMatrix_
->
N
()
*
constraintBlocksize
;
int
numJacobianNonzeros
=
0
;
for
(
size_t
i
=
0
;
i
<
constraintMatrix_
->
N
();
i
++
)
{
const
typename
JacobianType
::
row_type
&
row
=
(
*
constraintMatrix_
)[
i
];
// dim for each entry in the constraint matrix
typename
JacobianType
::
row_type
::
ConstIterator
cIt
=
row
.
begin
();
typename
JacobianType
::
row_type
::
ConstIterator
cEndIt
=
row
.
end
();
for
(;
cIt
!=
cEndIt
;
cIt
++
)
for
(
int
k
=
0
;
k
<
constraintBlocksize
;
k
++
)
for
(
int
l
=
0
;
l
<
blocksize
;
l
++
)
if
(
std
::
abs
((
*
cIt
)[
k
][
l
])
>
jacobianCutoff_
)
numJacobianNonzeros
++
;
}
nnz_jac_g
=
numJacobianNonzeros
;
return
true
;
}
// returns the variable bounds
template
<
class
VectorType
,
class
JacobianType
>
bool
LinearIPOptProblem
<
VectorType
,
JacobianType
>::
get_bounds_info
(
Ipopt
::
Index
n
,
Ipopt
::
Number
*
x_l
,
Ipopt
::
Number
*
x_u
,
Ipopt
::
Index
m
,
Ipopt
::
Number
*
g_l
,
Ipopt
::
Number
*
g_u
)
{
// here, the n and m we gave IPOPT in get_nlp_info are passed back to us.
// If desired, we could assert to make sure they are what we think they are.
assert
(
n
==
(
Ipopt
::
Index
)
x_
->
dim
());
if
(
obstacles_
)
{
for
(
size_t
i
=
0
;
i
<
x_
->
size
();
i
++
)
{
for
(
size_t
j
=
0
;
j
<
blocksize
;
j
++
)
{
// Simply copy the values. If they exceed a certain limit they are
// considered 'off'.
x_l
[
i
*
blocksize
+
j
]
=
(
*
obstacles_
)[
i
].
lower
(
j
);
x_u
[
i
*
blocksize
+
j
]
=
(
*
obstacles_
)[
i
].
upper
(
j
);
}
}
}
else
{
// unset all bounds
for
(
size_t
i
=
0
;
i
<
x_
->
dim
();
i
++
)
{
x_l
[
i
]
=
-
std
::
numeric_limits
<
double
>::
max
();
x_u
[
i
]
=
std
::
numeric_limits
<
double
>::
max
();
}
}
if
(
dirichletNodes_
)
{
for
(
size_t
i
=
0
;
i
<
x_
->
size
();
i
++
)
{
for
(
size_t
j
=
0
;
j
<
blocksize
;
j
++
)
{
if
(
(
*
dirichletNodes_
)[
i
][
j
])
x_l
[
i
*
blocksize
+
j
]
=
x_u
[
i
*
blocksize
+
j
]
=
(
*
this
->
x_
)[
i
][
j
];
}
}
}
if
(
constraintMatrix_
==
nullptr
)
return
true
;
// initialize with large numbers
for
(
int
i
=
0
;
i
<
m
;
i
++
)
{
g_l
[
i
]
=
-
std
::
numeric_limits
<
field_type
>::
max
();
g_u
[
i
]
=
std
::
numeric_limits
<
field_type
>::
max
();
}
for
(
size_t
i
=
0
;
i
<
constraintObstacles_
->
size
();
i
++
)
{
for
(
int
k
=
0
;
k
<
constraintBlocksize
;
k
++
)
{
g_l
[
i
*
constraintBlocksize
+
k
]
=
(
*
constraintObstacles_
)[
i
].
lower
(
k
);
g_u
[
i
*
constraintBlocksize
+
k
]
=
(
*
constraintObstacles_
)[
i
].
upper
(
k
);
}
}
return
true
;
}
// returns the initial point for the problem
template
<
class
VectorType
,
class
JacobianType
>
bool
LinearIPOptProblem
<
VectorType
,
JacobianType
>::
get_starting_point
(
Ipopt
::
Index
n
,
bool
init_x
,
Ipopt
::
Number
*
x
,
bool
init_z
,
Ipopt
::
Number
*
z_L
,
Ipopt
::
Number
*
z_U
,
Ipopt
::
Index
m
,
bool
init_lambda
,
Ipopt
::
Number
*
lambda
)
{
// Here, we assume we only have starting values for x, if you code
// your own NLP, you can provide starting values for the dual variables
// if you wish
assert
(
init_x
==
true
);
assert
(
init_z
==
false
);
assert
(
init_lambda
==
false
);
// initialize to the given starting point
for
(
size_t
i
=
0
;
i
<
x_
->
size
();
i
++
)
for
(
int
j
=
0
;
j
<
blocksize
;
j
++
)
x
[
i
*
blocksize
+
j
]
=
(
*
x_
)[
i
][
j
];
return
true
;
}
// returns the value of the objective function
template
<
class
VectorType
,
class
JacobianType
>
bool
LinearIPOptProblem
<
VectorType
,
JacobianType
>::
eval_f
(
Ipopt
::
Index
n
,
const
Ipopt
::
Number
*
x
,
bool
new_x
,
Ipopt
::
Number
&
obj_value
)
{
// Init return value
obj_value
=
0
;
////////////////////////////////////
// Compute rhs*x
////////////////////////////////////
for
(
size_t
i
=
0
;
i
<
rhs_
->
size
();
i
++
)
for
(
int
j
=
0
;
j
<
blocksize
;
j
++
)
obj_value
+=
x
[
i
*
blocksize
+
j
]
*
(
*
rhs_
)[
i
][
j
];
return
true
;
}
// return the gradient of the objective function grad_{x} f(x)
template
<
class
VectorType
,
class
JacobianType
>
bool
LinearIPOptProblem
<
VectorType
,
JacobianType
>::
eval_grad_f
(
Ipopt
::
Index
n
,
const
Ipopt
::
Number
*
x
,
bool
new_x
,
Ipopt
::
Number
*
grad_f
)
{
// g = g - b
for
(
size_t
i
=
0
;
i
<
rhs_
->
size
();
i
++
)
for
(
int
j
=
0
;
j
<
blocksize
;
j
++
)
grad_f
[
i
*
blocksize
+
j
]
=
(
*
rhs_
)[
i
][
j
];
return
true
;
}
// return the value of the constraints: g(x)
template
<
class
VectorType
,
class
JacobianType
>
bool
LinearIPOptProblem
<
VectorType
,
JacobianType
>::
eval_g
(
Ipopt
::
Index
n
,
const
Ipopt
::
Number
*
x
,
bool
new_x
,
Ipopt
::
Index
m
,
Ipopt
::
Number
*
g
)
{
if
(
constraintMatrix_
==
nullptr
)
return
true
;
for
(
int
i
=
0
;
i
<
m
;
i
++
)
g
[
i
]
=
0
;
int
rowCounter
=
0
;
for
(
size_t
rowIdx
=
0
;
rowIdx
<
constraintMatrix_
->
N
();
rowIdx
++
)
{
const
auto
&
row
=
(
*
constraintMatrix_
)[
rowIdx
];
auto
cIt
=
row
.
begin
();
auto
cEnd
=
row
.
end
();
// constraintMatrix times x
for
(;
cIt
!=
cEnd
;
cIt
++
)
for
(
int
l
=
0
;
l
<
constraintBlocksize
;
l
++
)
for
(
int
k
=
0
;
k
<
blocksize
;
k
++
)
if
(
std
::
abs
((
*
cIt
)[
l
][
k
])
>
jacobianCutoff_
)
g
[
rowCounter
+
l
]
+=
(
*
cIt
)[
l
][
k
]
*
x
[
cIt
.
index
()
*
blocksize
+
k
];
// increment constraint counter
rowCounter
+=
constraintBlocksize
;
}
return
true
;
}
// return the structure or values of the jacobian
template
<
class
VectorType
,
class
JacobianType
>
bool
LinearIPOptProblem
<
VectorType
,
JacobianType
>::
eval_jac_g
(
Ipopt
::
Index
n
,
const
Ipopt
::
Number
*
x
,
bool
new_x
,
Ipopt
::
Index
m
,
Ipopt
::
Index
nele_jac
,
Ipopt
::
Index
*
iRow
,
Ipopt
::
Index
*
jCol
,
Ipopt
::
Number
*
values
)
{
if
(
constraintMatrix_
==
nullptr
)
return
true
;
int
idx
=
0
;
int
rowCounter
=
0
;
// If the values are null then IpOpt wants the sparsity pattern
if
(
values
==
NULL
)
{
for
(
size_t
rowIdx
=
0
;
rowIdx
<
constraintMatrix_
->
N
();
rowIdx
++
)
{
const
auto
&
row
=
(
*
constraintMatrix_
)[
rowIdx
];
auto
cIt
=
row
.
begin
();
auto
cEnd
=
row
.
end
();
for
(;
cIt
!=
cEnd
;
++
cIt
)
{
for
(
int
l
=
0
;
l
<
constraintBlocksize
;
l
++
)
for
(
int
k
=
0
;
k
<
blocksize
;
k
++
)
if
(
std
::
abs
((
*
cIt
)[
l
][
k
])
>
jacobianCutoff_
)
{
iRow
[
idx
]
=
rowCounter
+
l
;
jCol
[
idx
]
=
cIt
.
index
()
*
blocksize
+
k
;
idx
++
;
}
}
rowCounter
+=
constraintBlocksize
;
}
// If the values are not null IpOpt wants the evaluated constraints gradient
}
else
{
for
(
size_t
rowIdx
=
0
;
rowIdx
<
constraintMatrix_
->
N
();
rowIdx
++
)
{
const
auto
&
row
=
(
*
constraintMatrix_
)[
rowIdx
];
auto
cIt
=
row
.
begin
();
auto
cEnd
=
row
.
end
();
for
(;
cIt
!=
cEnd
;
++
cIt
)
{
for
(
int
l
=
0
;
l
<
constraintBlocksize
;
l
++
)
for
(
int
k
=
0
;
k
<
blocksize
;
k
++
)
if
(
std
::
abs
((
*
cIt
)[
l
][
k
])
>
jacobianCutoff_
)
values
[
idx
++
]
=
(
*
cIt
)[
l
][
k
];
}
rowCounter
+=
constraintBlocksize
;
}
}
return
true
;
}
//return the structure or values of the hessian
template
<
class
VectorType
,
class
JacobianType
>
bool
LinearIPOptProblem
<
VectorType
,
JacobianType
>::
eval_h
(
Ipopt
::
Index
n
,
const
Ipopt
::
Number
*
x
,
bool
new_x
,
Ipopt
::
Number
obj_factor
,
Ipopt
::
Index
m
,
const
Ipopt
::
Number
*
lambda
,
bool
new_lambda
,
Ipopt
::
Index
nele_hess
,
Ipopt
::
Index
*
iRow
,
Ipopt
::
Index
*
jCol
,
Ipopt
::
Number
*
values
)
{
return
true
;
}
template
<
class
VectorType
,
class
JacobianType
>
void
LinearIPOptProblem
<
VectorType
,
JacobianType
>::
finalize_solution
(
Ipopt
::
SolverReturn
status
,
Ipopt
::
Index
n
,
const
Ipopt
::
Number
*
x
,
const
Ipopt
::
Number
*
z_L
,
const
Ipopt
::
Number
*
z_U
,
Ipopt
::
Index
m
,
const
Ipopt
::
Number
*
g
,
const
Ipopt
::
Number
*
lambda
,
Ipopt
::
Number
obj_value
,
const
Ipopt
::
IpoptData
*
ip_data
,
Ipopt
::
IpoptCalculatedQuantities
*
ip_cq
)
{
// here is where we would store the solution to variables, or write to a file, etc
// so we could use the solution.
for
(
size_t
i
=
0
;
i
<
x_
->
size
();
i
++
)
for
(
int
j
=
0
;
j
<
blocksize
;
j
++
)
(
*
x_
)[
i
][
j
]
=
x
[
i
*
blocksize
+
j
];
}
/** \brief Wraps the IPOpt interior-point solver for quadratic problems with
* linear constraints and bound constraints.
*
* The problems that can be solved are of the form
* \f[
* \min_x \frac{1}{2}x^T A x - b^T x
* x_l \leq x \leq x_u
* g_l \leq G x \leq g_u
* \f]
*
* \tparam JacobianType The type of the jacobian of the linear constraints
*/
template
<
class
VectorType
,
class
JacobianType
>
class
LinearIPOptSolver
:
public
IterativeSolver
<
VectorType
>
,
public
CanIgnore
<
Dune
::
BitSetVector
<
VectorType
::
block_type
::
dimension
>
>
{
enum
{
blocksize
=
VectorType
::
block_type
::
dimension
};
enum
{
constraintBlocksize
=
JacobianType
::
block_type
::
rows
};
typedef
typename
VectorType
::
field_type
field_type
;
typedef
Dune
::
FieldMatrix
<
field_type
,
blocksize
,
blocksize
>
MatrixBlock
;
typedef
Dune
::
FieldVector
<
field_type
,
blocksize
>
VectorBlock
;
public
:
/** \brief Default constructor */
LinearIPOptSolver
()
:
IterativeSolver
<
VectorType
>
(
1e-8
,
100
,
NumProc
::
FULL
),
rhs_
(
NULL
),
obstacles_
(
NULL
),
linearSolverType_
(
""
),
constraintObstacles_
(
nullptr
),
constraintMatrix_
(
nullptr
)
{}
/** \brief Constructor for a linear problem */
LinearIPOptSolver
(
VectorType
&
x
,
const
VectorType
&
rhs
,
NumProc
::
VerbosityMode
verbosity
=
NumProc
::
FULL
,
std
::
string
linearSolverType
=
""
)
:
IterativeSolver
<
VectorType
>
(
1e-8
,
100
,
verbosity
),
rhs_
(
&
rhs
),
obstacles_
(
NULL
),
linearSolverType_
(
linearSolverType
),
constraintObstacles_
(
nullptr
),
constraintMatrix_
(
nullptr
)
{
this
->
x_
=
&
x
;
}
void
setProblem
(
VectorType
&
x
,
const
VectorType
&
rhs
)
{
x_
=
&
x
;
rhs_
=
&
rhs
;
}
void
setLinearConstraints
(
const
JacobianType
&
constraintMatrix
,
const
std
::
vector
<
BoxConstraint
<
field_type
,
constraintBlocksize
>
>&
obstacles
)
{
constraintMatrix_
=
Dune
::
stackobject_to_shared_ptr
(
constraintMatrix
);
constraintObstacles_
=
Dune
::
stackobject_to_shared_ptr
(
obstacles
);
}
virtual
void
solve
();
///////////////////////////////////////////////////////
// Data
///////////////////////////////////////////////////////
//! Vector to store the solution
VectorType
*
x_
;
//! The linear term in the linear energy
const
VectorType
*
rhs_
;
//! Vector containing the bound constraints of the variables
// Can stay unset when no bound constraints exist
std
::
vector
<
BoxConstraint
<
field_type
,
blocksize
>
>*
obstacles_
;
//! The type of the linear solver to be used within IpOpt, default is ""
std
::
string
linearSolverType_
;
//! IpOpt expects constraints to be of the type g_l <= g(x) <= g_u
// Can stay unset when no linear constraints exist
std
::
shared_ptr
<
const
std
::
vector
<
BoxConstraint
<
field_type
,
constraintBlocksize
>
>
>
constraintObstacles_
;
//! The matrix corresponding to linear constraints
// Can stay unset when no linear constraints exist
std
::
shared_ptr
<
const
JacobianType
>
constraintMatrix_
;
};
template
<
class
VectorType
,
class
JacobianType
>
void
LinearIPOptSolver
<
VectorType
,
JacobianType
>::
solve
()
{
// Create a new instance of your nlp
// (use a SmartPtr, not raw)
Ipopt
::
SmartPtr
<
Ipopt
::
TNLP
>
mynlp
=
new
LinearIPOptProblem
<
VectorType
,
JacobianType
>
(
x_
,
rhs_
,
this
->
ignoreNodes_
,
obstacles_
,
constraintMatrix_
,
constraintObstacles_
);
// Create a new instance of IpoptApplication
// (use a SmartPtr, not raw)
Ipopt
::
SmartPtr
<
Ipopt
::
IpoptApplication
>
app
=
new
Ipopt
::
IpoptApplication
();
// Change some options
app
->
Options
()
->
SetNumericValue
(
"tol"
,
this
->
tolerance_
);
app
->
Options
()
->
SetIntegerValue
(
"max_iter"
,
this
->
maxIterations_
);
app
->
Options
()
->
SetStringValue
(
"mu_strategy"
,
"adaptive"
);
if
(
linearSolverType_
!=
""
)
app
->
Options
()
->
SetStringValue
(
"linear_solver"
,
linearSolverType_
);
app
->
Options
()
->
SetStringValue
(
"output_file"
,
"ipopt.out"
);
app
->
Options
()
->
SetStringValue
(
"hessian_constant"
,
"yes"
);
// We only support linear constraints
app
->
Options
()
->
SetStringValue
(
"jac_d_constant"
,
"yes"
);
app
->
Options
()
->
SetStringValue
(
"jac_c_constant"
,
"yes"
);
switch
(
this
->
verbosity_
)
{
case
NumProc
::
QUIET
:
app
->
Options
()
->
SetIntegerValue
(
"print_level"
,
0
);
break
;
case
NumProc
::
REDUCED
:
app
->
Options
()
->
SetIntegerValue
(
"print_level"
,
5
);
break
;
case
NumProc
::
FULL
:
app
->
Options
()
->
SetIntegerValue
(
"print_level"
,
12
);
}
// Intialize the IpoptApplication and process the options
Ipopt
::
ApplicationReturnStatus
status
;
status
=
app
->
Initialize
();
if
(
status
!=
Ipopt
::
Solve_Succeeded
)
DUNE_THROW
(
Dune
::
Exception
,
"IPOpt: Error during initialization!"
);
// Ask Ipopt to solve the problem
status
=
app
->
OptimizeTNLP
(
mynlp
);
// Print helpful text for at least some cases
if
(
status
==
Ipopt
::
Invalid_Option
)
DUNE_THROW
(
Dune
::
Exception
,
"IPOpt returned 'Invalid_Option' error!"
);
if
(
status
==
Ipopt
::
Solved_To_Acceptable_Level
)
std
::
cout
<<
"WARNING: Desired tolerance could not be reached, but still accetable tolerance is reached.
\n
"
;
else
if
(
status
!=
Ipopt
::
Solve_Succeeded
)
DUNE_THROW
(
Dune
::
Exception
,
"IPOpt: Error during optimization!"
);
}
#endif
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment