41 #ifndef H_HEXDOM_ALGO_MIXED_CONSTRAINED_SOLVER_H
42 #define H_HEXDOM_ALGO_MIXED_CONSTRAINED_SOLVER_H
46 #include <exploragram/hexdom/basic.h>
47 #include <exploragram/hexdom/id_map.h>
88 Coeff(
index_t p_index,
double p_a) : index(p_index), a(p_a) {
98 inline std::ostream& operator<<(
103 os <<(i?" + ":"")<< obj[i].a << ".X_"<<obj[i].index;
114 inline
bool coeffCmp(const
Coeff& A, const
Coeff& B) {
115 return (A.index < B.index);
118 inline void order_AND_make_unique(vector<Coeff>& c) {
124 if (i + 1 != c.size() && c[i].index == c[i + 1].index) {
127 if (std::fabs(sum)>1e-10) {
128 c[ires] = Coeff(c[i].index, sum);
154 if (L[jj].index == index) {
158 if (L[jj].index > index) {
159 L.insert(L.begin() +
long(jj),
Coeff(index, val));
163 L.push_back(
Coeff(index, val));
168 void init_zero(
index_t p_nb_lines) {
169 M.resize(p_nb_lines);
172 for (
index_t i = 0; i < p_nb_lines; ++i) {
177 void init_identity(
index_t size) {
180 M[i].push_back(
Coeff(i, 1));
189 return M[line][i_th_non_null_coeff];
214 std::swap(C.back(), C[ind_to_remove]);
215 zero_col = C.back().index;
216 double multi = -1. / C.back().a;
219 line.push_back(
Coeff(C[c].index, C[c].a*multi));
232 return line[i_th_non_null_coeff];
253 FOR(co_c, c.
size()) {
255 FOR(co_b, B.nb_coeffs_in_line(lB)) {
256 result.push_back(
Coeff(B.get(lB, co_b).index, B.get(lB, co_b).a * c[co_c].a));
259 order_AND_make_unique(result);
270 multiplicity.resize(size, 0);
271 DEBUG_init_multiplicity.resize(size, 0);
284 if (M0[i] != NOT_AN_ID) {
285 multiplicity[M0_nb_col] = multiplicity[i];
290 GEO::Logger::out(
"HexDom") <<
"M0 final size is " << M0.
size() <<
" x " << M0_nb_col << std::endl;
291 multiplicity.resize(M0_nb_col);
292 M1.resize(M0_nb_col);
303 while (M1[i].index != M1[M1[i].index].index) {
304 M1[i].a *= M1[M1[i].index].a;
305 M1[i].index = M1[M1[i].index].index;
312 FOR(i, M1.size())
if (M1[i].index == i) {
313 to_grp[i] = M1_nb_col;
318 index_t g = to_grp[M1[i].index];
319 new_multiplicity[g] = std::max(new_multiplicity[g], multiplicity[M1[i].index]);
322 multiplicity = new_multiplicity;
323 GEO::Logger::out(
"HexDom") <<
"M1 final size is " << M1.size() <<
" x " << M1_nb_col << std::endl;
324 M2.init_identity(M1_nb_col);
325 M2t.init_identity(M1_nb_col);
334 M2_nb_col = M2.M.size();
335 kernel_size = M2_nb_col;
336 multiplicity.resize(M2_nb_col);
337 GEO::Logger::out(
"HexDom") <<
"M2 final size is " << M2.nb_lines() <<
" x " << M2_nb_col << std::endl;
340 void end_pass(
index_t p_pass) {
345 else if (pass == 1) {
348 else if (pass == 2) {
351 check_multiplicity();
359 FOR(i, c.
size())
if (M0[c[i].index] != NOT_AN_ID) cM0.push_back(
Coeff(M0[c[i].index], c[i].a));
365 FOR(i, cM0.
size()) cM0M1.push_back(
Coeff(M1[cM0[i].index].index, cM0[i].a*M1[cM0[i].index].a));
366 order_AND_make_unique(cM0M1);
372 mult(cM0M1, M2, cM0M1M2);
385 FOR(nc, diffline.
size()) {
386 FOR(nl, M2col.
size()) {
387 index_t c = diffline[nc].index;
389 double coeff = diffline[nc].a*M2col[nl].a;
390 M2t.add(c, l, coeff);
401 M0[c[0].index] = NOT_AN_ID;
409 if (cM0M1.
size() == 0)
return true;
412 if (cM0M1.
size() == 2) {
413 FOR(i, 2)
if ((std::abs(cM0M1[i].a) != 1))
return false;
415 Coeff co[2] = {
Coeff(B.zero_col, 1.0),B.line[0] };
418 while (co[i].index != M1[co[i].index].index) {
419 co[i].a = co[i].a*M1[co[i].index].a;
420 co[i].index = M1[co[i].index].index;
424 if (multiplicity[co[0].index] < multiplicity[co[1].index])
425 M1[co[0].index] =
Coeff(co[1].index, co[1].a*co[0].a);
426 else M1[co[1].index] =
Coeff(co[0].index, co[1].a*co[0].a);
433 if (cM0M1M2.
size() == 0) {
439 FOR(i, cM0M1M2.
size()) {
440 if (cM0M1M2[i].a!=0 &&
441 double(multiplicity[cM0M1M2[i].index])* std::abs(cM0M1M2[i].a) <
442 double(multiplicity[cM0M1M2[ind_to_remove].index]) * std::abs(cM0M1M2[ind_to_remove].a)) {
447 inplace_mult_M2_by_B(B);
455 void check_multiplicity() {
456 std::cerr <<
" check_that multiplicity are respected\n";
457 FOR(x, M0.
size())
if (debug_var_multiplicity(x) < DEBUG_init_multiplicity[x]) {
459 plop(debug_var_multiplicity(x));
460 plop(DEBUG_init_multiplicity[x]);
467 plop(DEBUG_init_multiplicity[x]);
469 std::cerr<< res[i].a<<
" . "<< res[i].index<<
" ( mul= " << multiplicity[res[i].index] <<
" )\n";
476 if (M1.empty())
return cM0;
478 if (M2.M.empty())
return cM0M1;
479 return mult_by_M2(cM0M1);
482 double debug_var_multiplicity(
index_t x) {
483 double min_mult = 10000;
488 double(multiplicity[res[i].index]) * std::abs(res[i].a)
523 void set_multiplicity(
index_t id,
int period) {
525 M.multiplicity[id] = period;
526 M.DEBUG_init_multiplicity[id] = period;
530 void end_pass(
index_t p_pass) {
535 void begin_constraint() {
536 new_constraint.clear();
539 void add_constraint_coeff(
index_t id,
double coeff) {
542 new_constraint.push_back(Coeff(
id, coeff));
546 bool end_constraint() {
547 return M.add_constraint(new_constraint);
549 vector<Coeff> new_constraint;
552 void start_new_iter() {
553 std::cerr <<
"New LS iteration \n";
554 bool first_iter = V.empty();
556 fixed.resize(M.kernel_size,
false);
557 V.resize(M.kernel_size);
565 static const double auto_snap_threshold = 1.;
566 double snap_threshold = 1e20;
567 int nb_fixed_var = 0;
568 bool snap_size_has_changed =
false;
570 std::cerr <<
"Try enforce mutiplicity equality with snap size " << snap_size <<
"\n";
573 FOR(i, M.kernel_size) {
576 if (M.multiplicity[i] < snap_size)
continue;
577 if (M.multiplicity[i] ==0 )
continue;
578 if (M.M2t.nb_coeffs_in_line(i) == 0)
continue;
579 if (pass == 0 && fixed[i])
continue;
581 double snapped_val = double(M.multiplicity[i]) * nint(V[i] /
double(M.multiplicity[i]));
582 double dist = std::abs(snapped_val - val) / double(M.multiplicity[i]);
584 if (dist < snap_threshold
585 && snap_threshold>auto_snap_threshold) {
586 snap_threshold = std::max(dist + .001, auto_snap_threshold);
598 if (dist < snap_threshold && M.multiplicity[i] != 1000) {
599 if (!fixed[i]) nb_fixed_var++;
601 GEO::Logger::out(
"HexDom") <<
" i " << i <<
" snapped_val" << snapped_val <<
" (V[i] " << V[i] << std::endl;
608 snap_size_has_changed =
false;
609 if (nb_fixed_var == 0) {
610 if (snap_size >= 1) {
611 snap_size_has_changed =
true;
616 }
while (snap_size_has_changed);
623 if (fixed.empty())
return false;
624 FOR(i, M.kernel_size)
625 if (M.multiplicity[i] > 0
627 && M.M2t.nb_coeffs_in_line(i) > 0) return false;
636 FOR(i, M.kernel_size) {
644 void add_energy_coeff(
index_t id,
double coeff) {
649 vector<Coeff> line = M.get_line(
id);
650 FOR(m, line.size()) {
662 vector<Coeff> line = M.get_line(i);
663 FOR(m, line.size()) {
664 res += V[line[m].index] * line[m].a;
672 vector<Coeff> line = M.get_line(i);
673 std::cerr <<
" var " << i <<
" = ";
674 FOR(m, line.size()) {
675 std::cerr << line[m].a <<
" X " << V[line[m].index] <<
" + ";
676 res += V[line[m].index] * line[m].a;
686 std::vector<double> V;
687 std::vector<bool> fixed;
#define geo_assert_not_reached
Sets a non reachable point in the program.
#define geo_assert(x)
Verifies that a condition is met.
#define geo_debug_assert(x)
Verifies that a condition is met.
static std::ostream & out(const std::string &feature)
Gets the stream to send information messages.
Vector with aligned memory allocation.
index_t size() const
Gets the number of elements.
#define EXPLORAGRAM_API
Linkage declaration for exploragram symbols.
Included by all headers in exploragram.
Global Vorpaline namespace.
geo_index_t index_t
The type for storing and manipulating indices.
void sort(const ITERATOR &begin, const ITERATOR &end)
Sorts elements in parallel.
void add_to_sorted_sparse_vector(vector< Coeff > &L, index_t index, double val)
Adds a coefficient in a sparse vector.
The public API of the OpenNL linear solver library. Click the "More..." link below for simple example...
NLAPI void NLAPIENTRY nlEnable(NLenum pname)
Sets a boolean parameter to NL_TRUE.
NLAPI NLContext NLAPIENTRY nlGetCurrent(void)
Gets the current context.
#define NL_NB_VARIABLES
Symbolic constant for nlSolverParameteri() to specify the number of variables.
NLAPI void NLAPIENTRY nlCoefficient(NLuint i, NLdouble value)
Appends a coefficient to the current row.
NLAPI void NLAPIENTRY nlSetVariable(NLuint i, NLdouble value)
Sets the value of a variable.
#define NL_MATRIX
Symbolic constant for nlBegin() / nlEnd(), to be used to start creating / finalizing a matrix.
#define NL_SYSTEM
Symbolic constant for nlBegin() / nlEnd(), to be used to start creating / finalizing a linear system.
int32_t NLint
A 4-bytes signed integer.
NLAPI void NLAPIENTRY nlRightHandSide(NLdouble value)
Sets the right-hand side of the current row.
NLAPI void NLAPIENTRY nlSolverParameteri(NLenum pname, NLint param)
Specifies an integer solver parameter.
NLAPI void NLAPIENTRY nlLockVariable(NLuint index)
Locks a variable.
NLAPI NLboolean NLAPIENTRY nlSolve(void)
Solves the linear system in the current context.
NLAPI NLContext NLAPIENTRY nlNewContext(void)
Creates a new OpenNL context.
#define NL_LEAST_SQUARES
Symbolic constant for nlSolverParameteri() to specify whether least squares mode is used.
#define NL_TRUE
Constant for true NLbooleans.
#define NL_ROW
Symbolic constant for nlBegin() / nlEnd(), to be used to start creating / finalizing a row.
NLAPI NLdouble NLAPIENTRY nlGetVariable(NLuint i)
Gets the value of a variable.
NLAPI void NLAPIENTRY nlBegin(NLenum primitive)
Begins a new primitive.
#define NL_VERBOSE
Symbolic constant for nlEnable() / nlDisable() to enable or disable messages.
NLAPI void NLAPIENTRY nlEnd(NLenum primitive)
Begins a new primitive.
NLAPI void NLAPIENTRY nlDeleteContext(NLContext context)
Destroys an existing OpenNL context.
index_t size() const
Gets the number of variables.