Geogram  Version 1.9.1-rc
A programming library of geometric algorithms
mixed_constrained_solver.h
1 /*
2  * Copyright (c) 2000-2022 Inria
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  * * Neither the name of the ALICE Project-Team nor the names of its
14  * contributors may be used to endorse or promote products derived from this
15  * software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  * Contact: Bruno Levy
30  *
31  * https://www.inria.fr/fr/bruno-levy
32  *
33  * Inria,
34  * Domaine de Voluceau,
35  * 78150 Le Chesnay - Rocquencourt
36  * FRANCE
37  *
38  */
39 
40 
41 #ifndef H_HEXDOM_ALGO_MIXED_CONSTRAINED_SOLVER_H
42 #define H_HEXDOM_ALGO_MIXED_CONSTRAINED_SOLVER_H
43 
44 
46 #include <exploragram/hexdom/basic.h>
47 #include <exploragram/hexdom/id_map.h>
48 #include <geogram/NL/nl.h>
49 #include <algorithm>
50 
51 
52 
53 //***************************************************
54 // HOW TO USE:
55 //***************************************************
56 // MatrixMixedConstrainedSolver intsolver(nb_vars);
57 // // tell that variable var_id is a multiple of m
58 // intsolver.set_multiplicity(var_id, m);
59 // // tell 4 times the linear constraints
60 // FOR(pass, 4) {
61 // // construct each constraint
62 // intsolver.begin_constraint();
63 // intsolver.add_constraint_coeff(var_id, coeff);
64 // ....
65 // intsolver.end_constraint();
66 // // tell the solver to start the next pass
67 // intsolver.end_pass(pass);
68 //}
69 // // solve in two pass
70 // FOR(iter, 2) {
71 // if (iter == 0) intsolver.start_full_real_iter();
72 // else intsolver.start_mixed_iter();
73 // intsolver.begin_energy();
74 // intsolver.add_energy_coeff(var_id, coeff);
75 // ....
76 // intsolver.add_energy_rhs(rhs);
77 // intsolver.end_energy();
78 // }
79 // intsolver.end_iter();
80 //}
81 // // get the result
82 //double var_value = intsolver.value(var_id);
83 
84 
85 namespace GEO {
86 
87  struct Coeff {
88  Coeff(index_t p_index, double p_a) : index(p_index), a(p_a) {
89  }
90 
91  Coeff() : index(index_t(-1)), a(-1.0) {
92  }
93 
94  index_t index;
95  double a;
96  };
97 
98  inline std::ostream& operator<<(
99  std::ostream& os, const GEO::vector<Coeff>& obj
100  ) {
101  // write obj to stream
102  FOR(i, obj.size())
103  os <<(i?" + ":"")<< obj[i].a << ".X_"<<obj[i].index;
104  return os;
105  }
106 
107  //inline double nint(double x) {
108  // // return floor(x + .5);
109  // double r1 = floor(x);
110  // double r2 = floor(x + 1.0);
111  // return (x - r1) < (r2 - x) ? r1 : r2;
112  //}
113 
114  inline bool coeffCmp(const Coeff& A, const Coeff& B) {
115  return (A.index < B.index);
116  }
117 
118  inline void order_AND_make_unique(vector<Coeff>& c) {
119  std::sort(c.begin(), c.end(), coeffCmp);
120  double sum = 0;
121  index_t ires = 0;
122  FOR(i, c.size()) {
123  sum += c[i].a;
124  if (i + 1 != c.size() && c[i].index == c[i + 1].index) {
125  continue;
126  }
127  if (std::fabs(sum)>1e-10) {
128  c[ires] = Coeff(c[i].index, sum);
129  ires++;
130  }
131  sum = 0;
132  }
133  c.resize(ires);
134  }
135 
148  vector<Coeff>& L, index_t index, double val
149  ) {
150  // [BL] what follows is an optimized version of:
151  // L.push_back(Coeff(index,val));
152  // order_AND_make_unique(L);
153  for (index_t jj = 0; jj < L.size(); ++jj) {
154  if (L[jj].index == index) {
155  L[jj].a += val;
156  return;
157  }
158  if (L[jj].index > index) {
159  L.insert(L.begin() + long(jj), Coeff(index, val));
160  return;
161  }
162  }
163  L.push_back(Coeff(index, val));
164  }
165 
167 
168  void init_zero(index_t p_nb_lines) {
169  M.resize(p_nb_lines);
170  // [BL] the following line was missing (resize does
171  // not reset the existing items in a vector).
172  for (index_t i = 0; i < p_nb_lines; ++i) {
173  M[i].resize(0);
174  }
175  }
176 
177  void init_identity(index_t size) {
178  init_zero(size);
179  FOR(i, size) {
180  M[i].push_back(Coeff(i, 1));
181  }
182  }
183 
184  index_t nb_coeffs_in_line(index_t l) const {
185  return M[l].size();
186  }
187 
188  const Coeff& get(index_t line, index_t i_th_non_null_coeff) const {
189  return M[line][i_th_non_null_coeff];
190  }
191 
192  void add(index_t line, index_t col, double coeff) {
193  add_to_sorted_sparse_vector(M[line], col, coeff);
194  // [BL] the code above replaces:
195  // L.push_back(Coeff(col,coeff));
196  // order_AND_make_unique(L);
197  }
198 
199  index_t nb_lines() const {
200  return index_t(M.size());
201  }
202 
204  };
205 
206 
207 
208  // a RemoveColMatrix B is a matrix that zeros a column of M by M <-- MB
210 
211  RemoveColMatrix(vector<Coeff> C, index_t ind_to_remove = 0) {
212  geo_assert(ind_to_remove < C.size());
213  /* if (ind_to_remove >= 0) [BL] TODO: Check with Nico !!!*/
214  std::swap(C.back(), C[ind_to_remove]);
215  zero_col = C.back().index;
216  double multi = -1. / C.back().a;
217  C.pop_back();
218  FOR(c, C.size()) {
219  line.push_back(Coeff(C[c].index, C[c].a*multi));
220  }
221  }
222 
223  index_t nb_coeffs_in_line(index_t l) const {
224  if (zero_col == l) {
225  return line.size();
226  }
227  return 1;
228  }
229 
230  Coeff get(index_t l, int i_th_non_null_coeff) {
231  if (zero_col == l) {
232  return line[i_th_non_null_coeff];
233  }
234  return Coeff(l, 1.);
235  }
236 
237  // [BL] can we remove this function ?
238  /*
239  index_t nb_lines() const {
240  geo_assert_not_reached;
241  return NOT_AN_ID;
242  }
243  */
244 
245  index_t zero_col;
246  vector<Coeff > line;
247  };
248 
249 
250  // [BL] passed result by reference instead of making it returned.
251  inline void mult(const vector<Coeff>& c, NaiveSparseMatrix& B, vector<Coeff>& result) {
252  result.resize(0);
253  FOR(co_c, c.size()) {
254  index_t lB = c[co_c].index;
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));
257  }
258  }
259  order_AND_make_unique(result);
260  }
261 
262  // MatrixM is filled in 3 passes
263  // pass 1: creates M0 that sets some variables to zero
264  // pass 2: creates M1 that creates an indirection
265  // pass 3: creates M2 that manage all remaining problems
266 
267  struct MatrixM {
268 
269  MatrixM(index_t size) {
270  multiplicity.resize(size, 0);
271  DEBUG_init_multiplicity.resize(size, 0);
272  M0.resize(size);
273  FOR(i, size) {
274  M0[i] = i;
275  }
276  pass = 0;
277  }
278 
279  void finalize_M0() {
280  geo_assert(M1.size() == 0);
281  geo_assert(M2.nb_lines() == 0);
282  index_t M0_nb_col = 0;
283  FOR(i, M0.size()) {
284  if (M0[i] != NOT_AN_ID) {
285  multiplicity[M0_nb_col] = multiplicity[i];
286  M0[i] = M0_nb_col;
287  M0_nb_col++;
288  }
289  }
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);
293  FOR(i, M0_nb_col) {
294  M1[i] = Coeff(i, 1);
295  }
296  }
297 
298  void finalize_M1() {
299  geo_assert(M2.nb_lines() == 0);
300 
301  // find M1^n (n-> infty)
302  FOR(i, M1.size()) {
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;
306  }
307  }
308 
309  // compress
310  index_t M1_nb_col = 0;
311  vector<index_t> to_grp(M1.size(), NOT_AN_ID);
312  FOR(i, M1.size()) if (M1[i].index == i) {
313  to_grp[i] = M1_nb_col;
314  M1_nb_col++;
315  }
316  vector<int> new_multiplicity(M1_nb_col, 0);
317  FOR(i, M1.size()) {
318  index_t g = to_grp[M1[i].index];
319  new_multiplicity[g] = std::max(new_multiplicity[g], multiplicity[M1[i].index]);
320  M1[i].index = g;
321  }
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);
326 
327  }
328 
329  void finalize_M2() {
330  // WARNING !
331  // we do not compress here (there will be unused variables)
332  // some linear solver may not appreciate it...
333  index_t M2_nb_col = 0;
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;
338  }
339 
340  void end_pass(index_t p_pass) {
341  geo_assert(pass == p_pass);
342  if (pass == 0) {
343  finalize_M0();
344  }
345  else if (pass == 1) {
346  finalize_M1();
347  }
348  else if (pass == 2) {
349  finalize_M2();
350  } else {
351  check_multiplicity();
352  }
353  pass++;
354  }
355 
356 
357  vector<Coeff> mult_by_M0(vector<Coeff>& c) {
358  vector<Coeff> cM0;
359  FOR(i, c.size()) if (M0[c[i].index] != NOT_AN_ID) cM0.push_back(Coeff(M0[c[i].index], c[i].a));
360  return cM0;
361  }
362 
363  vector<Coeff> mult_by_M1(vector<Coeff>& cM0) {
364  vector<Coeff> cM0M1;
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);
367  return cM0M1;
368  }
369 
370  vector<Coeff> mult_by_M2(vector<Coeff>& cM0M1) {
371  vector<Coeff> cM0M1M2;
372  mult(cM0M1, M2, cM0M1M2);
373  // order_AND_make_unique(cM0M1M2); [BL]: already done in mult()
374  return cM0M1M2;
375  }
376 
377  void inplace_mult_M2_by_B(RemoveColMatrix& B) {
378  vector<Coeff> diffline = B.line;
379  add_to_sorted_sparse_vector(diffline, B.zero_col, -1.0);
380  // [BL] replaced with "insert_in_sorted_vector"
381  // diffline.push_back(Coeff(B.zero_col, -1.));
382  // order_AND_make_unique(diffline);
383 
384  vector<Coeff> M2col = M2t.M[B.zero_col];
385  FOR(nc, diffline.size()) {
386  FOR(nl, M2col.size()) {
387  index_t c = diffline[nc].index;
388  index_t l = M2col[nl].index;
389  double coeff = diffline[nc].a*M2col[nl].a;
390  M2t.add(c, l, coeff);
391  M2.add(l, c, coeff);
392  }
393  }
394  }
395 
396  bool add_constraint(vector<Coeff>& c) {
397 
398  if (pass == 0) {
399  if (c.size() == 1) {
400  geo_assert(c[0].a != 0);
401  M0[c[0].index] = NOT_AN_ID;
402  }
403  return true;
404  }
405 
406  vector<Coeff> cM0 = mult_by_M0(c);
407 
408  vector<Coeff> cM0M1 = mult_by_M1(cM0);
409  if (cM0M1.size() == 0) return true;
410 
411  if (pass == 1) {
412  if (cM0M1.size() == 2) {
413  FOR(i, 2) if ((std::abs(cM0M1[i].a) != 1)) return false;
414  RemoveColMatrix B(cM0M1);
415  Coeff co[2] = { Coeff(B.zero_col, 1.0),B.line[0] };
416  // find root
417  FOR(i, 2) {
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;
421  }
422  }
423  // link
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);
427 
428  }
429  return true;
430  }
431 
432  vector<Coeff> cM0M1M2 = mult_by_M2(cM0M1);
433  if (cM0M1M2.size() == 0) {
434  return true;
435  }
436 
437  if (pass == 2) {
438  index_t ind_to_remove = 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)) {
443  ind_to_remove = i;
444  }
445  }
446  RemoveColMatrix B(cM0M1M2, ind_to_remove);
447  inplace_mult_M2_by_B(B);
448  }
449  // debug
450  geo_assert(pass != 3 || cM0M1M2.empty());// "Kernel must be complete ";
451  return true;
452 
453  }
454 
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]) {
458  plop(x);
459  plop(debug_var_multiplicity(x));
460  plop(DEBUG_init_multiplicity[x]);
461  show_line(x);
463  }
464  }
465  void show_line(index_t x) {
466  vector<Coeff> res = get_line(x);
467  plop(DEBUG_init_multiplicity[x]);
468  FOR(i, res.size()) {
469  std::cerr<< res[i].a<<" . "<< res[i].index<< " ( mul= " << multiplicity[res[i].index] <<" )\n";
470  }
471  }
472 
473  vector<Coeff> get_line(index_t l) {
474  vector<Coeff> c(1, Coeff(l, 1.));
475  vector<Coeff> cM0 = mult_by_M0(c);
476  if (M1.empty()) return cM0;
477  vector<Coeff> cM0M1 = mult_by_M1(cM0);
478  if (M2.M.empty()) return cM0M1;
479  return mult_by_M2(cM0M1);
480  }
481 
482  double debug_var_multiplicity(index_t x) {
483  double min_mult = 10000;
484  vector<Coeff> res = get_line(x);
485  FOR(i, res.size()) {
486  min_mult = std::min(
487  min_mult,
488  double(multiplicity[res[i].index]) * std::abs(res[i].a)
489  );
490  }
491  return min_mult;
492  }
493 
494  vector<index_t> M0; // indirection map that removes null variables (set when growing a sphere)
495  vector<Coeff> M1; // indirection map + coefficient that produces groups of variables (for boundary & cuts)
496  NaiveSparseMatrix M2; // removes extra DOF when joining boundaries & cuts
497  NaiveSparseMatrix M2t; // transposed of M2: speed up computations
498  vector<int> multiplicity; // the multiplicity constraint for each variable (solver variable, not user variable)
499  index_t kernel_size; // number of final DOF
500  index_t pass; // iteration in filling the constraint matrix
501  vector<int> DEBUG_init_multiplicity; // the multiplicity constraint for each variable (user variable)
502  };
503 
504 
505 
507 
509  M(p_nb_vars),
510  size_(p_nb_vars) {
511  snap_size = 0;
512  }
513 
518  index_t size() const {
519  return size_;
520  }
521 
522  // set multiple (including integer) constraints
523  void set_multiplicity(index_t id, int period) {
524  geo_debug_assert(id < size());
525  M.multiplicity[id] = period;
526  M.DEBUG_init_multiplicity[id] = period;
527  }
528 
529  // constraints are included by increasing nuber of variables (from 1 to 3). The last pass (==3) is just for checking.
530  void end_pass(index_t p_pass) {
531  M.end_pass(p_pass);
532  }
533 
534  // add a new constraint
535  void begin_constraint() {
536  new_constraint.clear();
537  }
538 
539  void add_constraint_coeff(index_t id, double coeff) {
540  geo_debug_assert(id < size());
541  if (coeff != 0.0) {
542  new_constraint.push_back(Coeff(id, coeff));
543  }
544  }
545 
546  bool end_constraint() {
547  return M.add_constraint(new_constraint);
548  }
549  vector<Coeff> new_constraint;
550 
551  // start / end solving iterations
552  void start_new_iter() {
553  std::cerr << "New LS iteration \n";
554  bool first_iter = V.empty();
555  if (first_iter) {
556  fixed.resize(M.kernel_size, false);
557  V.resize(M.kernel_size);
558  }
559  nlNewContext();
561  nlSolverParameteri(NL_NB_VARIABLES, NLint(M.kernel_size));
563 
564  if (!first_iter) {
565  static const double auto_snap_threshold = 1.;// .005;// 25;
566  double snap_threshold = 1e20;
567  int nb_fixed_var = 0;
568  bool snap_size_has_changed = false;
569  do {
570  std::cerr << "Try enforce mutiplicity equality with snap size " << snap_size << "\n";
571  FOR(pass, 2) {
572  //FOR(i, M.kernel_size) if (M.multiplicity[i]>0)std::cerr << i << " " << M.multiplicity[i] << "\n";
573  FOR(i, M.kernel_size) {
574  nlSetVariable(i, V[i]);
575 
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;
580  double val = V[i];
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]);
583  if (pass == 0) {
584  if (dist < snap_threshold
585  && snap_threshold>auto_snap_threshold) {
586  snap_threshold = std::max(dist + .001, auto_snap_threshold);
587  }
588  continue;
589  }
590 
591  //if (!fixed[i]) {
592  // std::cerr << std::setprecision(2);
593  // std::cerr << snap_threshold << " " << dist << " " << val << "(" << M.multiplicity[i] << ")\n";
594  // if (dist < snap_threshold)
595  // std::cerr << snap_threshold << " < " << dist << " < " << 1.- snap_threshold << "\n";
596  //}
597 
598  if (dist < snap_threshold && M.multiplicity[i] != 1000) {
599  if (!fixed[i]) nb_fixed_var++;
600  fixed[i] = true;
601  GEO::Logger::out("HexDom") << " i " << i << " snapped_val" << snapped_val << " (V[i] " << V[i] << std::endl;
602  nlSetVariable(i, snapped_val);
603  nlLockVariable(i);
604  }
605  }
606  }
607 
608  snap_size_has_changed = false;
609  if (nb_fixed_var == 0) {
610  if (snap_size >= 1) {
611  snap_size_has_changed = true;
612  snap_size /= 2;
613  }
614  }
615  plop(nb_fixed_var);
616  } while (snap_size_has_changed);
617  }
619  }
620 
621  bool converged() {
622 
623  if (fixed.empty()) return false;
624  FOR(i, M.kernel_size)
625  if (M.multiplicity[i] > 0
626  && !fixed[i]
627  && M.M2t.nb_coeffs_in_line(i) > 0) return false;
628  return true;
629  }
630 
631  void end_iter() {
632  nlEnd(NL_MATRIX);
633  nlEnd(NL_SYSTEM);
635  nlSolve();
636  FOR(i, M.kernel_size) {
637  V[i] = nlGetVariable(i);
638  }
640  }
641 
642  // set up energy
643  void begin_energy() { nlBegin(NL_ROW); }
644  void add_energy_coeff(index_t id, double coeff) {
645  geo_debug_assert(id < size());
646  if (coeff == 0.0) {
647  return;
648  }
649  vector<Coeff> line = M.get_line(id);
650  FOR(m, line.size()) {
651  nlCoefficient(line[m].index, line[m].a*coeff);
652  }
653  }
654  void add_energy_rhs(double rhs) { nlRightHandSide(rhs); }
655 
656  void end_energy() { nlEnd(NL_ROW); }
657 
658  // access to the result ;)
659  double value(index_t i) {
660  geo_debug_assert(i < size());
661  double res = 0;
662  vector<Coeff> line = M.get_line(i);
663  FOR(m, line.size()) {
664  res += V[line[m].index] * line[m].a;
665  }
666  return res;
667  }
668 
669  double show_var(index_t i) {
670  geo_debug_assert(i < size());
671  double res = 0;
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;
677  }
678  GEO::Logger::out("HexDom") << std::endl;
679  return res;
680  }
681 
682 
683  bool solved;
684  MatrixM M; // Matrix + multiplicity of variables
685  index_t size_;
686  std::vector<double> V; // inner variables
687  std::vector<bool> fixed; // is it fixed already ?
688  int snap_size;
689  };
690 
691 }
692 
693 
694 #endif
#define geo_assert_not_reached
Sets a non reachable point in the program.
Definition: assert.h:177
#define geo_assert(x)
Verifies that a condition is met.
Definition: assert.h:149
#define geo_debug_assert(x)
Verifies that a condition is met.
Definition: assert.h:196
static std::ostream & out(const std::string &feature)
Gets the stream to send information messages.
Vector with aligned memory allocation.
Definition: memory.h:635
index_t size() const
Gets the number of elements.
Definition: memory.h:674
#define EXPLORAGRAM_API
Linkage declaration for exploragram symbols.
Definition: defs.h:18
Included by all headers in exploragram.
Global Vorpaline namespace.
Definition: basic.h:55
geo_index_t index_t
The type for storing and manipulating indices.
Definition: numeric.h:329
void sort(const ITERATOR &begin, const ITERATOR &end)
Sorts elements in parallel.
Definition: algorithm.h:90
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.
Definition: nl.h:347
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.
Definition: nl.h:1081
#define NL_SYSTEM
Symbolic constant for nlBegin() / nlEnd(), to be used to start creating / finalizing a linear system.
Definition: nl.h:1073
int32_t NLint
A 4-bytes signed integer.
Definition: nl.h:248
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.
Definition: nl.h:361
#define NL_TRUE
Constant for true NLbooleans.
Definition: nl.h:316
#define NL_ROW
Symbolic constant for nlBegin() / nlEnd(), to be used to start creating / finalizing a row.
Definition: nl.h:1089
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.
Definition: nl.h:689
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.