9static char help[] =
"Test diagonal nonnegative least squares.\n\n";
18 const PetscScalar *data;
19 CHKERR VecGetOwnershipRange(vec, &first, &last);
20 CHKERR VecGetArrayRead(vec, &data);
21 for (
auto i = first;
i != last; ++
i)
23 CHKERR VecRestoreArrayRead(vec, &data);
24 CHKERR MPIU_Allreduce(MPI_IN_PLACE,
values.data(),
N, MPIU_SCALAR, MPI_SUM,
34 CHKERR VecGetOwnershipRange(vec, &first, &last);
35 CHKERR VecGetArray(vec, &data);
36 for (
auto i = first;
i != last; ++
i)
38 CHKERR VecRestoreArray(vec, &data);
43 PetscInt local_rows, local_columns, global_rows, global_columns;
46 "Get local column size");
51 global_rows, global_columns, local_columns,
52 nullptr, global_columns - local_columns,
60writeRows(Mat matrix,
const std::array<std::array<PetscScalar, 3>,
N> &
rows) {
63 const PetscInt columns[] = {0, 1, 2};
64 CHKERR MatGetOwnershipRange(matrix, &first, &last);
65 for (
auto row = first; row != last; ++row)
68 CHKERR MatAssemblyBegin(matrix, MAT_FINAL_ASSEMBLY);
69 CHKERR MatAssemblyEnd(matrix, MAT_FINAL_ASSEMBLY);
78 static PetscErrorCode evaluate(Tao, Vec x, PetscReal *f, Vec
g,
void *ctx) {
80 auto &problem = *
static_cast<LeastSquares *
>(ctx);
81 CHKERR MatMultTranspose(problem.jacobian, x, problem.residual);
82 CHKERR VecAXPY(problem.residual, -1, problem.target);
84 CHKERR VecDot(problem.residual, problem.residual, &squared);
85 *f = 0.5 * PetscRealPart(squared);
86 CHKERR MatMult(problem.jacobian, problem.residual,
g);
95 CHKERR VecZeroEntries(nonnegative);
99 CHKERR TaoSetType(tao, TAOSHELL);
101 CHKERR TaoSetOptionsPrefix(tao,
"direct_");
102 CHKERR TaoSetSolution(tao, x);
103 CHKERR TaoSetFromOptions(tao);
106 std::array<PetscScalar, 3>
target;
107 std::array<PetscScalar, 2> scales, expected;
110 const std::array<Case, 4> cases = {{{{3, 4, 1}, {1, 1}, {1, 0}, 0.5},
111 {{7, 1, 2}, {1, 1}, {1, 0}, 14.5},
112 {{0, 0, 0}, {1, 1}, {0, 0}, 0},
113 {{-1, 7, 2}, {0.1, 10}, {10, 0.1}, 2}}};
114 for (
size_t i = 0;
i != cases.size(); ++
i) {
115 const auto &test = cases[
i];
118 std::array<std::array<PetscScalar, 3>, 2>{
119 {{3 * test.scales[0], 4 * test.scales[0], 0},
120 {-4 * test.scales[1], 3 * test.scales[1], 0}}});
127 if (
i == 0 ||
i == 2)
129 if (previous_target && previous_target.use_count() != 1)
131 "Rebinding did not release the previous NNLS target");
133 CHKERR TaoSetVariableBounds(tao, nonnegative,
nullptr);
136 PetscReal objective, projected_gradient;
137 TaoConvergedReason reason;
138 CHKERR TaoGetSolutionStatus(tao,
nullptr, &objective, &projected_gradient,
139 nullptr,
nullptr, &reason);
141 PetscReal stored_norm;
142 CHKERR TaoGetGradient(tao, &stored_gradient,
nullptr,
nullptr);
143 CHKERR VecNorm(stored_gradient, NORM_2, &stored_norm);
144 std::array<PetscScalar, 2>
values;
146 if (reason <= 0 || !std::isfinite(stored_norm) ||
147 std::abs(stored_norm - projected_gradient) > 1e-10 ||
148 std::abs(objective - test.objective) > 1e-10 ||
149 projected_gradient > 1e-10 ||
150 PetscAbsScalar(
values[0] - test.expected[0]) > 1e-10 ||
151 PetscAbsScalar(
values[1] - test.expected[1]) > 1e-10)
153 "Incorrect diagonal NNLS solution or convergence status");
155 auto reference =
createTao(PETSC_COMM_WORLD);
160 CHKERR VecZeroEntries(reference_x);
161 CHKERR VecZeroEntries(lower);
162 CHKERR VecSet(upper, PETSC_INFINITY);
164 CHKERR TaoSetType(reference, TAOBLMVM);
165 CHKERR TaoSetSolution(reference, reference_x);
166 CHKERR TaoSetVariableBounds(reference, lower, upper);
167 CHKERR ::TaoSetObjectiveAndGradient(reference,
gradient,
168 LeastSquares::evaluate, &problem);
169 CHKERR TaoSetTolerances(reference, 1e-10, 0, 0);
170 CHKERR TaoSetMaximumIterations(reference, 1000);
171 CHKERR TaoSolve(reference);
172 CHKERR TaoGetConvergedReason(reference, &reason);
173 CHKERR VecAXPY(reference_x, -1, x);
174 PetscReal difference;
175 CHKERR VecNorm(reference_x, NORM_INFINITY, &difference);
176 if (reason <= 0 || difference > 1e-7)
178 "Diagonal NNLS disagrees with BLMVM");
181 CHKERR VecZeroEntries(short_bound);
182 for (
const auto wrong_size : {
true,
false}) {
184 CHKERR VecSet(nonnegative, 1);
185 CHKERR PetscPushErrorHandler(PetscReturnErrorHandler,
nullptr);
186 auto error = TaoSetVariableBounds(
187 tao, wrong_size ? short_bound.get() : nonnegative.get(),
nullptr);
189 error = TaoSolve(tao);
190 CHKERR PetscPopErrorHandler();
191 if (error != (wrong_size ? PETSC_ERR_ARG_SIZ : PETSC_ERR_SUP))
193 "Diagonal NNLS did not reject unsupported bounds");
195 CHKERR VecZeroEntries(nonnegative);
196 CHKERR TaoSetVariableBounds(tao, nonnegative,
nullptr);
199 "NNLS did not retain its problem data");
200 CHKERR TaoSetType(tao, TAOLMVM);
203 "Changing TAO type did not release NNLS problem data");
204 CHKERR PetscPrintf(PETSC_COMM_WORLD,
205 "Diagonal NNLS: four analytic cases agree with BLMVM\n");
217 std::array<std::array<PetscScalar, 3>, 2>{
218 {zero_row ? std::array<PetscScalar, 3>{0, 0, 0}
219 : std::array<PetscScalar, 3>{1, 1, 0},
223 CHKERR TaoSetSolution(tao, x);
224 CHKERR PetscPushErrorHandler(PetscReturnErrorHandler,
nullptr);
227 error = TaoSolve(tao);
228 CHKERR PetscPopErrorHandler();
229 if (error != (zero_row ? PETSC_ERR_ARG_OUTOFRANGE : PETSC_ERR_ARG_INCOMP))
231 "Diagonal NNLS did not reject unsupported Jacobian rows");
241 auto dm =
createDM(PETSC_COMM_WORLD, DMSHELL);
243 CHKERR writeValues(x, std::array<PetscScalar, 3>{1, 1, 3});
245 CHKERR TaoSetOptionsPrefix(tao,
"cell_");
246 CHKERR TaoSetSolution(tao, x);
247 CHKERR ::TaoSetObjectiveAndGradient(
249 [](Tao, Vec x, PetscReal *f, Vec
g,
void *) {
251 std::array<PetscScalar, 3> p;
253 *f = 0.5 * (PetscSqr(p[0] - 3) + PetscSqr(p[1] - 4)) + p[2];
255 std::array<PetscScalar, 3>{p[0] - 3, p[1] - 4, 1});
259 CHKERR TaoSetInequalityConstraintsRoutine(
261 [](Tao, Vec x, Vec
c,
void *) {
263 std::array<PetscScalar, 3> p;
265 CHKERR VecSet(
c, p[2] - std::hypot(p[0], p[1]));
269 CHKERR TaoSetJacobianInequalityRoutine(
271 [](Tao, Vec x, Mat
j, Mat,
void *) {
273 std::array<PetscScalar, 3> p;
275 const auto radius = std::hypot(p[0], p[1]);
276 CHKERR writeRows(
j, std::array<std::array<PetscScalar, 3>, 1>{
277 {{-p[0] / radius, -p[1] / radius, 1}}});
282 CHKERR TaoSetMaximumIterations(tao, 300);
283 CHKERR TaoSetTolerances(tao, 1e-7, 0, 0);
284 CHKERR TaoSetConstraintTolerances(tao, 1e-7, 0);
285 CHKERR TaoSetFromOptions(tao);
288 TaoConvergedReason reason;
289 CHKERR TaoGetSolutionStatus(tao,
nullptr, &objective, &
residual,
nullptr,
291 std::array<PetscScalar, 3>
values;
295 std::array<PetscScalar, 1> dual, constraint;
297 CHKERR readValues(
c, constraint);
298 if (reason <= 0 || residual > 1e-7 || std::abs(objective - 4.5) > 5e-6 ||
299 PetscAbsScalar(
values[0] - 2.4) > 5e-6 ||
300 PetscAbsScalar(
values[1] - 3.2) > 5e-6 ||
301 PetscAbsScalar(
values[2] - 4) > 5e-6 ||
302 PetscAbsScalar(dual[0] - 1) > 5e-6 ||
303 PetscRealPart(constraint[0]) < -1e-7)
305 "Incorrect null-space optimum with diagonal multiplier solver");
308 "Null-space diagonal multipliers: x=(%g,%g,%g), KKT=%g\n",
309 static_cast<double>(
values[0]),
static_cast<double>(
values[1]),
316int main(
int argc,
char *argv[]) {
321 CHKERR checkDirectSolve();
322 CHKERR checkInvalidRows(
false);
323 CHKERR checkInvalidRows(
true);
324 CHKERR checkNullSpaceIntegration();
SmartPetscObj< Vec > target
SmartPetscObj< Vec > residual
SmartPetscObj< Vec > gradient
SmartPetscObj< Mat > jacobian
SmartPetscObj< Vec > values
SmartPetscObj< Vec > multipliers
#define CATCH_ERRORS
Catch errors.
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_DATA_INCONSISTENCY
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
constexpr char TAONULLSPACE[]
FTensor::Index< 'i', SPACE_DIM > i
const double c
speed of light (cm/ns)
FTensor::Index< 'j', 3 > j
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
MoFEMErrorCode TaoNullSpaceGetMultipliers(Tao tao, Vec *multipliers)
MoFEMErrorCode TaoDiagonalNNLSSetProblem(Tao tao, Mat jacobian, Vec target)
MoFEMErrorCode TaoNullSpaceSetConstraints(Tao tao, DM constraint_dm, Vec constraints, Mat jacobian, Mat preconditioner)
MoFEMErrorCode TaoRegisterDiagonalNNLS()
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
auto createVectorMPI(MPI_Comm comm, PetscInt n, PetscInt N)
Create MPI Vector.
constexpr char TAODIAGONALNNLS[]
MoFEMErrorCode MatSetValues(Mat M, const EntitiesFieldData::EntData &row_data, const EntitiesFieldData::EntData &col_data, const double *ptr, InsertMode iora)
Assemble PETSc matrix.
PetscObject getPetscObject(T obj)
MoFEMErrorCode TaoRegisterNullSpace()
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM object.
auto createTao(MPI_Comm comm)
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
intrusive_ptr for managing petsc objects