Macaulay2 Engine
Loading...
Searching...
No Matches
NAG.cpp
Go to the documentation of this file.
1// Copyright 2008 Anton Leykin and Mike Stillman
2
3// Anton Leykin's code in this file is in the public domain.
4
5#include "NAG.hpp"
6
7#include "engine-includes.hpp" // need HAVE_DLFCN_H
8#include <M2/math-include.h>
9
10#include <time.h>
11#ifdef HAVE_DLFCN_H
12#include <dlfcn.h>
13#else
14#define dlopen(x, y) NULL
15#define dlsym(x, y) NULL
16#define dlclose(x) (-1)
17#endif
18
19#include "interface/NAG.h"
20#include "lapack.hpp"
21#include "matrix-con.hpp"
22#include "matrix.hpp"
23#include "poly.hpp"
24#include "relem.hpp"
25
26class FreeModule;
27
28// Straight Line Program classes
29
30// functions of the wrapper !!!
32 ring_elem e)
33{
36 return ret;
37}
39 const Matrix* consts,
41{
42 StraightLineProgram* ret = static_cast<StraightLineProgram*>(
44 return ret;
45}
51 const element_type* values,
52 element_type* out)
53{
54 SLP<ComplexField>::evaluate(n, values, out);
55}
60
61template <class Field>
63{
64 C = nullptr;
65 handle = nullptr;
66 eval_time = 0;
67 n_calls = 0;
68 nodes = nullptr;
69}
70
71template <class Field>
73{
75 if (handle != nullptr)
76 {
77 printf("closing library\n");
79 }
80}
81
82template <class Field>
84template <class Field>
86
87template <class Field>
88SLP<Field> /* or null */* SLP<Field>::make(const Matrix* m_consts,
90{
91 // todo: move some of these lines to rawSLP
92 SLP<Field>* res;
94 {
95 ERROR("max number of slps exceeded");
96 res = nullptr;
97 }
98 else if (program->len < 3)
99 {
100 ERROR("invalid SLP");
101 res = nullptr;
102 }
103 else
104 {
105 res = new SLP<Field>;
106 res->C = cast_to_CCC(m_consts->get_ring());
107 catalog[num_slps++] = res;
108 res->is_relative_position = false;
109 res->num_consts = program->array[0];
110 if (m_consts->n_cols() != res->num_consts)
111 ERROR("different number of constants expected");
112 res->num_inputs = program->array[1];
113 res->rows_out = program->array[2];
114 res->cols_out = program->array[3];
115 res->program = program;
116 switch (program->array[4])
117 {
118 case slpCOMPILED:
119 {
120 // nodes = constants + input + output
121 make_nodes(res->nodes,
122 res->num_consts + res->num_inputs +
123 res->rows_out * res->cols_out);
124 char libname[100];
125 snprintf(libname, 100,
126 "%s%d.dylib",
127 libPREFIX,
128 program->array[5]); // Mac OS
129 // sprintf(libname, "%s%d.so", libPREFIX,
130 // program->array[5]);//Linux (not working yet)
131 const char* funname = "slpFN";
132 printf("loading slpFN from %s\n", libname);
133 res->handle = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL);
134 if (res->handle == nullptr) ERROR("can't load library %s", libname);
135 res->compiled_fn = (void (*)(element_type*, element_type*))dlsym(
136 res->handle, funname);
137 if (res->compiled_fn == nullptr)
138 ERROR(
139 "can't link function %s from library %s", funname, libname);
140 }
141 break;
142 case slpPREDICTOR:
143 case slpCORRECTOR:
144 make_nodes(res->nodes,
145 res->num_consts + res->num_inputs +
146 res->rows_out * res->cols_out);
147 break;
148 default:
149 make_nodes(res->nodes,
150 program->len + res->num_consts + res->num_inputs);
151 }
152 for (int i = 0; i < res->num_consts; i++)
153 {
154 res->nodes[i] =
155 element_type(toBigComplex(res->C, m_consts->elem(0, i)));
156 }
157 }
158 return res;
159}
160
161template <class Field>
163{
164 a = newarray_atomic(element_type, size);
165}
166
167template <class Field>
169{
170 SLP<Field>* res = new SLP<Field>;
171 res->C = C;
173 res->program = M2_makearrayint(program->len);
174 memcpy(res->program->array, program->array, program->len * sizeof(int));
176 for (int i = 0; i < num_consts; i++) res->nodes[i] = nodes[i];
177 res->node_index = node_index; // points to position in program (rel. to
178 // start) of operation corresponding to a node
179 res->num_consts = num_consts;
180 res->num_inputs = num_inputs;
182 res->rows_out = rows_out;
183 res->cols_out = cols_out;
184 res->handle = handle;
186 res->eval_time = eval_time;
187 res->n_calls = n_calls;
188 return res;
189}
190
191Nterm* extract_divisible_by_x(Nterm*& ff, int i) // auxiliary
192{
193 /* Extracts into fx the terms divisible by the (n-1-i)-th variable "x"
194 and divides them by x. (exponent vectors are assumed to be reversed)
195 Note: terms in fx may not be in monomial order. */
196 Nterm* fx = nullptr;
197 Nterm* f = ff;
198 Nterm* prev_f = nullptr;
199 while (f != nullptr)
200 {
201 if (f->monom[i] == 0)
202 {
203 prev_f = f;
204 f = f->next;
205 }
206 else
207 {
208 f->monom[i]--; // divide by x
209 if (prev_f != nullptr)
210 {
211 prev_f->next = f->next; // extract
212 }
213 else
214 {
215 ff = f->next; // ... or cut
216 }
217 f->next = fx; // prepend to fx
218 fx = f;
219 f = (prev_f == nullptr) ? ff : prev_f->next;
220 }
221 }
222 return fx;
223}
224
225template <class Field>
227 typename Field::element_type c) // auxiliary
228{
230 consts.push_back(c);
231 return static_cast<int>(consts.size()) - 1;
232}
233
234/* create the part of slp computing f, return the position of the final
235 * operation */
236template <class Field>
238 gc_vector<int>& prog,
240 Nterm*& f) // auxiliary
241{
242 std::vector<int> part_pos(n); // absolute positions of the parts
243 int last_nonzero_part_pos = ZERO_CONST;
244 for (int i = 0; i < n; i++)
245 {
246 Nterm* fx = extract_divisible_by_x(f, i);
247 if (fx == nullptr)
248 part_pos[i] = ZERO_CONST;
249 else
250 {
251 int p = poly_to_horner_slp(n, prog, consts, fx);
252 last_nonzero_part_pos = part_pos[i] = num_operations++;
253 node_index.push_back(prog.size());
254 prog.push_back(slpPRODUCT);
255 prog.push_back(n - 1 - i); // reference to (n-1-i)-th input (recall: the
256 // order of vars is reversed in monomials)
257 prog.push_back(p - part_pos[i]); // relative position of p
258 }
259 }
260 int c = 0; // count nonzeros
261 if (f != nullptr) c++;
262 for (int i = 0; i < n; i++)
263 if (part_pos[i] != ZERO_CONST) c++;
264 if (c == 0) return ZERO_CONST;
265 if (c == 1 && last_nonzero_part_pos != ZERO_CONST)
266 return last_nonzero_part_pos;
267 int cur_p = num_operations++;
268 node_index.push_back(prog.size());
269 prog.push_back(slpMULTIsum);
270 prog.push_back(c);
271 if (f != nullptr)
272 prog.push_back(CONST_OFFSET +
274 consts, element_type(toBigComplex(C, f->coeff))));
275 for (int i = 0; i < n; i++)
276 if (part_pos[i] != ZERO_CONST)
277 prog.push_back(part_pos[i] - cur_p); // relative position of the i-th part
278 return cur_p;
279}
280
281void monomials_to_conventional_expvectors(int n, Nterm* f) // auxiliary
282/* "unpack" monomials */
283{
284 for (; f != nullptr; f = f->next)
285 for (int i = 0; i < n - 1; i++) f->monom[i] -= f->monom[i + 1];
286}
287
288template <class Field>
290{
291 // todo: move some of these lines to rawSLP
292 SLP<Field>* res;
294 {
295 ERROR("max number of slps exceeded");
296 res = nullptr;
297 }
298 else
299 {
300 res = new SLP<Field>;
301 res->C = cast_to_CCC(R->getCoefficientRing());
302 res->is_relative_position = true;
303 int n = res->num_inputs = R->n_vars();
304 res->num_operations = 0;
305 res->rows_out = 1;
306 res->cols_out = 1;
307 gc_vector<int> prog;
309
310 // make prog and node
311 e = R->copy(e); /* a copy of "e" will be decomposed;
312 how to remove the pieces afterwards?
313 R->remove(...) is an empty function */
314 Nterm* f = e.get_poly();
316 int out = res->poly_to_horner_slp(n, prog, consts, f);
317 if (out == ZERO_CONST)
318 {
319 out = res->num_operations++;
320 res->node_index.push_back(prog.size());
321 prog.push_back(slpMULTIsum);
322 prog.push_back(0); // sum with zero summands
323 }
324
325 // make program
327 prog.size() + 2 /* accounts for lines +2,+3 */ + SLP_HEADER_LEN);
328 res->program->array[0] = res->num_consts =
329 static_cast<int>(consts.size());
330 prog.push_back(slpEND);
331 prog.push_back(out + res->num_consts +
332 res->num_inputs); // position of the output
333
334 res->program->array[1] = res->num_inputs;
335 res->program->array[2] = res->rows_out;
336 res->program->array[3] = res->cols_out;
337 memcpy(res->program->array + SLP_HEADER_LEN,
338 prog.data(),
339 sizeof(int) * prog.size());
340
341 // make nodes: [constants, inputs, operations]
342 make_nodes(res->nodes,
343 res->num_consts + res->num_inputs + res->num_operations);
344 for (int i = 0; i < res->num_consts; i++)
345 {
346 res->nodes[i] = consts[i];
347 }
348 }
349 return res;
350}
351
352template <class Field>
354{
356 num_inputs != slp->num_inputs || rows_out != slp->rows_out)
357 {
358 ERROR("slps unstackable");
359 return nullptr;
360 }
361 int num_outputs = rows_out * cols_out;
362 int* end_program = program->array + program->len - num_outputs;
363 int* slp_start_program = slp->program->array + SLP_HEADER_LEN;
364 int slp_num_outputs = slp->rows_out * slp->cols_out;
365
366 int slp_len = slp->program->len - SLP_HEADER_LEN - slp_num_outputs;
367 // length of the part containing operations and slpEND
368
369 SLP<Field>* res = new SLP<Field>;
370 res->C = C;
371 res->is_relative_position = true;
372 res->num_inputs = num_inputs;
374 res->rows_out = rows_out;
375 res->cols_out = cols_out + slp->cols_out;
376
377 // gc_vector<element_type> consts; // !!! use to optimize constants
378
379 // make program
380 res->program = M2_makearrayint(program->len + slp_len - 1 + slp_num_outputs);
381 res->program->array[1] = res->num_inputs;
382 res->program->array[2] = res->rows_out;
383 res->program->array[3] = res->cols_out;
384
385 int* res_start_program = res->program->array + SLP_HEADER_LEN;
386 int* res_end_program =
387 res->program->array + res->program->len - slp_num_outputs - num_outputs;
388
389 // copy "this"
390 memcpy(res_start_program,
391 program->array + SLP_HEADER_LEN,
392 program->len * sizeof(int));
393 memcpy(res_end_program, end_program, num_outputs * sizeof(int));
394 for (int *a = res_end_program, i = 0; i < num_outputs; i++, a++)
395 *a += slp->num_consts;
396 res->node_index = node_index;
397
398 // copy "slp"
399 memcpy(res_end_program - slp_len, slp_start_program, slp_len * sizeof(int));
400 for (int *a = res_end_program - slp_len, i = 0;
401 i < slp_len - 1 /* for slpEND */;
402 i++, a++)
403 if (*a >= CONST_OFFSET) // if refers to a constant
404 *a += num_consts;
405 memcpy(res_end_program + num_outputs,
406 slp_start_program + slp_len,
407 slp_num_outputs * sizeof(int));
408 for (int *a = res_end_program + num_outputs, i = 0; i < slp_num_outputs;
409 i++, a++)
410 *a += num_consts + num_operations;
411 for (int i = 0; i < slp->num_operations; i++)
412 // shift by the size of "operations" part of this->program
413 res->node_index.push_back(slp->node_index[i] + program->len - SLP_HEADER_LEN -
414 num_outputs - 1);
415
416 res->program->array[0] = res->num_consts =
417 num_consts + slp->num_consts;
418
419 // make nodes: [constants, inputs, operations]
420 make_nodes(res->nodes,
421 res->num_consts + res->num_inputs + res->num_operations);
422 // memcpy(res->nodes, nodes, num_consts*sizeof(element_type)); //!!! assume:
423 // appending constants
424 for (int i = 0; i < num_consts; i++) res->nodes[i] = nodes[i];
425 // memcpy(res->nodes+num_consts, slp->nodes,
426 // slp->num_consts*sizeof(element_type)); //!!! assume: appending constants
427 for (int i = 0; i < slp->num_consts; i++)
428 res->nodes[num_consts + i] = slp->nodes[i];
429 return res;
430}
431
432/* ref = reference to a node rel. n */
433template <class Field>
434int SLP<Field>::diffPartReference(int n, int ref, int v, gc_vector<int>& prog)
435{
436 if (ref < 0)
437 return diffNodeInput(n + ref, v, prog);
438 else if (ref < CONST_OFFSET)
439 { // an input
440 if (ref == v)
441 return ONE_CONST;
442 else
443 return ZERO_CONST;
444 }
445 else
446 return ZERO_CONST; // a constant
447}
448
449template <class Field>
451 int v,
452 gc_vector<int>& prog) // used by jacobian
453{
454 int i = node_index[n];
455 switch (prog[i])
456 {
457 /* case slpCOPY:
458 break;*/
459 case slpMULTIsum:
460 {
461 int n_summands = prog[(++i)++];
462 std::vector<int> part_pos(n_summands);
463 int c = 0; // count nonzeroes
464 int last_non_zero = ZERO_CONST;
465 for (int j = 0; j < n_summands; j++)
466 {
467 part_pos[j] = diffPartReference(n, prog[i++], v, prog);
468 if (part_pos[j] != ZERO_CONST)
469 {
470 c++;
471 last_non_zero = part_pos[j];
472 }
473 }
474 if (c == 0) return ZERO_CONST;
475 if (c == 1) return last_non_zero;
476 int cur_p = num_operations++;
477 node_index.push_back(prog.size());
478 prog.push_back(slpMULTIsum);
479 prog.push_back(c);
480 for (int j = 0; j < n_summands; j++)
481 {
482 if (part_pos[j] != ZERO_CONST)
483 prog.push_back(part_pos[j] -
484 cur_p); // relative position of the j-th part
485 }
486 return cur_p;
487 }
488 case slpPRODUCT:
489 {
490 int a = prog[(++i)++];
491 int b = prog[i++];
492 int da = diffPartReference(n, a, v, prog);
493 int db = diffPartReference(n, b, v, prog);
494 if (db == ZERO_CONST)
495 {
496 if (da == ZERO_CONST) return ZERO_CONST;
497 if (da == ONE_CONST)
498 {
499 if (b < 0) // if refers to operation node
500 return n + b;
501 else if (b >= CONST_OFFSET)
502 { // ... constant
503 int cur_p = num_operations++;
504 node_index.push_back(prog.size());
505 prog.push_back(slpCOPY); // is there better way?
506 prog.push_back(b);
507 return cur_p;
508 }
509 else
510 { // ... input
511 ERROR("input node not expected");
513 };
514 }
515 else
516 {
517 int cur_p = num_operations++;
518 node_index.push_back(prog.size());
519 prog.push_back(slpPRODUCT);
520 prog.push_back(da - cur_p);
521 if (b < 0) // if refers to an operation node
522 b = n + b - cur_p; // recalculate wrt cur_p
523 prog.push_back(b);
524 return cur_p;
525 }
526 }
527 else if (da == ZERO_CONST)
528 { // ... and db != 0
529 if (db == ONE_CONST)
530 {
531 if (a < 0) // if refers to an operation node
532 return n + a;
533 else if (a >= CONST_OFFSET)
534 { // ... constant
535 int cur_p = num_operations++;
536 node_index.push_back(prog.size());
537 prog.push_back(slpCOPY); // is there a better way ?
538 if (a < 0) // if refers to an operation node
539 a = n + a - cur_p; // recalculate wrt cur_p
540 prog.push_back(a);
541 return cur_p;
542 }
543 else
544 { // ... input
545 ERROR("input node not expected");
546 return ZERO_CONST;
547 };
549 else
550 { // db!=0 and db!=1
551 int cur_p = num_operations++;
552 node_index.push_back(prog.size());
553 prog.push_back(slpPRODUCT);
554 prog.push_back(db - cur_p);
555 if (a < 0) // if refers to an operation node
556 a = n + a - cur_p; // recalculate wrt cur_p
557 prog.push_back(a);
558 return cur_p;
559 }
560 }
561 else
562 { // da |=0 and db !=0
563 int part1 = ZERO_CONST;
564 int is_part1_created = (da != ONE_CONST);
565 if (is_part1_created)
566 {
567 int cur_p = num_operations++;
568 node_index.push_back(prog.size());
569 prog.push_back(slpPRODUCT);
570 prog.push_back(da - cur_p);
571 if (b < 0) // if refers to an operation node
572 b = n + b - cur_p; // recalculate wrt cur_p
573 prog.push_back(b);
574 part1 = cur_p;
575 }
576 int part2 = ZERO_CONST;
577 int is_part2_created = (db != ONE_CONST);
578 if (is_part2_created)
579 {
580 int cur_p = num_operations++;
581 node_index.push_back(prog.size());
582 prog.push_back(slpPRODUCT);
583 prog.push_back(db - cur_p);
584 if (a < 0) // if refers to an operation node
585 a = n + a - cur_p; // recalculate wrt cur_p
586 prog.push_back(a);
587 part2 = cur_p;
588 }
589 int cur_p = num_operations++;
590 node_index.push_back(prog.size());
591 prog.push_back(slpMULTIsum);
592 prog.push_back(2);
593 if (is_part1_created)
594 prog.push_back(part1 - cur_p);
595 else
596 prog.push_back((b < 0) ? b + n - cur_p : b);
597 if (is_part2_created)
598 prog.push_back(part2 - cur_p);
599 else
600 prog.push_back((a < 0) ? a + n - cur_p : a);
601 return cur_p;
602 }
603 }
604 default:
605 ERROR("unknown SLP operation");
606 printf("i = %d, a[i] = %d\n", i, prog[i]);
607 return 0;
608 }
609}
610
611template <class Field>
612SLP<Field> /* or null */* SLP<Field>::jacobian(bool makeHxH,
613 SLP<Field>*& slpHxH,
614 bool makeHxtH,
615 SLP<Field>*& slpHxtH)
616/* Produces a jacobian of the slp H: (i,j)-th output = dH_j/dx_i
617 Constructs also HxH and HxtH. */
618{
619 if (rows_out != 1)
620 {
621 ERROR("1-row slp expected");
622 return nullptr;
623 };
624
625 int num_outputs = rows_out * cols_out;
626 int* end_program = program->array + program->len - num_outputs;
627
628 SLP<Field>* res = new SLP<Field>;
629 res->C = C;
630 res->is_relative_position = true;
631 res->num_inputs = num_inputs;
633 res->rows_out = num_inputs;
634 res->cols_out = cols_out;
635
636 // gc_vector<element_type> consts; // !!! use to optimize constants
637 gc_vector<int> prog;
638 prog.reserve(program->len);
639 for (int i = SLP_HEADER_LEN;
640 i < program->len - num_outputs - 1 /*for slpEND*/;
641 i++)
642 prog.push_back(program->array[i]);
643 res->node_index = node_index;
644
645 std::vector<int> out_pos(res->rows_out *
646 res->cols_out); // records absolute position of output entries
647
648 for (int j = 0; j < num_outputs; j++)
649 for (int i = 0; i < num_inputs; i++)
650 out_pos[i * res->cols_out + j] =
651 res->diffNodeInput(end_program[j] - num_consts -
652 num_inputs /*position of j-th output in prog*/,
653 i,
654 prog); // uses res->num_operations
655 // make program
656 res->program = M2_makearrayint(SLP_HEADER_LEN + prog.size() + 1 +
657 res->rows_out * res->cols_out);
658 res->program->array[0] = res->num_consts =
659 num_consts + 1;
660 res->program->array[1] = res->num_inputs;
661 res->program->array[2] = res->rows_out;
662 res->program->array[3] = res->cols_out;
663 prog.push_back(slpEND);
664 for (int i = 0; i < num_inputs; i++)
665 for (int j = 0; j < num_outputs; j++)
666 {
667 int t = out_pos[i * res->cols_out + j];
668 prog.push_back((t == ZERO_CONST)
669 ? num_consts /*ref to ZERO*/
670 : t + res->num_consts +
671 num_inputs); // position of the output
672 }
673 memcpy(res->program->array + SLP_HEADER_LEN,
674 prog.data(),
675 sizeof(int) * prog.size());
676
677 // make nodes: [constants, inputs, operations]
678 make_nodes(res->nodes,
679 res->num_consts + res->num_inputs + res->num_operations);
680 // memcpy(res->nodes, nodes, num_consts*sizeof(element_type)); // old
681 // constants
682 for (int i = 0; i < num_consts; i++)
683 {
684 res->nodes[i] = nodes[i];
685 }
686
687 res->nodes[num_consts] = element_type(0, 0); // ... plus ZERO
688
689 if (makeHxH)
690 {
691 slpHxH = res->copy();
692 int* c = slpHxH->program->array + slpHxH->program->len - slpHxH->cols_out;
693 for (int j = 0; j < num_outputs; j++, c++)
694 *c = end_program[j] - num_consts + res->num_consts;
695 }
696 if (makeHxtH)
697 {
698 slpHxtH = res->copy();
699 slpHxtH->rows_out++;
700 // how to kill M2_arrayint ???
701 slpHxtH->program = M2_makearrayint(slpHxtH->program->len + cols_out);
702 memcpy(slpHxtH->program->array,
703 res->program->array,
704 sizeof(int) * res->program->len);
705 int* c = slpHxtH->program->array + res->program->len;
706 for (int j = 0; j < num_outputs; j++, c++)
707 *c = end_program[j] - num_consts + res->num_consts;
708 }
709 return res;
710}
711
712template <typename Field>
713void SLP<Field>::evaluate(int n, const element_type* values, element_type* ret)
714{
715 if (n != num_inputs) ERROR("wrong number of inputs");
716
717 element_type* out = nullptr; // used by compiledSLP
718 int out_entries_shift = 0; // position of "out matrix"
719
720 int cur_node = num_consts;
721 int i;
722 copy_complex_array<Field>(num_inputs, values, nodes + cur_node);
723 cur_node += num_inputs;
724
725 clock_t start_t = clock(); // clock execution time
726
727 switch (program->array[4])
728 {
729 /* obsolete !!!
730 case slpPREDICTOR:
731 out = nodes+num_consts+num_inputs;
732 predictor();
733 break;
734 case slpCORRECTOR:
735 out = nodes+num_consts+num_inputs;
736 corrector();
737 break;
738 */
739 case slpCOMPILED:
740 // evaluation via dynamically linked function
741 // input: nodes (shifted by number of consts)
742 // output: out
743 out = nodes + num_consts + num_inputs;
745 break;
746 default: // evaluation by interpretation
748 i = SLP_HEADER_LEN;
749 for (; program->array[i] != slpEND; cur_node++)
750 {
751 switch (program->array[i])
752 {
753 case slpCOPY:
754 nodes[cur_node] = nodes[program->array[(++i)++]];
755 break;
756 case slpMULTIsum:
757 {
758 int n_summands = program->array[i + 1];
759 nodes[cur_node] =
760 (n_summands > 0)
761 ? // create a temp var?
762 nodes[program->array[i + 2]]
763 : element_type(0, 0); // zero if empty sum
764 for (int j = 1; j < n_summands; j++)
765 nodes[cur_node] =
766 nodes[cur_node] + nodes[program->array[i + j + 2]];
767 i += n_summands + 2;
768 }
769 break;
770 case slpPRODUCT:
771 nodes[cur_node] = nodes[program->array[i + 1]] *
772 nodes[program->array[i + 2]];
773 i += 3;
774 break;
775 default:
776 ERROR("unknown SLP operation");
777 return;
778 }
779 }
780 out_entries_shift = i + 1;
781 // end: evaluation by interpretation
782 }
783
784 eval_time += clock() - start_t;
785 n_calls++;
786
787 switch (program->array[4])
788 {
789 case slpPREDICTOR:
790 case slpCOMPILED:
791 // dynamically linked
793 break;
794 default:
795 // interpretation
796 element_type* c = ret;
797 for (i = 0; i < rows_out; i++)
798 for (int j = 0; j < cols_out; j++, c++)
799 *c = nodes[program->array[i * cols_out + j + out_entries_shift]];
800 // end: interpretation
801 }
802}
803
804template <class Field>
806{
807 element_type* out = nullptr; // used by compiledSLP
808 int out_entries_shift = 0; // position of "out matrix" in slp->program
809
810 int cur_node = num_consts;
811 int i;
812 if (values->n_cols() != num_inputs)
813 ERROR("different number of inputs expected");
814 for (i = 0; i < num_inputs; i++, cur_node++)
815 nodes[cur_node] = element_type(toBigComplex(C, values->elem(0, i)));
816
817 clock_t start_t = clock(); // clock execution time
818
819 switch (program->array[4])
820 {
821 case slpCOMPILED:
822 // evaluation via dynamically linked function
823 // input: nodes (shifted by number of consts)
824 // output: out
825 out = nodes + num_consts + num_inputs;
827 break;
828 default: // evaluation by interpretation
830 i = SLP_HEADER_LEN;
831 for (; program->array[i] != slpEND; cur_node++)
832 {
833 switch (program->array[i])
834 {
835 case slpCOPY:
836 nodes[cur_node] = nodes[program->array[(++i)++]];
837 break;
838 case slpMULTIsum:
839 {
840 int n_summands = program->array[i + 1];
841 nodes[cur_node] =
842 (n_summands > 0)
843 ? // create a temp var?
844 nodes[program->array[i + 2]]
845 : element_type(0, 0); // zero if empty sum
846 for (int j = 1; j < n_summands; j++)
847 nodes[cur_node] =
848 nodes[cur_node] + nodes[program->array[i + j + 2]];
849 i += n_summands + 2;
850 }
851 break;
852 case slpPRODUCT:
853 nodes[cur_node] = nodes[program->array[i + 1]] *
854 nodes[program->array[i + 2]];
855 i += 3;
856 break;
857 default:
858 ERROR("unknown SLP operation");
859 return nullptr;
860 }
861 }
862 out_entries_shift = i + 1;
863 // end: evaluation by interpretation
864 }
865
866 eval_time += clock() - start_t;
867 n_calls++;
868
869 const CCC* R = cast_to_CCC(values->get_ring());
870 // CCC* R = CCC::create(53); //values->get_ring();
873 MatrixConstructor mat(T, S);
874 mpfr_t re, im;
875 mpfr_init(re);
876 mpfr_init(im);
877 switch (program->array[4])
878 {
879 case slpPREDICTOR:
880 case slpCORRECTOR:
881 case slpCOMPILED:
882 {
883 // printf("predictor output: %d by %d\n", rows_out, cols_out);
884 element_type* c = out;
885 for (i = 0; i < rows_out; i++)
886 for (int j = 0; j < cols_out; j++, c++)
887 {
888 // printf("%lf %lf \n", c->getreal(), c->getimaginary());
889 ring_elem e = from_doubles(R, c->getreal(), c->getimaginary());
890
891 mat.set_entry(i, j, e);
892 }
893 }
894 break;
895 default: // interpretation
896 for (i = 0; i < rows_out; i++)
897 for (int j = 0; j < cols_out; j++)
898 {
899 element_type c =
900 nodes[program->array[i * cols_out + j + out_entries_shift]];
901
902 ring_elem e = from_doubles(R, c.getreal(), c.getimaginary());
903
904 mat.set_entry(i, j, e);
905 }
906 // end: interpretation
907 }
908 mpfr_clear(re);
909 mpfr_clear(im);
910 return mat.to_matrix();
911}
912
913template <class Field>
915{
917 is_relative_position = false;
918 else
919 return;
920
921 int cur_node = num_consts + num_inputs;
922 int* a = program->array;
923 for (int i = SLP_HEADER_LEN; a[i] != slpEND; cur_node++)
924 {
925 switch (a[i])
926 {
927 case slpCOPY:
928 relative_to_absolute(a[(++i)++], cur_node);
929 break;
930 case slpMULTIsum:
931 {
932 int n_summands = a[(++i)++];
933 for (int j = 0; j < n_summands; j++)
934 relative_to_absolute(a[i++], cur_node);
935 }
936 break;
937 case slpPRODUCT:
938 relative_to_absolute(a[(++i)++], cur_node);
939 relative_to_absolute(a[i++], cur_node);
940 break;
941 default:
942 ERROR("unknown SLP operation");
943 printf("i = %d, a[i] = %d\n", i, a[i]);
944 return;
945 }
946 }
947}
948
949template <class Field>
951{
952 o << "Called " << n_calls
953 << " times, total evaluation time = " << (eval_time / CLOCKS_PER_SEC) << "."
954 << (eval_time % CLOCKS_PER_SEC) << " sec" << newline;
955}
956
957template <class Field>
959{
961 {
962 if (program->array[4] == slpCOMPILED)
963 {
964 o << "(SLP is precompiled) " << newline;
965 }
966 if (program->array[4] == slpPREDICTOR ||
967 program->array[4] == slpCORRECTOR)
968 {
969 return;
970 }
971 }
972
973 o << "CONSTANT (count = " << num_consts;
974 o << ") nodes:\n";
975 int cur_node = 0;
976 int i, j;
977 for (i = 0; i < num_consts; i++, cur_node++)
978 {
979 char s[100];
980 nodes[cur_node].snprint(s, 100);
981 o << s << ", ";
982 }
983 o << newline;
984 o << "INPUT (count = " << num_inputs << ") nodes:\n";
985 for (i = 0; i < num_inputs; i++, cur_node++) o << cur_node << " ";
986 o << newline;
987
988 switch (program->array[SLP_HEADER_LEN])
989 {
990 case slpPREDICTOR:
991 o << "Predictor: type " << program->array[5] << newline;
992 o << "SLPs: " << program->array[6] << "," << program->array[7] << ","
993 << program->array[8] << newline;
994 break;
995 default:
996 for (i = SLP_HEADER_LEN; program->array[i] != slpEND; cur_node++)
997 {
998 o << cur_node << " => ";
999 switch (program->array[i])
1000 {
1001 case slpCOPY:
1002 o << "copy " << program->array[(++i)++];
1003 break;
1004 case slpMULTIsum:
1005 {
1006 o << "sum";
1007 int n_summands = program->array[i + 1];
1008 for (j = 0; j < n_summands; j++)
1009 o << " " << program->array[i + j + 2];
1010 i += n_summands + 2;
1011 }
1012 break;
1013 case slpPRODUCT:
1014 o << "product " << program->array[i + 1] << " "
1015 << program->array[i + 2];
1016 i += 3;
1017 break;
1018 default:
1019 o << "BLA i=" << i++;
1020 }
1021 o << newline;
1022 }
1023 int out_shift = i + 1;
1024 o << "OUTPUT (" << rows_out << "x" << cols_out << ") nodes:\n";
1025 for (i = 0; i < rows_out; i++)
1026 {
1027 for (j = 0; j < cols_out; j++)
1028 o << program->array[out_shift + i * cols_out + j] << " ";
1029 o << newline;
1030 }
1031 }
1032}
1033// end SLP
1034
1035/* obsolete !!!
1036// template <class Field>
1037// void SLP<Field>::predictor()
1038// {
1039// int n = num_inputs - 2; // n = size of vectors and matrices
1040// const complex* x0t0 = nodes+num_consts;
1041// const complex* dt = x0t0+n+1;
1042// complex* dx = nodes+num_consts+num_inputs;
1043// int predictor_type = program->array[5];
1044// SLP<Field>* Hx = catalog[program->array[6]];
1045// SLP<Field>* Ht = catalog[program->array[7]];
1046// //SLP* H = catalog[program->array[8]];
1047
1048// complex* RHS = newarray_atomic(complex, n);
1049// complex* LHS = newarray_atomic(complex, n*n);
1050// switch(predictor_type) {
1051// case TANGENT: {
1052// Ht->evaluate(n+1,x0t0, RHS);
1053// multiply_complex_array_scalar(n,RHS,-*dt);
1054// Hx->evaluate(n+1,x0t0, LHS);
1055// solve_via_lapack(n,LHS,1,RHS,dx);
1056// } break;
1057// case RUNGE_KUTTA: {
1058// complex one_half(0.5,0);
1059
1060// complex* xt = newarray_atomic(complex,n+1);
1061// copy_complex_array<ComplexField>(n+1,x0t0,xt);
1062// complex* dx1 = newarray_atomic(complex,n);
1063// Ht->evaluate(n+1, xt, RHS);
1064// negate_complex_array(n,RHS);
1065// Hx->evaluate(n+1, xt, LHS);
1066// solve_via_lapack(n,LHS,1,RHS,dx1);
1067
1068// complex* dx2 = newarray_atomic(complex,n);
1069// multiply_complex_array_scalar(n,dx1,one_half*(*dt));
1070// add_to_complex_array(n,xt,dx1); // x0+.5dx1*dt
1071// xt[n] += one_half*(*dt); // t0+.5dt
1072// Ht->evaluate(n+1, xt, RHS);
1073// negate_complex_array(n,RHS);
1074// Hx->evaluate(n+1, xt, LHS);
1075// solve_via_lapack(n,LHS,1,RHS,dx2);
1076
1077// complex* dx3 = newarray_atomic(complex,n);
1078// multiply_complex_array_scalar(n,dx2,one_half*(*dt));
1079// copy_complex_array<ComplexField>(n,x0t0,xt); // spare t
1080// add_to_complex_array(n,xt,dx2); // x0+.5dx2*dt
1081// // xt[n] += one_half*(*dt); // t0+.5dt (SAME)
1082// Ht->evaluate(n+1, xt, RHS);
1083// negate_complex_array(n,RHS);
1084// Hx->evaluate(n+1, xt, LHS);
1085// solve_via_lapack(n,LHS,1,RHS,dx3);
1086
1087// complex* dx4 = newarray_atomic(complex,n);
1088// multiply_complex_array_scalar(n,dx3,*dt);
1089// copy_complex_array<ComplexField>(n+1,x0t0,xt);
1090// add_to_complex_array(n,xt,dx3); // x0+dx3*dt
1091// xt[n] += *dt; // t0+dt
1092// Ht->evaluate(n+1, xt, RHS);
1093// negate_complex_array(n,RHS);
1094// Hx->evaluate(n+1, xt, LHS);
1095// solve_via_lapack(n,LHS,1,RHS,dx4);
1096
1097// // "dx1" = .5*dx1*dt, "dx2" = .5*dx2*dt, "dx3" = dx3*dt
1098// multiply_complex_array_scalar(n,dx4,*dt);
1099// multiply_complex_array_scalar(n,dx1,2);
1100// multiply_complex_array_scalar(n,dx2,4);
1101// multiply_complex_array_scalar(n,dx3,2);
1102// add_to_complex_array(n,dx4,dx1);
1103// add_to_complex_array(n,dx4,dx2);
1104// add_to_complex_array(n,dx4,dx3);
1105// multiply_complex_array_scalar(n,dx4,1.0/6);
1106// copy_complex_array<ComplexField>(n,dx4,dx);
1107// freemem(dx1);
1108// freemem(dx2);
1109// freemem(dx3);
1110// freemem(dx4);
1111// } break;
1112// default: ERROR("unknown predictor");
1113// };
1114// freemem(LHS);
1115// freemem(RHS);
1116// }
1117
1118// template <class Field>
1119// void SLP<Field>::corrector()
1120// {
1121// int n = num_inputs - 2; // n = size of vectors and matrices
1122// double epsilon2 = 1e-10; // square of the tolerance
1123// double theSmallestNumber = 1e-12;
1124// double minStep = 1e-6;
1125
1126// complex* x0t = nodes+num_consts;
1127// complex* t = x0t+n;
1128// complex* dt = t+1;
1129// SLP<Field>* Hx = catalog[program->array[5]];
1130// SLP<Field>* H = catalog[program->array[6]];
1131// int maxCorSteps = program->array[7];
1132// if (1-t->getreal()<theSmallestNumber && dt->getreal()<=minStep)
1133// maxCorSteps = program->array[8]; // finalMaxCorSteps
1134
1135// complex* x1 = nodes+num_consts+num_inputs; // output
1136// complex* dx = x1+n; // on return: estimate of the error
1137
1138// complex* x1t = newarray(complex, n+1);
1139// copy_complex_array<ComplexField>(n+1, x0t, x1t);
1140// complex* RHS = newarray_atomic(complex, n);
1141// complex* LHS = newarray_atomic(complex, n*n);
1142// int i=0; // number of steps
1143// do {
1144// i++;
1145// H->evaluate(n+1,x1t, RHS);
1146// negate_complex_array(n,RHS);
1147// Hx->evaluate(n+1,x1t, LHS);
1148// solve_via_lapack(n,LHS,1,RHS,dx);
1149// add_to_complex_array(n,x1t,dx);
1150// } while (norm2_complex_array(n,dx)>epsilon2*norm2_complex_array(n,x1t) and
1151i<maxCorSteps);
1152
1153// copy_complex_array<ComplexField>(n,x1t,x1);
1154
1155// freemem(x1t);
1156// freemem(LHS);
1157// freemem(RHS);
1158// }
1159*/
1160
1161// BEGIN lapack-based routines
1162
1163// lapack solve routine (direct call)
1164// matrix A is transposed
1165bool solve_via_lapack(int size,
1166 complex* A, // size-by-size matrix of complex #s
1167 int bsize,
1168 complex* b, // bsize-by-size RHS of Ax=b
1169 complex* x // solution
1170 )
1171{
1172 bool ret = true;
1173 int info;
1174
1175 int* permutation = newarray_atomic(int, size);
1176 complex* At = newarray_atomic(complex, size * size);
1177 int i, j;
1178 for (i = 0; i < size; i++)
1179 for (j = 0; j < size; j++) // transpose the matrix: lapack solves A^t x = b
1180 *(At + i * size + j) = *(A + j * size + i);
1181 double* copyA = (double*)At;
1183 double* copyb = (double*)x; // result is stored in copyb
1184
1185 /*
1186 printf("-----------(solve)-----------------------------------\ncopyA:\n");
1187 for (i=0; i<size*size; i++)
1188 printf("(%lf %lf) ", *(copyA+2*i), *(copyA+2*i+1));
1189 printf("\nb:\n");
1190 for (i=0; i<size; i++)
1191 printf("(%lf %lf) ", *(copyb+2*i), *(copyb+2*i+1));
1192 */
1193 zgesv_(&size, &bsize, copyA, &size, permutation, copyb, &size, &info);
1194 /*
1195 printf("\nx = b:\n");
1196 for (i=0; i<size; i++)
1197 printf("(%lf %lf) ", *(copyb+2*i), *(copyb+2*i+1));
1198 printf("\n");
1199 */
1200 if (info > 0)
1201 {
1202 ERROR("according to zgesv, matrix is singular");
1203 ret = false;
1204 }
1205 else if (info < 0)
1206 {
1207 ERROR("argument passed to zgesv had an illegal value");
1208 ret = false;
1209 }
1210
1211 freemem(permutation);
1212 freemem(At);
1213
1214 return ret;
1215}
1216
1217// lapack solve routine (direct call)
1219 int size,
1220 complex* A, // size-by-size matrix of complex #s
1221 int bsize,
1222 complex* b, // bsize-by-size RHS of Ax=b
1223 complex* x // solution
1224 )
1225{
1226 bool ret = true;
1227 int info;
1228
1229 int* permutation = newarray_atomic(int, size);
1230 // int i,j;
1231 double* copyA = (double*)A;
1233 double* copyb = (double*)x; // result is stored in copyb
1234
1235 /*
1236 printf("-----------(solve)-----------------------------------\ncopyA:\n");
1237 for (int i=0; i<size*size; i++)
1238 printf("(%lf %lf) ", *(copyA+2*i), *(copyA+2*i+1));
1239 printf("\nb:\n");
1240 for (int i=0; i<size; i++)
1241 printf("(%lf %lf) ", *(copyb+2*i), *(copyb+2*i+1));
1242 */
1243
1244 zgesv_(&size, &bsize, copyA, &size, permutation, copyb, &size, &info);
1245 /*
1246 printf("\nx = b:\n");
1247 for (i=0; i<size; i++)
1248 printf("(%lf %lf) ", *(copyb+2*i), *(copyb+2*i+1));
1249 printf("\n");
1250 */
1251 if (info > 0)
1252 {
1253 // ERROR("according to zgesv, matrix is singular");
1254 ret = false;
1255 }
1256 else if (info < 0)
1257 {
1258 ERROR("argument passed to zgesv had an illegal value");
1259 ret = false;
1260 }
1261
1262 freemem(permutation);
1263
1264 return ret;
1265}
1266
1267// In: A, a square matrix of size "size"
1268// Out: true if success, cond = condition number of A
1269bool cond_number_via_svd(int size, complex* A, double& cond)
1270{
1271 bool ret = true;
1272 char doit = 'A'; // other options are 'S' and 'O' for singular vectors only
1273 int rows = size;
1274 int cols = size;
1275 int info;
1276 int min = (rows <= cols) ? rows : cols;
1277
1278 if (min == 0)
1279 {
1280 ERROR("expected a matrix with positive dimensions");
1281 return false;
1282 }
1283
1284 int max = (rows >= cols) ? rows : cols;
1285 int wsize = 4 * min + 2 * max;
1286 double* workspace = newarray_atomic(double, 2 * wsize);
1287 double* rwork = newarray_atomic(double, 5 * max);
1288
1289 double* copyA = (double*)A;
1290 double* u = newarray_atomic(double, 2 * rows * rows);
1291 double* vt = newarray_atomic(double, 2 * cols * cols);
1292 double* sigma = newarray_atomic(double, 2 * min);
1293
1294 zgesvd_(&doit,
1295 &doit,
1296 &rows,
1297 &cols,
1298 copyA,
1299 &rows,
1300 sigma,
1301 u,
1302 &rows,
1303 vt,
1304 &cols,
1305 workspace,
1306 &wsize,
1307 rwork,
1308 &info);
1309
1310 if (info < 0)
1311 {
1312 ERROR("argument passed to zgesvd had an illegal value");
1313 ret = false;
1314 }
1315 else if (info > 0)
1316 {
1317 ERROR("zgesvd did not converge");
1318 ret = false;
1319 }
1320 else
1321 {
1322 cond = sigma[0] / sigma[size - 1];
1323 // print_complex_matrix(size,copyA);
1324 // printf("(s_large=%lf, s_small=%lf)\n", sigma[0], sigma[size-1]);
1325 }
1326
1327 freemem(workspace);
1328 freemem(rwork);
1329 // freemem(copyA);
1330 freemem(u);
1331 freemem(vt);
1332 freemem(sigma);
1333
1334 return ret;
1335}
1336
1337// In: A, a square matrix of size "size"
1338// Out: true if success, "norm" = operator norm of A^{-1}
1339bool norm_of_inverse_via_svd(int size, complex* A, double& norm)
1340{
1341 bool ret = true;
1342 char doit = 'A'; // other options are 'S' and 'O' for singular vectors only
1343 int rows = size;
1344 int cols = size;
1345 int info;
1346 int min = (rows <= cols) ? rows : cols;
1347
1348 if (min == 0)
1349 {
1350 ERROR("expected a matrix with positive dimensions");
1351 return false;
1352 }
1353
1354 int max = (rows >= cols) ? rows : cols;
1355 int wsize = 4 * min + 2 * max;
1356 double* workspace = newarray_atomic(double, 2 * wsize);
1357 double* rwork = newarray_atomic(double, 5 * max);
1358
1359 double* copyA = (double*)A;
1360 double* u = newarray_atomic(double, 2 * rows * rows);
1361 double* vt = newarray_atomic(double, 2 * cols * cols);
1362 double* sigma = newarray_atomic(double, 2 * min);
1363
1364 zgesvd_(&doit,
1365 &doit,
1366 &rows,
1367 &cols,
1368 copyA,
1369 &rows,
1370 sigma,
1371 u,
1372 &rows,
1373 vt,
1374 &cols,
1375 workspace,
1376 &wsize,
1377 rwork,
1378 &info);
1379
1380 if (info < 0)
1381 {
1382 ERROR("argument passed to zgesvd had an illegal value");
1383 ret = false;
1384 }
1385 else if (info > 0)
1386 {
1387 ERROR("zgesvd did not converge");
1388 ret = false;
1389 }
1390 else
1391 {
1392 if (sigma[size - 1] == 0)
1393 {
1394 ERROR("invertible matrix expected");
1395 ret = false;
1396 }
1397 norm = 1 / sigma[size - 1];
1398 }
1399
1400 freemem(workspace);
1401 freemem(rwork);
1402 // freemem(copyA);
1403 freemem(u);
1404 freemem(vt);
1405 freemem(sigma);
1406
1407 return ret;
1408}
1409
1410// END lapack-based routines
1411
1414
1417
1419{
1420 raw_solutions = nullptr;
1421 solutions = nullptr;
1422 DMforPN = nullptr;
1423}
1424
1426{
1427 for (int i = 0; i < n_sols; i++) raw_solutions[i].release();
1430}
1431
1432// creates a PathTracker object (case: is_projective), builds slps for predictor
1433// and corrector given start/target systems
1434// input: two (1-row) matrices of polynomials
1435// out: PathTracker*
1437 const Matrix* T,
1439{
1440 if (S->n_rows() != 1 || T->n_rows() != 1)
1441 {
1442 ERROR("1-row matrices expected");
1443 return nullptr;
1444 };
1445 PathTracker* p = new PathTracker;
1446 const PolyRing* R = p->homotopy_R = S->get_ring()->cast_to_PolyRing();
1447 if (R == nullptr)
1448 {
1449 ERROR("polynomial ring expected");
1450 return nullptr;
1451 }
1452 p->C = cast_to_CCC(R->getCoefficients());
1453 // const Ring* K = R->getCoefficients();
1454 // p->C = cast_to_CCC(K); // cast to ConcreteRing<ARingCCC> for now
1455 if (!p->C)
1456 {
1457 ERROR("complex coefficients expected");
1458 return nullptr;
1459 }
1460 p->productST = mpfr_get_d(productST, MPFR_RNDN);
1461 // p->bigT = asin(sqrt(1-p->productST*p->productST));
1462 // const double pi = 3.141592653589793238462643383279502;
1463 // if (p->productST < 0)
1464 // p->bigT = pi - p->bigT;
1465 p->bigT = acos(p->productST);
1466
1467 int n = S->n_cols() + 1; // equals the number of variables
1468 p->maxDegreeTo3halves = 0;
1469 p->DMforPN = newarray_atomic(double, n);
1470 p->DMforPN[n - 1] = 1;
1471 p->S = S;
1472 p->slpS = nullptr;
1473 for (int i = 0; i < n - 1; i++)
1474 {
1475 int d = degree_ring_elem(R, S->elem(0, i));
1476 if (d > p->maxDegreeTo3halves) p->maxDegreeTo3halves = d;
1477 p->DMforPN[i] = 1 / sqrt(d);
1478 StraightLineProgram* slp = StraightLineProgram::make(R, S->elem(0, i));
1479 if (p->slpS == nullptr)
1480 p->slpS = slp;
1481 else
1482 {
1483 StraightLineProgram* t = p->slpS->concatenate(slp);
1484 delete slp;
1485 delete p->slpS;
1486 p->slpS = t;
1487 }
1488 }
1489 p->slpSx = p->slpS->jacobian(false, p->slpHxH /*not used*/, true, p->slpSxS);
1490 p->maxDegreeTo3halves = p->maxDegreeTo3halves * sqrt(p->maxDegreeTo3halves);
1491
1492 p->T = T;
1493 p->slpT = nullptr;
1494 for (int i = 0; i < T->n_cols(); i++)
1495 {
1496 StraightLineProgram* slp = StraightLineProgram::make(R, T->elem(0, i));
1497 if (p->slpT == nullptr)
1498 p->slpT = slp;
1499 else
1500 {
1501 StraightLineProgram* t = p->slpT->concatenate(slp);
1502 delete slp;
1503 delete p->slpT;
1504 p->slpT = t;
1505 }
1506 }
1507 p->slpTx = p->slpT->jacobian(false, p->slpHxH /*not used*/, true, p->slpTxT);
1508
1509 return p;
1510}
1511
1512// creates a PathTracker object, builds the homotopy, slps for predictor and
1513// corrector given a target system
1514// input: a (1-row) matrix of polynomials
1515// out: PathTracker*
1516PathTracker /* or null */* PathTracker::make(const Matrix* HH)
1517{
1518 if (HH->n_rows() != 1)
1519 {
1520 ERROR("1-row matrix expected");
1521 return nullptr;
1522 };
1523
1524 PathTracker* p = new PathTracker;
1525 const PolyRing* R = p->homotopy_R = HH->get_ring()->cast_to_PolyRing();
1526 if (R == nullptr)
1527 {
1528 ERROR("polynomial ring expected");
1529 return nullptr;
1530 }
1531 const Ring* K = R->getCoefficients();
1532 p->C = cast_to_CCC(K); // cast to ConcreteRing<ARingCCC> for now
1533 if (!p->C)
1534 {
1535 ERROR("complex coefficients expected");
1536 return nullptr;
1537 }
1538
1539 p->H = HH;
1540 p->slpH = nullptr;
1541 for (int i = 0; i < HH->n_cols(); i++)
1542 {
1544 if (p->slpH == nullptr)
1545 p->slpH = slp;
1546 else
1547 {
1548 StraightLineProgram* t = p->slpH->concatenate(slp);
1549 delete slp;
1550 delete p->slpH;
1551 p->slpH = t;
1552 }
1553 }
1554 p->slpHxt = p->slpH->jacobian(true, p->slpHxH, true, p->slpHxtH);
1555 return p;
1556}
1557
1558// for SLPs constructed on the top level
1560 StraightLineProgram* slp_corr)
1561{
1562 PathTracker* p = new PathTracker;
1563 p->H = nullptr;
1564 p->slpH = nullptr;
1565 p->slpHxt = p->slpHxtH = slp_pred;
1566 p->slpHxH = slp_corr;
1567 p->C = nullptr;
1568 return p;
1569}
1570
1596
1597void rawLaunchPT(PathTracker* PT, const Matrix* start_sols)
1598{
1599 PT->track(start_sols);
1600}
1601
1602const Matrix /* or null */* rawGetSolutionPT(PathTracker* PT, int solN)
1603{
1604 return PT->getSolution(solN);
1605}
1606
1607const Matrix /* or null */* rawGetAllSolutionsPT(PathTracker* PT)
1608{
1609 return PT->getAllSolutions();
1610}
1611
1613{
1614 return PT->getSolutionStatus(solN);
1615}
1616
1618{
1619 return PT->getSolutionSteps(solN);
1620}
1621
1623{
1624 return PT->getSolutionLastT(solN);
1625}
1626
1628{
1629 return PT->getSolutionRcond(solN);
1630}
1631
1632const Matrix /* or null */* rawRefinePT(PathTracker* PT,
1633 const Matrix* sols,
1634 gmp_RR tolerance,
1635 int max_corr_steps_refine)
1636{
1637 return PT->refine(sols, tolerance, max_corr_steps_refine);
1638}
1639
1640int PathTracker::track(const Matrix* start_sols)
1641{
1642 double the_smallest_number = 1e-13;
1643 double epsilon2 = mpfr_get_d(epsilon, MPFR_RNDN);
1644 epsilon2 *= epsilon2; // epsilon^2
1645 double t_step = mpfr_get_d(init_dt, MPFR_RNDN); // initial step
1646 double dt_min_dbl = mpfr_get_d(min_dt, MPFR_RNDN);
1647 double dt_increase_factor_dbl = mpfr_get_d(dt_increase_factor, MPFR_RNDN);
1648 double dt_decrease_factor_dbl = mpfr_get_d(dt_decrease_factor, MPFR_RNDN);
1649 double infinity_threshold2 = mpfr_get_d(infinity_threshold, MPFR_RNDN);
1650 infinity_threshold2 *= infinity_threshold2;
1651 double end_zone_factor_dbl = mpfr_get_d(end_zone_factor, MPFR_RNDN);
1652
1653 if (C == nullptr)
1654 C = cast_to_CCC(
1655 start_sols->get_ring()); // fixes the problem for PrecookedSLPs
1656
1657 int n = n_coords = start_sols->n_cols();
1658 n_sols = start_sols->n_rows();
1659
1661 printf(
1662 "epsilon2 = %e, t_step = %lf, dt_min_dbl = %lf, dt_increase_factor_dbl "
1663 "= %lf, dt_decrease_factor_dbl = %lf\n",
1664 epsilon2,
1665 t_step,
1666 dt_min_dbl,
1667 dt_increase_factor_dbl,
1668 dt_decrease_factor_dbl);
1669
1670 // memory distribution for arrays
1671 complex* s_sols = newarray_atomic(complex, n * n_sols);
1673 complex* x0t0 = newarray_atomic(complex, n + 1);
1674 complex* x0 = x0t0;
1675 complex* t0 = x0t0 + n;
1676 complex* x1t1 = newarray_atomic(complex, n + 1);
1677 // complex* x1 = x1t1;
1678 // complex* t1 = x1t1+n;
1679 complex* dxdt = newarray_atomic(complex, n + 1);
1680 complex* dx = dxdt;
1681 complex* dt = dxdt + n;
1682 complex* Hxt = newarray_atomic(complex, (n + 1) * n);
1683 complex* HxtH = newarray_atomic(complex, (n + 2) * n);
1684 complex* HxH = newarray_atomic(complex, (n + 1) * n);
1685 complex *LHS, *RHS;
1686 complex one_half(0.5, 0);
1687 complex* xt = newarray_atomic(complex, n + 1);
1688 complex* dx1 = newarray_atomic(complex, n);
1689 complex* dx2 = newarray_atomic(complex, n);
1690 complex* dx3 = newarray_atomic(complex, n);
1691 complex* dx4 = newarray_atomic(complex, n);
1692
1693 // read solutions: rows are solutions
1694 int i, j;
1695 complex* c = s_sols;
1696 for (i = 0; i < n_sols; i++)
1697 for (j = 0; j < n; j++, c++)
1698 *c = complex(toBigComplex(C, start_sols->elem(i, j)));
1699
1700 Solution* t_s = raw_solutions; // current target solution
1701 complex* s_s = s_sols; // current start solution
1702
1703 for (int sol_n = 0; sol_n < n_sols; sol_n++, s_s += n, t_s++)
1704 {
1705 t_s->make(n, s_s); // cook a Solution
1706 t_s->status = PROCESSING;
1707 bool end_zone = false;
1708 double tol2 =
1709 epsilon2; // current tolerance squared, will change in end zone
1711 *t0 = complex(0, 0);
1712
1713 *dt = complex(t_step);
1714 int predictor_successes = 0;
1715 int count = 0; // number of steps
1716 while (t_s->status == PROCESSING &&
1717 1 - t0->getreal() > the_smallest_number)
1718 {
1719 if (1 - t0->getreal() <= end_zone_factor_dbl + the_smallest_number &&
1720 !end_zone)
1721 {
1722 end_zone = true;
1723 // to do: see if this path coincides with any other path on entry
1724 // to the end zone
1725 }
1726 if (end_zone)
1727 {
1728 if (dt->getreal() > 1 - t0->getreal())
1729 *dt = complex(1 - t0->getreal());
1730 }
1731 else
1732 {
1733 if (dt->getreal() > 1 - end_zone_factor_dbl - t0->getreal())
1734 *dt = complex(1 - end_zone_factor_dbl - t0->getreal());
1735 }
1736
1737 bool LAPACK_success = false;
1738
1739 if (is_projective) // normalize
1741 n, x0, 1 / sqrt(norm2_complex_array<ComplexField>(n, x0)));
1742
1743 // PREDICTOR in: x0t0,dt,pred_type
1744 // out: dx
1745 switch (pred_type)
1746 {
1747 case TANGENT:
1748 {
1749 evaluate_slpHxt(n, x0t0, Hxt);
1750 LHS = Hxt;
1751 RHS = Hxt + n * n;
1754 n, LHS, 1, RHS, dx);
1755 }
1756 break;
1757 case EULER:
1758 {
1759 evaluate_slpHxtH(n, x0t0, HxtH); // for Euler "H" is attached
1760 LHS = HxtH;
1761 RHS = HxtH + n * (n + 1); // H
1762 complex* Ht = RHS - n;
1767 n, LHS, 1, RHS, dx);
1768 }
1769 break;
1770 case RUNGE_KUTTA:
1771 {
1772 copy_complex_array<ComplexField>(n + 1, x0t0, xt);
1773
1774 // dx1
1775 evaluate_slpHxt(n, xt, Hxt);
1776 LHS = Hxt;
1777 RHS = Hxt + n * n;
1778 //
1780 solve_via_lapack_without_transposition(n, LHS, 1, RHS, dx1);
1781
1782 // dx2
1784 n, dx1, one_half * (*dt));
1786 n, xt, dx1); // x0+.5dx1*dt
1787 xt[n] += one_half * (*dt); // t0+.5dt
1788 //
1789 evaluate_slpHxt(n, xt, Hxt);
1790 LHS = Hxt;
1791 RHS = Hxt + n * n;
1792 //
1795 n, LHS, 1, RHS, dx2);
1796
1797 // dx3
1799 n, dx2, one_half * (*dt));
1800 copy_complex_array<ComplexField>(n, x0t0, xt); // spare t
1802 n, xt, dx2); // x0+.5dx2*dt
1803 // xt[n] += one_half*(*dt); // t0+.5dt (SAME)
1804 //
1805 evaluate_slpHxt(n, xt, Hxt);
1806 LHS = Hxt;
1807 RHS = Hxt + n * n;
1808 //
1810 LAPACK_success =
1812 n, LHS, 1, RHS, dx3);
1813
1814 // dx4
1816 copy_complex_array<ComplexField>(n + 1, x0t0, xt);
1817 add_to_complex_array<ComplexField>(n, xt, dx3); // x0+dx3*dt
1818 xt[n] += *dt; // t0+dt
1819 //
1820 evaluate_slpHxt(n, xt, Hxt);
1821 LHS = Hxt;
1822 RHS = Hxt + n * n;
1823 //
1825 LAPACK_success =
1827 n, LHS, 1, RHS, dx4);
1828
1829 // "dx1" = .5*dx1*dt, "dx2" = .5*dx2*dt, "dx3" = dx3*dt
1839 }
1840 break;
1841 case PROJECTIVE_NEWTON:
1842 {
1843 evaluate_slpHxt(n, x0t0, Hxt);
1844 LHS = Hxt;
1845 RHS = Hxt + n * n;
1847 n, LHS, 1, RHS, dx); // dx used as temp
1848 double chi2 = sqrt(norm2_complex_array<ComplexField>(n, RHS) +
1850 double chi1;
1851
1852 // evaluate again: LHS destroyed by solve_... !!!
1853 evaluate_slpHxt(n, x0t0, Hxt);
1854 LHS = Hxt;
1855
1856 for (j = 0; j < n; j++)
1857 for (i = 0; i < n; i++)
1858 *(LHS + n * i + j) =
1859 *(LHS + n * i + j) *
1860 DMforPN[j]; // multiply j-th column by sqrt(degree)
1861 // print_complex_matrix(n,(double*)LHS); //!!!
1862 norm_of_inverse_via_svd(n, LHS, chi1);
1863 // printf("chi1=%lf\n", chi1);
1864 *dt = 0.04804448 / (maxDegreeTo3halves * chi1 * chi2 * bigT);
1865 if (dt->getreal() < dt_min_dbl) t_s->status = MIN_STEP_FAILED;
1866 if (dt->getreal() > 1 - t0->getreal())
1867 *dt = complex(1 - t0->getreal());
1869 }
1870 break;
1871 default:
1872 ERROR("unknown predictor");
1873 };
1874
1875 // make prediction
1876 copy_complex_array<ComplexField>(n + 1, x0t0, x1t1);
1877 add_to_complex_array<ComplexField>(n + 1, x1t1, dxdt);
1878
1879 // CORRECTOR
1880 int n_corr_steps = 0;
1881 bool is_successful;
1882 do
1883 {
1884 n_corr_steps++;
1885 //
1886 evaluate_slpHxH(n, x1t1, HxH);
1887 LHS = HxH;
1888 RHS = HxH + n * n; // i.e., H
1889 //
1891 LAPACK_success =
1892 LAPACK_success &&
1893 solve_via_lapack_without_transposition(n, LHS, 1, RHS, dx);
1895 is_successful =
1898 tol2 * norm2_complex_array<ComplexField>(n, x1t1));
1899 // printf("c: |dx|^2 = %lf\n",
1900 // norm2_complex_array<ComplexField>(n,dx));
1901 }
1902 while (!is_successful and n_corr_steps < max_corr_steps);
1903
1904 if (!is_successful)
1905 {
1906 // predictor failure
1907 predictor_successes = 0;
1908 *dt = complex(dt_decrease_factor_dbl) * (*dt);
1909 if (dt->getreal() < dt_min_dbl) t_s->status = MIN_STEP_FAILED;
1910 }
1911 else
1912 {
1913 // predictor success
1914 predictor_successes = predictor_successes + 1;
1915 copy_complex_array<ComplexField>(n + 1, x1t1, x0t0);
1916 count++;
1917 if (is_successful &&
1918 predictor_successes >= num_successes_before_increase)
1919 {
1920 predictor_successes = 0;
1921 *dt = complex(dt_increase_factor_dbl) * (*dt);
1922 }
1923 }
1924 if (norm2_complex_array<ComplexField>(n, x0) > infinity_threshold2)
1925 t_s->status = INFINITY_FAILED;
1926 if (!LAPACK_success) t_s->status = SINGULAR;
1927 }
1928 // record the solution
1930 t_s->t = t0->getreal();
1931 if (t_s->status == PROCESSING) t_s->status = REGULAR;
1932 evaluate_slpHxH(n, x0t0, HxH);
1933 cond_number_via_svd(n, HxH /*Hx*/, t_s->cond);
1934 t_s->num_steps = count;
1936 {
1937 if (sol_n % 50 == 0) printf("\n");
1938 switch (t_s->status)
1939 {
1940 case REGULAR:
1941 printf(".");
1942 break;
1943 case INFINITY_FAILED:
1944 printf("I");
1945 break;
1946 case MIN_STEP_FAILED:
1947 printf("M");
1948 break;
1949 case SINGULAR:
1950 printf("S");
1951 break;
1952 default:
1953 printf("-");
1954 }
1955 fflush(stdout);
1956 }
1957 }
1958 if (M2_numericalAlgebraicGeometryTrace > 0) printf("\n");
1959
1960 // clear arrays
1961 // freemem(t_sols); // do not delete (same as raw_solutions)
1962 freemem(s_sols);
1963 freemem(x0t0);
1964 freemem(x1t1);
1965 freemem(dxdt);
1966 freemem(xt);
1967 freemem(dx1);
1968 freemem(dx2);
1969 freemem(dx3);
1970 freemem(dx4);
1971 freemem(Hxt);
1972 freemem(HxtH);
1973 freemem(HxH);
1974
1975 return n_sols;
1976}
1977
1978Matrix /* or null */* PathTracker::refine(const Matrix* sols,
1979 gmp_RR tolerance,
1980 int max_corr_steps_refine)
1981{
1982 double epsilon2 = mpfr_get_d(tolerance, MPFR_RNDN);
1983 epsilon2 *= epsilon2;
1984 int n = n_coords;
1985 if (!cast_to_CCC(sols->get_ring()))
1986 {
1987 ERROR("complex coordinates expected");
1988 return nullptr;
1989 }
1990 if (sols->n_cols() != n)
1991 {
1992 ERROR("incorrect number of coordinates");
1993 return nullptr;
1994 }
1995 n_sols = sols->n_rows();
1996
1997 // memory distribution for arrays
1998 complex* s_sols = newarray_atomic(complex, n * n_sols);
2000 complex* x1t1 = newarray_atomic(complex, n + 1);
2001 complex* x1 = x1t1;
2002 complex* t1 = x1t1 + n;
2003 complex* HxH = newarray_atomic(complex, n * (n + 1));
2004 complex *LHS, *RHS;
2005
2006 // read solutions: rows are solutions
2007 int i, j;
2008 complex* c = s_sols;
2009 for (i = 0; i < n_sols; i++)
2010 for (j = 0; j < n; j++, c++)
2011 *c = complex(toBigComplex(C, sols->elem(i, j)));
2012
2013 complex* s_s = s_sols; // current solution
2014 for (int sol_n = 0; sol_n < n_sols; sol_n++, s_s += n)
2015 {
2017 *t1 = complex(1, 0);
2018 // CORRECTOR
2019 bool is_successful;
2020 int n_corr_steps = 0;
2021 do
2022 {
2023 n_corr_steps++;
2024 //
2025 evaluate_slpHxH(n, x1t1, HxH);
2026 LHS = HxH;
2027 RHS = HxH + n * n; // i.e., H
2028 //
2030 solve_via_lapack_without_transposition(n, LHS, 1, RHS, dx);
2032 is_successful = norm2_complex_array<ComplexField>(n, dx) <
2033 epsilon2 * norm2_complex_array<ComplexField>(n, x1t1);
2034 }
2035 while (!is_successful and n_corr_steps < max_corr_steps_refine);
2036 if (!is_successful)
2037 printf("max number of corrector steps exceeded for solution %d", sol_n);
2039 }
2040
2041// make the output matrix
2042#ifdef SS // Unfortunate Solaris macro
2043#undef SS
2044#endif
2045 FreeModule* SS = C->make_FreeModule(n);
2046 FreeModule* TT = C->make_FreeModule(n_sols);
2047 MatrixConstructor mat(TT, SS);
2048 mpfr_t re, im;
2049 mpfr_init(re);
2050 mpfr_init(im);
2051 c = s_sols;
2052 for (i = 0; i < n_sols; i++)
2053 for (j = 0; j < n; j++, c++)
2054 {
2055 // mpfr_set_d(re, c->getreal(), MPFR_RNDN);
2056 // mpfr_set_d(im, c->getimaginary(), MPFR_RNDN);
2057 // ring_elem e = from_BigReals(C,re,im);
2058 ring_elem e = from_doubles(C, c->getreal(), c->getimaginary());
2059
2060 mat.set_entry(i, j, e);
2061 }
2062 mpfr_clear(re);
2063 mpfr_clear(im);
2064
2065 // clear arrays
2066 freemem(s_sols);
2067 freemem(dx);
2068 freemem(x1t1);
2069 freemem(HxH);
2070
2071 return mat.to_matrix();
2072}
2073
2074Matrix /* or null */* PathTracker::getSolution(int solN)
2075{
2076 if (solN < 0 || solN >= n_sols) return nullptr;
2077 // construct output
2078 FreeModule* SS = C->make_FreeModule(n_coords);
2079 FreeModule* TT = C->make_FreeModule(1);
2080 MatrixConstructor mat(TT, SS);
2081 mpfr_t re, im;
2082 mpfr_init(re);
2083 mpfr_init(im);
2084 Solution* s = raw_solutions + solN;
2085 complex* c = s->x;
2086 for (int j = 0; j < n_coords; j++, c++)
2087 {
2088 // mpfr_set_d(re, c->getreal(), MPFR_RNDN);
2089 // mpfr_set_d(im, c->getimaginary(), MPFR_RNDN);
2090 // ring_elem e = from_BigReals(C,re,im);
2091 ring_elem e = from_doubles(C, c->getreal(), c->getimaginary());
2092
2093 mat.set_entry(0, j, e);
2094 }
2095 mpfr_clear(re);
2096 mpfr_clear(im);
2097 return mat.to_matrix();
2098}
2099
2101{
2102 // construct output
2103 FreeModule* SS = C->make_FreeModule(n_coords);
2104 FreeModule* TT = C->make_FreeModule(n_sols);
2105 MatrixConstructor mat(TT, SS);
2106 mpfr_t re, im;
2107 mpfr_init(re);
2108 mpfr_init(im);
2110 for (int i = 0; i < n_sols; i++, s++)
2111 {
2112 complex* c = s->x;
2113 for (int j = 0; j < n_coords; j++, c++)
2114 {
2115 // mpfr_set_d(re, c->getreal(), MPFR_RNDN);
2116 // mpfr_set_d(im, c->getimaginary(), MPFR_RNDN);
2117 // ring_elem e = from_BigReals(C,re,im);
2118 ring_elem e = from_doubles(C, c->getreal(), c->getimaginary());
2119
2120 mat.set_entry(i, j, e);
2121 }
2122 }
2123 mpfr_clear(re);
2124 mpfr_clear(im);
2125 return (solutions = mat.to_matrix());
2126}
2127
2129{
2130 if (solN < 0 || solN >= n_sols) return -1;
2131 return raw_solutions[solN].status;
2132}
2133
2135{
2136 if (solN < 0 || solN >= n_sols) return -1;
2137 return raw_solutions[solN].num_steps;
2138}
2139
2141{
2142 if (solN < 0 || solN >= n_sols) return nullptr;
2144 mpfr_init2(result, C->get_precision());
2145 mpfr_set_d(result, raw_solutions[solN].t, MPFR_RNDN);
2146 return moveTo_gmpRR(result);
2147}
2148
2150{
2151 if (solN < 0 || solN >= n_sols) return nullptr;
2153 mpfr_init2(result, C->get_precision());
2154 mpfr_set_d(result, raw_solutions[solN].cond, MPFR_RNDN);
2155 return moveTo_gmpRR(result);
2156}
2157
2159{
2160 o << "path tracker #" << number;
2161 // slpHxt->stats_out(o);
2162 // slpHxH->stats_out(o);
2163
2164 /* int n = slpHxH->num_inputs;
2165 char buf[1000];
2166 complex input[n], output[n*n];
2167 for(int i=0; i<n; i++) {
2168 Nterm* t = H->elem(1,i).get_poly();
2169 input[i] = complex(toBigComplex(C,t->coeff));
2170 }
2171
2172 slpHxH->evaluate(n, input, output);
2173 for(int i=0; i<n*n; i++) {
2174 output[i].sprint(buf);
2175 o << "HxH[" << i << "] = " << buf << newline;
2176 }
2177 slpHxt->evaluate(n, input, output);
2178 for(int i=0; i<n*n; i++) {
2179 output[i].sprint(buf);
2180 o << "Hxt[" << i << "] = " << buf << newline;
2181 }
2182 slpH->text_out(o);
2183 slpHxH->text_out(o);
2184 */
2185}
2186
2187// ------------------------- service functions -------------------------
2188void Solution::make(int m, const complex* s_s)
2189{
2190 this->n = m;
2194}
2195
2197{
2199 R->multi_degree(re, d);
2200 // for a single graded ring, the first entry in a monomial array
2201 // is the negative of the degree, which is the second entry
2202 return -d[0];
2203}
2204
2205void print_complex_matrix(int size, const double* A)
2206{
2207 static int c = 5;
2208 int i, j;
2209 if (c-- > 0)
2210 for (i = 0; i < size; i++)
2211 {
2212 for (j = 0; j < size; j++)
2213 printf("(%lf %lf) ",
2214 *(A + 2 * (size * i + j)),
2215 *(A + 2 * (size * i + j) + 1));
2216 printf("\n");
2217 }
2218}
2219
2220// template class StraightLineProgram<complex>;
2221// template class StraightLineProgram<CC>;
2222
2223// Local Variables:
2224// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
2225// indent-tabs-mode: nil
2226// End:
#define dlclose(x)
Definition NAG.cpp:16
int add_constant_get_position(gc_vector< typename Field::element_type > &consts, typename Field::element_type c)
Definition NAG.cpp:226
bool cond_number_via_svd(int size, complex *A, double &cond)
Definition NAG.cpp:1269
void rawSetParametersPT(PathTracker *PT, M2_bool is_projective, gmp_RR init_dt, gmp_RR min_dt, gmp_RR dt_increase_factor, gmp_RR dt_decrease_factor, int num_successes_before_increase, gmp_RR epsilon, int max_corr_steps, gmp_RR end_zone_factor, gmp_RR infinity_threshold, int pred_type)
Definition NAG.cpp:1571
bool norm_of_inverse_via_svd(int size, complex *A, double &norm)
Definition NAG.cpp:1339
const Matrix * rawGetSolutionPT(PathTracker *PT, int solN)
Definition NAG.cpp:1602
int rawGetSolutionStatusPT(PathTracker *PT, int solN)
Definition NAG.cpp:1612
gmp_RRorNull rawGetSolutionLastTvaluePT(PathTracker *PT, int solN)
Definition NAG.cpp:1622
bool solve_via_lapack(int size, complex *A, int bsize, complex *b, complex *x)
Definition NAG.cpp:1165
void print_complex_matrix(int size, const double *A)
Definition NAG.cpp:2205
void monomials_to_conventional_expvectors(int n, Nterm *f)
Definition NAG.cpp:281
int rawGetSolutionStepsPT(PathTracker *PT, int solN)
Definition NAG.cpp:1617
int degree_ring_elem(const PolyRing *R, ring_elem re)
Definition NAG.cpp:2196
const Matrix * rawRefinePT(PathTracker *PT, const Matrix *sols, gmp_RR tolerance, int max_corr_steps_refine)
Definition NAG.cpp:1632
bool solve_via_lapack_without_transposition(int size, complex *A, int bsize, complex *b, complex *x)
Definition NAG.cpp:1218
Nterm * extract_divisible_by_x(Nterm *&ff, int i)
Definition NAG.cpp:191
void rawLaunchPT(PathTracker *PT, const Matrix *start_sols)
Definition NAG.cpp:1597
#define dlsym(x, y)
Definition NAG.cpp:15
gmp_RRorNull rawGetSolutionRcondPT(PathTracker *PT, int solN)
Definition NAG.cpp:1627
const Matrix * rawGetAllSolutionsPT(PathTracker *PT)
Definition NAG.cpp:1607
#define dlopen(x, y)
Definition NAG.cpp:14
Engine-boundary C API for the Numerical Algebraic Geometry subsystem.
#define ONE_CONST
Definition NAG.hpp:443
#define slpMULTIsum
Definition NAG.hpp:439
#define slpCOPY
Definition NAG.hpp:438
#define slpCORRECTOR
Definition NAG.hpp:436
#define CONST_OFFSET
Definition NAG.hpp:452
#define slpPRODUCT
Definition NAG.hpp:440
#define libPREFIX
Definition NAG.hpp:433
#define MAX_NUM_SLPs
Definition NAG.hpp:451
#define RUNGE_KUTTA
Definition NAG.hpp:446
void zero_complex_array(int n, typename Field::element_type *a)
Definition NAG.hpp:375
gmp_CC toBigComplex(const CCC *C, ring_elem a)
Definition NAG.hpp:210
#define slpPREDICTOR
Definition NAG.hpp:435
void add_to_complex_array(int n, typename Field::element_type *a, const typename Field::element_type *b)
Definition NAG.hpp:408
void multiply_complex_array_scalar(int n, typename Field::element_type *a, const typename Field::element_type b)
Definition NAG.hpp:400
#define EULER
Definition NAG.hpp:448
#define ZERO_CONST
Definition NAG.hpp:442
#define SLP_HEADER_LEN
Definition NAG.hpp:453
int degree_ring_elem(const PolyRing *R, ring_elem re)
Definition NAG.cpp:2196
ring_elem from_doubles(const CCC *C, double re, double im)
Definition NAG.hpp:201
#define TANGENT
Definition NAG.hpp:447
#define CCC
Definition NAG.hpp:195
void negate_complex_array(int n, typename Field::element_type *a)
Definition NAG.hpp:416
#define PROJECTIVE_NEWTON
Definition NAG.hpp:449
double norm2_complex_array(int n, typename Field::element_type *a)
Definition NAG.hpp:422
void copy_complex_array(int n, const typename Field::element_type *a, typename Field::element_type *b)
Definition NAG.hpp:381
#define slpEND
Definition NAG.hpp:437
#define slpCOMPILED
Definition NAG.hpp:434
const CCC * cast_to_CCC(const Ring *R)
Definition NAG.hpp:196
#define MAX_NUM_PATH_TRACKERS
Definition NAG.hpp:455
Numerical Algebraic Geometry: homotopy continuation PathTracker and supporting numeric types.
@ PROCESSING
Definition SLP-imp.hpp:355
@ INFINITY_FAILED
Definition SLP-imp.hpp:358
@ MIN_STEP_FAILED
Definition SLP-imp.hpp:359
@ SINGULAR
Definition SLP-imp.hpp:357
@ REGULAR
Definition SLP-imp.hpp:356
const Ring * R
Definition freemod.hpp:75
Engine-side free module R^n over a Ring.
Definition freemod.hpp:66
const Ring * get_ring() const
Definition matrix.hpp:134
ring_elem elem(int i, int j) const
Definition matrix.cpp:307
int n_cols() const
Definition matrix.hpp:147
int n_rows() const
Definition matrix.hpp:146
Matrix * to_matrix()
void set_entry(int r, int c, ring_elem a)
Mutable builder used to assemble an immutable Matrix one column (or one term) at a time.
M2_bool is_projective
Definition NAG.hpp:751
gmp_RRorNull getSolutionLastT(int)
Definition NAG.cpp:2140
int track(const Matrix *)
Definition NAG.cpp:1640
Matrix * solutions
Definition NAG.hpp:748
static PathTracker * catalog[MAX_NUM_PATH_TRACKERS]
Definition NAG.hpp:655
gmp_RR end_zone_factor
Definition NAG.hpp:757
int max_corr_steps
Definition NAG.hpp:756
int getSolutionSteps(int)
Definition NAG.cpp:2134
void evaluate_slpHxt(int n, const complex *x0t0, complex *Hxt)
Definition NAG.hpp:671
static PathTracker * make(const Matrix *)
Definition NAG.cpp:1516
double maxDegreeTo3halves
Definition NAG.hpp:669
const Matrix * T
Definition NAG.hpp:661
gmp_RR init_dt
Definition NAG.hpp:752
int n_coords
Definition NAG.hpp:745
const Matrix * S
Definition NAG.hpp:661
int number
Definition NAG.hpp:658
virtual ~PathTracker()
Definition NAG.cpp:1425
void evaluate_slpHxH(int n, const complex *x0t0, complex *HxH)
Definition NAG.hpp:715
PathTracker()
Definition NAG.cpp:1418
int n_sols
Definition NAG.hpp:746
int pred_type
Definition NAG.hpp:759
static int num_path_trackers
Definition NAG.hpp:656
int getSolutionStatus(int)
Definition NAG.cpp:2128
gmp_RR dt_decrease_factor
Definition NAG.hpp:753
double productST
Definition NAG.hpp:666
void evaluate_slpHxtH(int n, const complex *x0t0, complex *HxtH)
Definition NAG.hpp:708
gmp_RR epsilon
Definition NAG.hpp:755
int num_successes_before_increase
Definition NAG.hpp:754
Matrix * getAllSolutions()
Definition NAG.cpp:2100
const CCC * C
Definition NAG.hpp:742
Solution * raw_solutions
Definition NAG.hpp:747
gmp_RR min_dt
Definition NAG.hpp:752
Matrix * refine(const Matrix *sols, gmp_RR tolerance, int max_corr_steps_refine=100)
Definition NAG.cpp:1978
double * DMforPN
Definition NAG.hpp:668
double bigT
Definition NAG.hpp:667
gmp_RR infinity_threshold
Definition NAG.hpp:758
Matrix * getSolution(int)
Definition NAG.cpp:2074
gmp_RR dt_increase_factor
Definition NAG.hpp:753
gmp_RRorNull getSolutionRcond(int)
Definition NAG.cpp:2149
void text_out(buffer &o) const
Definition NAG.cpp:2158
Numerical homotopy-continuation path tracker for systems of polynomial equations.
Definition NAG.hpp:654
Concrete PolyRingFlat subclass implementing ordinary commutative polynomial rings K[x_1,...
Definition poly.hpp:64
virtual const Ring * getCoefficients() const
Definition polyring.hpp:277
virtual FreeModule * make_FreeModule() const
Definition ring.cpp:53
virtual const PolyRing * cast_to_PolyRing() const
Definition ring.hpp:245
virtual ring_elem copy(const ring_elem f) const =0
virtual bool multi_degree(const ring_elem f, monomial d) const
Definition ring.cpp:407
xxx xxx xxx
Definition ring.hpp:102
SLP< Field > * concatenate(const SLP< Field > *slp)
Definition NAG.cpp:353
void evaluate(int n, const element_type *values, element_type *out)
Definition NAG.cpp:713
void relative_to_absolute(int &aa, int cur_node)
Definition NAG.hpp:528
virtual ~SLP()
Definition NAG.cpp:72
int rows_out
Definition NAG.hpp:502
SLP()
Definition NAG.cpp:62
void convert_to_absolute_position()
Definition NAG.cpp:914
int cols_out
Definition NAG.hpp:502
SLP< Field > * jacobian(bool makeHxH, SLP< Field > *&slpHxH, bool makeHxtH, SLP< Field > *&slpHxtH)
Definition NAG.cpp:612
static int num_slps
Definition NAG.hpp:495
int num_operations
Definition NAG.hpp:502
clock_t eval_time
Definition NAG.hpp:506
void * handle
Definition NAG.hpp:504
int poly_to_horner_slp(int n, gc_vector< int > &prog, gc_vector< element_type > &consts, Nterm *&f)
Definition NAG.cpp:237
M2_arrayint program
Definition NAG.hpp:498
void stats_out(buffer &o) const
Definition NAG.cpp:950
SLP< Field > * copy()
Definition NAG.cpp:168
ComplexField::element_type element_type
Definition NAG.hpp:488
static SLP< Field > * make(const PolyRing *, ring_elem)
Definition NAG.cpp:289
int n_calls
Definition NAG.hpp:507
int diffNodeInput(int n, int v, gc_vector< int > &prog)
Definition NAG.cpp:450
static void make_nodes(element_type *&, int size)
Definition NAG.cpp:162
int num_inputs
Definition NAG.hpp:502
element_type * nodes
Definition NAG.hpp:499
static SLP< Field > * catalog[MAX_NUM_SLPs]
Definition NAG.hpp:494
void(* compiled_fn)(element_type *, element_type *)
Definition NAG.hpp:505
int num_consts
Definition NAG.hpp:502
void text_out(buffer &o) const
Definition NAG.cpp:958
gc_vector< int > node_index
Definition NAG.hpp:500
bool is_relative_position
Definition NAG.hpp:497
int diffPartReference(int n, int ref, int v, gc_vector< int > &prog)
Definition NAG.cpp:434
const CCC * C
Definition NAG.hpp:491
Definition NAG.hpp:485
static StraightLineProgram * make(const PolyRing *R, ring_elem e)
Definition NAG.cpp:31
void evaluate(int n, const element_type *values, element_type *out)
Definition NAG.cpp:50
void text_out(buffer &o) const
Definition NAG.cpp:46
double getreal() const
Definition NAG.hpp:358
double getimaginary() const
Definition NAG.hpp:359
Engine-wide include prelude — a single point of truth for portability shims.
#define Matrix
Definition factory.cpp:14
mpfr_srcptr moveTo_gmpRR(mpfr_ptr _z)
Definition gmp-util.h:153
int p
int zgesvd_(char *jobU, char *jobV, int *rows, int *cols, double *A, int *ldA, double *Sigma, double *U, int *ldU, double *VT, int *ldVT, double *w, int *lwork, double *rwork, int *info)
int zgesv_(int *n, int *nrhs, double *a, int *lda, int *ipiv, double *b, int *ldb, int *info)
Engine bridge into LAPACK for RR / CC dense linear algebra.
void freemem(void *s)
Definition m2-mem.cpp:103
void size_t s
Definition m2-mem.cpp:271
const int ERROR
Definition m2-mem.cpp:55
VALGRIND_MAKE_MEM_DEFINED & result(result)
#define getmemstructtype(S)
Definition m2-mem.h:143
int M2_numericalAlgebraicGeometryTrace
Definition m2-types.cpp:53
M2_arrayint M2_makearrayint(int n)
Definition m2-types.cpp:6
char newline[]
Definition m2-types.cpp:49
mpfr_srcptr gmp_RR
Definition m2-types.h:148
mpfr_ptr gmp_RRmutable
Definition m2-types.h:150
mpfr_srcptr gmp_RRorNull
Definition m2-types.h:149
char M2_bool
Definition m2-types.h:82
MatrixConstructor — the mutable builder that produces an immutable Matrix.
Matrix — the engine's immutable homomorphism F -> G between free modules.
#define ALLOCATE_EXPONENTS(byte_len)
Definition monoid.hpp:62
#define EXPONENT_BYTE_SIZE(nvars)
Definition monoid.hpp:63
typename std::vector< T, gc_allocator< T > > gc_vector
a version of the STL vector, which allocates its backing memory with gc.
Definition newdelete.hpp:76
#define newarray(T, len)
Definition newdelete.hpp:82
#define newarray_atomic(T, len)
Definition newdelete.hpp:91
volatile int x
Concrete commutative PolyRing — standard polynomial ring inheriting from PolyRingFlat.
#define max(a, b)
Definition polyroots.cpp:52
RingElement — tagged (Ring*, ring_elem) pair, the engine's universal element type.
Nterm * next
Definition ringelem.hpp:157
ring_elem coeff
Definition ringelem.hpp:158
int monom[1]
Definition ringelem.hpp:160
Singly linked-list node carrying one term of a polynomial-ring element.
Definition ringelem.hpp:156
complex * x
Definition NAG.hpp:620
double cond
Definition NAG.hpp:623
SolutionStatus status
Definition NAG.hpp:624
double t
Definition NAG.hpp:621
complex * start_x
Definition NAG.hpp:622
void make(int m, const complex *s_s)
Definition NAG.cpp:2188
int num_steps
Definition NAG.hpp:625
One numerical solution produced by a PathTracker run, with the full per-path diagnostic record.
Definition NAG.hpp:618
#define T
Definition table.c:13
Nterm * get_poly() const
Definition ringelem.hpp:122