/[ascend]/trunk/solvers/cmslv/slv9.c
ViewVC logotype

Contents of /trunk/solvers/cmslv/slv9.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1540 - (show annotations) (download) (as text)
Sun Jul 15 03:59:23 2007 UTC (17 years, 9 months ago) by jpye
File MIME type: text/x-csrc
File size: 163300 byte(s)
Reorganising CONOPT binding so that building support for CONOPT is possible without it being installed.
1 /* ASCEND modelling environment
2 Copyright (C) 2006, 2007 Carnegie Mellon University
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18 *//**
19 @file
20 Conditional Modeling Solver (CMSlv) module.
21 *//*
22 Conditional Modeling Solver
23 by Vicente Rico-Ramirez, 04/1997
24 Last in CVS: $Revision: 1.22 $ $Date: 2000/01/25 02:27:58 $ $Author: ballan $
25 */
26
27 #include <math.h>
28
29 #include <utilities/config.h>
30 #include <utilities/ascConfig.h>
31 #include <utilities/ascSignal.h>
32 #include <utilities/ascMalloc.h>
33 #include <general/tm_time.h>
34 #include <utilities/mem.h>
35 #include <general/list.h>
36 #include <general/mathmacros.h>
37
38 #include <linear/mtx_reorder.h>
39
40 #include <system/calc.h>
41 #include <system/relman.h>
42 #include <system/logrelman.h>
43 #include <system/bndman.h>
44 #include <system/slv_stdcalls.h>
45 #include <system/cond_config.h>
46 #include <solver/solver.h>
47 #include <solver/slvDOF.h>
48
49 #include <solver/solver.h>
50
51 typedef struct slv9_system_structure *slv9_system_t;
52
53 #define SOLVER_CMSLV 9
54
55 ASC_DLLSPEC SolverRegisterFn cmslv_register;
56
57 #ifdef ASC_WITH_CONOPT
58 # include <solver/conopt_dl.h>
59 #else
60 # define MAX_INT MAXINT
61 # define MAX_REAL MAXDOUBLE
62 # define CONOPT_BOUNDLIMIT 1e12
63 #endif
64
65 /*
66 * definitions to enable/disable the output of partial results in
67 * the solution of a problem
68 */
69 #define DEBUG FALSE
70 #define SHOW_LOGICAL_DETAILS FALSE
71 #define SHOW_BOUNDARY_ANALYSIS_DETAILS FALSE
72 #define SHOW_OPTIMIZATION_DETAILS FALSE
73 #define SHOW_BISECTION_DETAILS FALSE
74 #define SHOW_LINEAR_SEARCH_DETAILS FALSE
75 #define SHOW_LAGRANGE_DETAILS FALSE
76 #define DEBUG_CONSISTENCY FALSE
77 #define TEST_CONSISTENCY FALSE
78 #define USE_CONSISTENCY FALSE
79
80 /*
81 * system definitions
82 */
83 #define SLV9(s) ((slv9_system_t)(s))
84 #define SERVER (sys->slv)
85 #define slv9_PA_SIZE 26 /* MUST INCREMENT WHEN ADDING PARAMETERS */
86 #define LOGSOLVER_OPTION_PTR (sys->parm_array[0])
87 #define LOGSOLVER_OPTION ((*(char **)LOGSOLVER_OPTION_PTR))
88 #define NONLISOLVER_OPTION_PTR (sys->parm_array[1])
89 #define NONLISOLVER_OPTION ((*(char **)NONLISOLVER_OPTION_PTR))
90 #define OPTSOLVER_OPTION_PTR (sys->parm_array[2])
91 #define OPTSOLVER_OPTION ((*(char **)OPTSOLVER_OPTION_PTR))
92 #define TIME_LIMIT_PTR (sys->parm_array[3])
93 #define TIME_LIMIT ((*(int32 *)TIME_LIMIT_PTR))
94 #define ITER_LIMIT_PTR (sys->parm_array[4])
95 #define ITER_LIMIT ((*(int32 *)ITER_LIMIT_PTR))
96 #define ITER_BIS_LIMIT_PTR (sys->parm_array[5])
97 #define ITER_BIS_LIMIT ((*(int32 *)ITER_BIS_LIMIT_PTR))
98 #define TOO_SMALL_PTR (sys->parm_array[6])
99 #define TOO_SMALL ((*(real64 *)TOO_SMALL_PTR))
100 #define LINEAR_SEARCH_FACTOR_PTR (sys->parm_array[7])
101 #define LINEAR_SEARCH_FACTOR ((*(real64 *)LINEAR_SEARCH_FACTOR_PTR))
102 #define SHOW_MORE_IMPT_PTR (sys->parm_array[8])
103 #define SHOW_MORE_IMPT ((*(int32 *)SHOW_MORE_IMPT_PTR))
104 #define SHOW_LESS_IMPT_PTR (sys->parm_array[9])
105 #define SHOW_LESS_IMPT ((*(int32 *)SHOW_LESS_IMPT_PTR))
106 #define AUTO_RESOLVE_PTR (sys->parm_array[10])
107 #define AUTO_RESOLVE ((*(int32 *)AUTO_RESOLVE_PTR))
108 #define UNDEFINED_PTR (sys->parm_array[11])
109 #define UNDEFINED ((*(real64 *)UNDEFINED_PTR))
110 #define DOMLIM_PTR (sys->parm_array[12])
111 #define DOMLIM ((*(int32 *)DOMLIM_PTR))
112 #define OPT_ITER_LIMIT_PTR (sys->parm_array[13])
113 #define OPT_ITER_LIMIT ((*(int32 *)OPT_ITER_LIMIT_PTR))
114 #define INFINITY_PTR (sys->parm_array[14])
115 #define ASC_INFINITY ((*(real64 *)INFINITY_PTR))
116 #define OBJ_TOL_PTR (sys->parm_array[15])
117 #define OBJ_TOL ((*(real64 *)OBJ_TOL_PTR))
118 #define RTMAXJ_PTR (sys->parm_array[16])
119 #define RTMAXJ ((*(real64 *)RTMAXJ_PTR))
120 #define RHO_PTR (sys->parm_array[17])
121 #define RHO ((*(real64 *)RHO_PTR))
122
123
124 /*
125 * Client tokens of the different solvers: Conditional, Optimizer,
126 * Nonlinear, Logical. We will switch from one client token to
127 * another as the solution process occurs.
128 */
129 #define NUMBER_OF_CLIENTS 4
130 SlvClientToken token[NUMBER_OF_CLIENTS];
131 int32 solver_index[NUMBER_OF_CLIENTS];
132
133 /*
134 * indeces in arrays token and solver_index
135 */
136 #define CONDITIONAL_SOLVER 0
137 #define LOGICAL_SOLVER 1
138 #define NONLINEAR_SOLVER 2
139 #define OPTIMIZATION_SOLVER 3
140
141 /*
142 * Do we have an optimization problem ?. Global variable initialized
143 * to 0 (not optimizing)
144 */
145 static int32 g_optimizing = 0;
146
147 #if USE_CONSISTENCY
148 /*
149 * number of subregion visited during the solution of the conditional
150 * model.
151 */
152 static int32 g_subregions_visited;
153
154 #endif /* USE_CONSISTENCY */
155
156
157 /* auxiliar structures */
158 struct boolean_values {
159 int32 *pre_val; /* previous values of dis_discrete */
160 int32 *cur_val; /* current values of dis_discrete */
161 };
162
163 struct matching_cases {
164 int32 *case_list; /* list of cases */
165 int32 ncases; /* number of cases */
166 int32 diff_subregion; /* subregion ? */
167 };
168
169 struct real_values {
170 real64 *pre_values; /* previous values of var_variables */
171 real64 *cur_values; /* current values of var_variables */
172 };
173
174 struct opt_vector {
175 real64 *element; /* elements in colum of matrix */
176 };
177
178 struct opt_matrix {
179 struct opt_vector *cols; /* columns in matrix */
180 };
181
182 struct subregionID {
183 unsigned long ID_number;
184 int32 *bool_values;
185 };
186
187 struct ds_subregion_list {
188 int32 length,capacity;
189 struct subregionID *sub_stack;
190 };
191
192 struct ds_subregions_visited {
193 int32 length,capacity;
194 unsigned long *visited;
195 };
196
197 /*
198 * This solver's data structure (CMSlv)
199 */
200 struct slv9_system_structure {
201
202 /*
203 * Problem definition
204 */
205 slv_system_t slv; /* slv_system_t back-link */
206
207 struct rel_relation *obj; /* Objective function: NULL = none */
208 struct var_variable **vlist; /* Variable list (NULL terminated) */
209 struct rel_relation **rlist; /* Relation list (NULL terminated) */
210 struct dis_discrete **dvlist; /* Dis vars list (NULL terminated) */
211 struct logrel_relation **lrlist; /* Logrels list(NULL terminated)*/
212 struct bnd_boundary **blist; /* Variable list (NULL terminated) */
213 struct var_variable **mvlist;
214 struct dis_discrete **mdvlist; /* We will not touch the masters list,
215 * but they can provide very useful
216 * information to the conditional
217 * solver since the master index does
218 * not change.
219 */
220
221 /*
222 * for optimization at boundaries
223 */
224 struct opt_matrix *coeff_matrix; /* Matrix for optimization problem */
225 struct opt_vector *opt_var_values; /* Values of vars in opt problem */
226 int32 subregions; /* number of subregions at cur bnd */
227 mtx_matrix_t lin_mtx; /* Matrix to define the linear system
228 * for calculation of the lagrange
229 * multipliers
230 */
231 /*
232 * For search consistency analysis
233 */
234 struct ds_subregion_list subregion_list;
235 /*
236 * Information about the subregions
237 * visited during the solution of the
238 * conditional model
239 */
240 struct ds_subregions_visited subregions_visited;
241 /*
242 * ID number of the subregions
243 * visited
244 */
245 int32 *bool_mindex; /* master indices of boolean vars in
246 * the problem associated with WHENs
247 */
248 int32 need_consistency_analysis; /* Is the consistency analysis needed */
249
250
251 /*
252 * Solver information
253 */
254 int32 integrity; /* Has the system been created ? */
255 int32 presolved; /* Has the system been presolved ? */
256 slv_parameters_t p; /* Parameters */
257 slv_status_t s; /* Status (as of iteration end) */
258 int32 cap; /* Order of matrix/vectors */
259 int32 rank; /* Symbolic rank of problem */
260 int32 vused; /* Free and incident variables */
261 int32 vtot; /* length of varlist */
262 int32 mvtot; /* length of master varlist */
263 int32 rused; /* Included relations */
264 int32 rtot; /* length of rellist */
265 real64 clock; /* CPU time */
266 int32 nliter; /* iterations in nonlinear solver */
267
268 void *parm_array[slv9_PA_SIZE]; /* array of pointers to param values */
269 struct slv_parameter pa[slv9_PA_SIZE]; /* &pa[0] => sys->p.parms */
270
271 #ifdef ASC_WITH_CONOPT
272 /*
273 * Data for optimizer at boundaries (CONOPT)
274 */
275 struct conopt_data con;
276 #endif
277 };
278
279
280 /*
281 * Integrity checks
282 * ----------------
283 * check_system(sys)
284 */
285
286 #define OK ((int32)813029392)
287 #define DESTROYED ((int32)103289182)
288
289 /*
290 * Checks sys for NULL and for integrity.
291 */
292 static
293 int check_system(slv9_system_t sys){
294 if(sys == NULL ) {
295 FPRINTF(ASCERR,"ERROR: (slv9) check_system\n");
296 FPRINTF(ASCERR," NULL system handle.\n");
297 return 1;
298 }
299
300 switch( sys->integrity ) {
301 case OK:
302 return 0;
303 case DESTROYED:
304 FPRINTF(ASCERR,"ERROR: (slv9) check_system\n");
305 FPRINTF(ASCERR," System was recently destroyed.\n");
306 return 1;
307 default:
308 FPRINTF(ASCERR,"ERROR: (slv9) check_system\n");
309 FPRINTF(ASCERR," System reused or never allocated.\n");
310 return 1;
311 }
312 }
313
314
315 /*
316 * General input/output routines
317 * -----------------------------
318 * print_var_name(out,sys,var)
319 */
320 #define print_var_name(a,b,c) slv_print_var_name((a),(b)->slv,(c))
321
322
323 /*
324 * Array operations
325 * ----------------
326 * destroy_array(p)
327 * create_array(len,type)
328 * create_zero_array(len,type)
329 */
330 #define destroy_array(p) \
331 if((p) != NULL ) ascfree((p))
332 #define create_array(len,type) \
333 ((len) > 0 ? (type *)ascmalloc((len)*sizeof(type)) : NULL)
334 #define create_zero_array(len,type) \
335 ((len) > 0 ? (type *)asccalloc((len),sizeof(type)) : NULL)
336
337
338 /*
339 * Search Consistency Analysis during iterative process
340 * ---------------------------------------------------------
341 * The caller of this functions is in charge of
342 * defining the extension of the analysis by passing an integer
343 * which will tell us if 1) the analysis consider only the current
344 * and the previous alternatives or 2) the analysis consider all the
345 * alternatives visited at current the state of the solution
346 * algorithm.
347 */
348
349 /*
350 * Handling dynamic allocation of the structural information
351 */
352
353 #define alloc_array(nelts,type) \
354 ((nelts) > 0 ? (type *)ascmalloc((nelts)*sizeof(type)) : NULL)
355 #define copy_nums(from,too,nnums) \
356 asc_memcpy((from),(too),(nnums)*sizeof(int32))
357 #define copy_subregions(from,too,nsubs) \
358 asc_memcpy((from),(too),(nsubs)*sizeof(struct subregionID))
359
360 #if TEST_CONSISTENCY
361 /*
362 * Appends the subregion_visited into the list
363 */
364 static
365 void append_subregion(struct ds_subregion_list *sl,
366 struct subregionID sub
367 ){
368 if(sl->length == sl->capacity ) {
369 int32 newcap;
370 struct subregionID *newlist;
371
372 newcap = sl->capacity + 10;
373 newlist = alloc_array(newcap,struct subregionID);
374 copy_subregions((char *)sl->sub_stack,(char *)newlist,sl->length);
375 if(sl->sub_stack != NULL ) {
376 ascfree(sl->sub_stack);
377 }
378 sl->sub_stack = newlist;
379 sl->capacity = newcap;
380 }
381
382 sl->sub_stack[sl->length++] = sub;
383 }
384
385 /*
386 * Appends the subregion_visited into the list
387 */
388 static
389 void append_sub_visited(struct ds_subregions_visited *sv,
390 unsigned long sub_visited
391 ){
392 if(sv->length == sv->capacity ) {
393 int32 newcap;
394 unsigned long *newlist;
395
396 newcap = sv->capacity + 10;
397 newlist = alloc_array(newcap,unsigned long);
398 copy_nums((char *)sv->visited,(char *)newlist,sv->length);
399 if(sv->visited != NULL ) {
400 ascfree(sv->visited);
401 }
402 sv->visited = newlist;
403 sv->capacity = newcap;
404 }
405
406 sv->visited[sv->length++] = sub_visited;
407 }
408
409 static
410 unsigned long powoftwo (int32 expo){
411 unsigned long val;
412 int32 c;
413
414 val = 1;
415 for (c=1; c<= expo; c++) {
416 val = val * 2;
417 }
418
419 return val;
420 }
421
422
423 /*
424 * Storage information (boolean values) about a subregion so that
425 * we can visit it later for interactive strucutral analysis
426 */
427 static
428 void ID_and_storage_subregion_information(slv_system_t server,
429 SlvClientToken asys
430 ){
431 slv9_system_t sys;
432 struct dis_discrete **bvlist;
433 struct dis_discrete *cur_dis;
434 struct ds_subregion_list *sl;
435 struct ds_subregions_visited *sv;
436 struct subregionID *sub;
437 dis_filter_t dfilter;
438 unsigned long val, visited, sID;
439 int32 d, numdvs, numdvf, dcount;
440 int32 len, s, found;
441
442 sys = SLV9(asys);
443 check_system(sys);
444
445 bvlist = sys->mdvlist;
446 if(bvlist == NULL ) {
447 FPRINTF(ASCERR,"ERROR: ID_and_storage_subregion_information.\n");
448 FPRINTF(ASCERR," Master discrete var list was never set.\n");
449 return;
450 }
451 numdvs = slv_get_num_master_dvars(server);
452
453 dfilter.matchbits = (DIS_INWHEN | DIS_BOOLEAN);
454 dfilter.matchvalue = (DIS_INWHEN | DIS_BOOLEAN);
455 numdvf = slv_count_master_dvars(server,&dfilter);
456
457 if(numdvf > 0) {
458 sub = (struct subregionID *)(ascmalloc(sizeof(struct subregionID)));
459 sub->bool_values = (int32 *)(ascmalloc(numdvf*sizeof(int32)));
460 }else{
461 FPRINTF(ASCERR,"ERROR: ID_and_storage_subregion_information.\n");
462 FPRINTF(ASCERR," No boolean variables in the problem \n");
463 return;
464 }
465
466 dcount = 0;
467 val = 0;
468 for (d=0; d<numdvs; d++) {
469 cur_dis = bvlist[d];
470 if(dis_apply_filter(cur_dis,&dfilter)) {
471 sub->bool_values[dcount] = dis_value(cur_dis);
472 dcount++;
473 if(sub->bool_values[dcount - 1] == 1) {
474 val = val + powoftwo(numdvf - dcount);
475 }
476 }
477 }
478 if((val == 0 ) && (numdvf > 0) ) {
479 val = powoftwo(numdvf);
480 }
481 sub->ID_number = val;
482 #if DEBUG_CONSISTENCY
483 FPRINTF(ASCERR,"ID of alternative is %ul \n", val);
484 #endif /* DEBUG_CONSISTENCY */
485 visited = val;
486 found = 0;
487 len = sys->subregions_visited.length;
488 if(len > 0) {
489 for (s=0; s<len; s++) {
490 sID = sys->subregions_visited.visited[s];
491 if(visited == sID) {
492 found = 1;
493 break;
494 }
495 }
496 }
497
498 sv = &(sys->subregions_visited);
499 append_sub_visited(sv,visited);
500
501 if(found == 0) {
502 #if DEBUG_CONSISTENCY
503 FPRINTF(ASCERR,"Saving alternative\n");
504 #endif /* DEBUG_CONSISTENCY */
505 sl = &(sys->subregion_list);
506 append_subregion(sl,(*sub));
507 }else{
508 destroy_array(sub->bool_values);
509 ascfree(sub);
510 }
511
512 return;
513 }
514 #endif
515
516 /*
517 * Destroys subregion information
518 */
519 static
520 void destroy_subregion_information(SlvClientToken asys){
521 slv9_system_t sys;
522 struct subregionID *sub;
523 int32 lens, s;
524
525 sys = SLV9(asys);
526 check_system(sys);
527
528 if(sys->subregions_visited.visited != NULL) {
529 destroy_array(sys->subregions_visited.visited);
530 }
531
532 lens = sys->subregion_list.length;
533 if(lens != 0) {
534 for (s=0; s<lens; s++) {
535 sub = &(sys->subregion_list.sub_stack[s]);
536 if(sub->bool_values != NULL) {
537 destroy_array(sub->bool_values);
538 }
539 }
540 }
541
542 if(sys->subregion_list.sub_stack != NULL) {
543 destroy_array(sys->subregion_list.sub_stack);
544 }
545
546 if(sys->bool_mindex != NULL) {
547 destroy_array(sys->bool_mindex);
548 }
549 }
550
551
552 #if 0 /** unused function eligible_set_for_neighboring_subregions */
553 /* might be used if DEBUG_CONSISTENCY on */
554
555 /*
556 * Storing original values of boolean variables
557 */
558 static void store_original_bool_values(struct gl_list_t *bollist,
559 struct boolean_values *bval)
560 {
561 struct dis_discrete *dvar;
562 int32 d, dlen;
563
564 dlen = gl_length(bollist);
565 bval->pre_val = create_array(dlen,int32);
566 bval->cur_val = create_array(dlen,int32);
567 for (d=1; d<=dlen; d++){
568 dvar = (struct dis_discrete *)gl_fetch(bollist,d);
569 bval->cur_val[d-1] = dis_value(dvar);
570 bval->pre_val[d-1] = dis_previous_value(dvar);
571 }
572 }
573
574 /*
575 * Restoring original values of boolean variables
576 */
577 static void restore_original_bool_values(struct gl_list_t *bollist,
578 struct boolean_values *bval)
579 {
580 struct dis_discrete *dvar;
581 int32 d, dlen;
582
583 dlen = gl_length(bollist);
584 for (d=1; d<=dlen; d++){
585 dvar = (struct dis_discrete *)gl_fetch(bollist,d);
586 dis_set_boolean_value(dvar,bval->cur_val[d-1]);
587 dis_set_value(dvar,bval->cur_val[d-1]);
588 dis_set_previous_value(dvar,bval->pre_val[d-1]);
589 }
590 destroy_array(bval->cur_val);
591 destroy_array(bval->pre_val);
592 }
593
594 #endif /* if 0 */
595
596 /*
597 * the first element of cur_cases is in position one. The result is
598 * the same array, but ordered and starting in position zero
599 */
600 static
601 void cases_reorder(int32 *cur_cases, int32 *correct_cases, int32 ncases){
602 int32 cur_case,pos=0,tmp_num,c,ind;
603
604 for (c=1; c<=ncases; c++) {
605 tmp_num = 0;
606 for (ind=1; ind<=ncases; ind++) {
607 cur_case = cur_cases[ind];
608 if(tmp_num < cur_case) {
609 pos = ind;
610 tmp_num = cur_case;
611 }
612 }
613 cur_cases[pos] = 0;
614 correct_cases[ncases-c] = tmp_num;
615 }
616
617 return;
618 }
619
620 #if 0 /** unused function eligible_set_for_neighboring_subregions */
621 /* might appear if debug_consistency is true. */
622 /*
623 * Restoring orignal configuration of the system
624 */
625 static void restore_configuration(slv_system_t server,
626 struct gl_list_t *bollist)
627
628 {
629 int32 *cur_cases, *correct_cases;
630 int32 ncases;
631
632 cur_cases = cases_matching(bollist,&ncases);
633 correct_cases = create_array(ncases,int32);
634 cases_reorder(cur_cases,correct_cases,ncases);
635 set_active_rels_in_subregion(server,correct_cases,ncases,bollist);
636 set_active_vars_in_subregion(server);
637 destroy_array(cur_cases);
638 destroy_array(correct_cases);
639 }
640
641
642 /*
643 * Get the list of boolean variables in the problem which are
644 * associated with a WHEN
645 */
646 static struct gl_list_t *get_list_of_booleans(slv_system_t server,
647 SlvClientToken asys)
648 {
649 slv9_system_t sys;
650 struct dis_discrete **bvlist;
651 struct dis_discrete *cur_dis;
652 struct gl_list_t *boolvars;
653 dis_filter_t dfilter;
654 int32 numdvf, numdvs, d, dcount;
655
656 sys = SLV9(asys);
657 check_system(sys);
658
659 bvlist = sys->mdvlist;
660 if(bvlist == NULL ) {
661 FPRINTF(ASCERR,"ERROR: (slv9) get_list_of_booleans.\n");
662 FPRINTF(ASCERR," Master discrete var list was never set.\n");
663 return NULL;
664 }
665 numdvs = slv_get_num_master_dvars(server);
666
667 dfilter.matchbits = (DIS_INWHEN | DIS_BOOLEAN);
668 dfilter.matchvalue = (DIS_INWHEN | DIS_BOOLEAN);
669 numdvf = slv_count_master_dvars(server,&dfilter);
670
671 if(numdvf == 0) {
672 FPRINTF(ASCERR,"ERROR: (slv9) get_list_of_booleans.\n");
673 FPRINTF(ASCERR," No boolean variables in the problem \n");
674 return NULL;
675 }
676
677 sys->bool_mindex = (int32 *)(ascmalloc(numdvf*sizeof(int32)));
678 boolvars = gl_create(numdvf);
679
680 dcount = 0;
681 for (d=0; d<numdvs; d++) {
682 cur_dis = bvlist[d];
683 if(dis_apply_filter(cur_dis,&(dfilter))) {
684 gl_append_ptr(boolvars,cur_dis);
685 sys->bool_mindex[dcount] = d;
686 dcount++;
687 }
688 }
689
690 return boolvars;
691 }
692
693 #endif /* 0*/
694
695 /*
696 * Get the eligible var list for each alternative
697 * Return:
698 * 1 means everything went right
699 * 0 means the analysis has failed with the current parititioning
700 * -1 means a memory problem has occurred
701 */
702 static
703 int32 get_eligible_set(slv_system_t server,struct gl_list_t *disvars,
704 int32 *terminate
705 ){
706 struct var_variable **vslist;
707 struct var_variable **vmlist;
708 struct var_variable *mvar, *svar;
709 var_filter_t vfilter;
710 int32 *cur_cases;
711 int32 *correct_cases;
712 int32 *vars;
713 int32 v, count=0, ind;
714 int32 ncases;
715 int32 mnum;
716 int32 status,dof;
717
718 vslist = slv_get_solvers_var_list(server);
719 vmlist = slv_get_master_var_list(server);
720 mnum = slv_get_num_master_vars(server);
721 for (v=0; v<mnum; v++) {
722 mvar = vmlist[v];
723 var_set_eligible_in_subregion(mvar,FALSE);
724 }
725
726 cur_cases = cases_matching(disvars,&ncases);
727 correct_cases = create_array(ncases,int32);
728 cases_reorder(cur_cases,correct_cases,ncases);
729 set_active_rels_in_subregion(server,correct_cases,ncases,disvars);
730 set_active_vars_in_subregion(server);
731 destroy_array(cur_cases);
732 destroy_array(correct_cases);
733
734 #if DEBUG_CONSISTENCY
735 FPRINTF(ASCERR,"Analyzing alternative:\n");
736 #endif /* DEBUG_CONSISTENCY */
737
738 if(!slvDOF_status(server,(&status),(&dof))) {
739 FPRINTF(ASCERR,"ERROR in combinatorial search\n");
740 FPRINTF(ASCERR,"Combinatorial search aborted\n");
741 return -1;
742 }else{
743 if(status == 3) {
744 #if DEBUG_CONSISTENCY
745 FPRINTF(ASCERR,"Alternative is structurally singular\n");
746 #endif /* DEBUG_CONSISTENCY */
747 (*terminate) = 0;
748 return 0;
749 }else{
750 if(status == 4) {
751 #if DEBUG_CONSISTENCY
752 FPRINTF(ASCERR,"Alternative is overspecified\n");
753 #endif /* DEBUG_CONSISTENCY */
754 (*terminate) = 0;
755 return 0;
756 }
757 }
758 }
759
760 if(status == 1) {
761 (*terminate) = 0;
762 #if DEBUG_CONSISTENCY
763 FPRINTF(ASCERR,"Alternative has % d degrees of freedom.\n", dof);
764
765 #endif /* DEBUG_CONSISTENCY */
766 if(slvDOF_eligible(server,&(vars))) {
767 count = 0;
768 while (vars[count] != -1) {
769 ind = vars[count];
770 svar = vslist[ind];
771 v = var_mindex(svar);
772 mvar = vmlist[v];
773 var_set_eligible_in_subregion(mvar,TRUE);
774 count++;
775 }
776 destroy_array(vars);
777 }
778 if(dof > count) {
779 #if DEBUG_CONSISTENCY
780 FPRINTF(ASCERR,
781 "Alternative does not have enough number of eligible vars\n");
782 #endif /* DEBUG_CONSISTENCY */
783 return 0;
784 }
785 }
786
787 if(status == 2) {
788 #if DEBUG_CONSISTENCY
789 FPRINTF(ASCERR,"Alternative is square.\n");
790 #endif /* DEBUG_CONSISTENCY */
791 }
792
793 vfilter.matchbits = (VAR_ACTIVE | VAR_INCIDENT | VAR_SVAR
794 | VAR_ELIGIBLE_IN_SUBREGION);
795 vfilter.matchvalue = (VAR_ACTIVE | VAR_INCIDENT | VAR_SVAR);
796
797 for (v=0; v<mnum; v++) {
798 mvar = vmlist[v];
799 if(var_apply_filter(mvar,&vfilter)) {
800 var_set_eligible(mvar,FALSE);
801 }
802 var_set_eligible_in_subregion(mvar,FALSE);
803 }
804
805 return 1;
806 }
807
808 /*
809 * Get the eligible set of variables for each of the alternatives generated
810 * by modifying the values of the boolean variables with the values stored
811 * during the solution process
812 * Return:
813 * 1 means everything went right
814 * 0 means the analysis has failed with the current partitioning
815 * -1 means a memory problem or wierdness has occurred
816 */
817 static
818 int32 do_search_alternatives(slv_system_t server, SlvClientToken asys,
819 struct gl_list_t *disvars,
820 int32 *terminate, int32 all_sub
821 ){
822 slv9_system_t sys;
823 struct dis_discrete *cur_dis;
824 struct subregionID *sub;
825 int32 *values = NULL;
826 int32 dlen, test;
827 int32 lens, lenv, v, s, d;
828 int32 result;
829 unsigned long visited, vID;
830
831
832 sys = SLV9(asys);
833
834 dlen = gl_length(disvars);
835 lenv = sys->subregions_visited.length;
836 lens = sys->subregion_list.length;
837
838 if(all_sub == 0) { /* current and previous subregion */
839 for (v=lenv-2; v<lenv; v++) {
840 test = 0;
841 vID = sys->subregions_visited.visited[v];
842 for (s=lens-1; s>=0; s--) {
843 sub = &(sys->subregion_list.sub_stack[s]);
844 visited = sub->ID_number;
845 if(vID == visited) {
846 values = sub->bool_values;
847 test = 1;
848 FPRINTF(ASCERR,"s = %d \n",s);
849 break;
850 }
851 }
852
853 if(test == 0) {
854 FPRINTF(ASCERR,"ERROR: (slv9) do_search_alternatives \n");
855 FPRINTF(ASCERR," subregion not found \n");
856 return -1;
857 }
858 #if DEBUG_CONSISTENCY
859 FPRINTF(ASCERR,"Alternative = %ul \n", vID);
860 #endif /* DEBUG_CONSISTENCY */
861 for (d=0; d<dlen; d++) {
862 assert(values != NULL); /* if null, test was 0 above and we returned, in theory */
863 cur_dis = (struct dis_discrete *)(gl_fetch(disvars,d+1));
864 if(values[d] == 1) {
865 dis_set_boolean_value(cur_dis,TRUE);
866 }else{
867 dis_set_boolean_value(cur_dis,FALSE);
868 }
869 }
870 result = get_eligible_set(server,disvars,terminate);
871 if(result != 1) {
872 return result;
873 }
874 }
875
876 }else{ /* all visited subregions */
877
878 for (s=lens-1; s>=0; s--) {
879 sub = &(sys->subregion_list.sub_stack[s]);
880 values = sub->bool_values;
881 vID = sub->ID_number;
882 #if DEBUG_CONSISTENCY
883 FPRINTF(ASCERR,"Alternative = %ul \n", vID);
884 #endif /* DEBUG_CONSISTENCY */
885 for (d=0; d<dlen; d++) {
886 cur_dis = (struct dis_discrete *)(gl_fetch(disvars,d+1));
887 if(values[d] == 1) {
888 dis_set_boolean_value(cur_dis,TRUE);
889 }else{
890 dis_set_boolean_value(cur_dis,FALSE);
891 }
892 }
893 result = get_eligible_set(server,disvars,terminate);
894 if(result != 1) {
895 return result;
896 }
897 }
898 }
899
900 return 1;
901 }
902
903
904 /*
905 * Perform consistency analysis for the visited/current-previous subregions.
906 * If all_subs is 1, the analysis takes in account all of the subregions
907 * visited by the solution algorithm at the current point if the solution
908 * procedure. If all_subs is 0, the analysis is only for the current
909 * and previous subregion.
910 */
911 static
912 int32 consistency(slv_system_t server, SlvClientToken asys,
913 struct gl_list_t *bollist,
914 int32 all_subs, int32 *terminate
915 ){
916 slv9_system_t sys;
917 struct var_variable **vmlist;
918 struct var_variable *mvar;
919 var_filter_t vfilter;
920 int32 *globeli = NULL;
921 int32 dlen;
922 int32 mnum, v, elnum;
923 int32 result;
924 int32 iter;
925
926 sys = SLV9(asys);
927 check_system(sys);
928
929 /*
930 * Initializing eligible bit for variables
931 */
932 vmlist = slv_get_master_var_list(server);
933 mnum = slv_get_num_master_vars(server);
934 for (v=0; v<mnum; v++) {
935 mvar = vmlist[v];
936 var_set_eligible(mvar,TRUE);
937 }
938
939 dlen = gl_length(bollist);
940
941 #if DEBUG_CONSISTENCY
942 FPRINTF(ASCERR,"S e a r c h i n g \n");
943 #endif /* DEBUG_CONSISTENCY */
944 result = do_search_alternatives(server,asys,bollist,terminate,all_subs);
945
946 if(result != 1) {
947 #if DEBUG_CONSISTENCY
948 FPRINTF(ASCERR,"returning failed search after S e a r c h \n");
949 #endif /* DEBUG_CONSISTENCY */
950 return result;
951 }
952
953 /*
954 * Getting the "globally" eligible variables
955 */
956 vfilter.matchbits = (VAR_INCIDENT | VAR_SVAR | VAR_ELIGIBLE | VAR_FIXED);
957 vfilter.matchvalue = (VAR_INCIDENT | VAR_SVAR | VAR_ELIGIBLE);
958 elnum = slv_count_master_vars(server,&vfilter);
959
960 if(elnum > 0) {
961 globeli = ASC_NEW_ARRAY(int32,elnum);
962 elnum = 0;
963 for (v=0; v<mnum; v++) {
964 mvar = vmlist[v];
965 if(var_apply_filter(mvar,&vfilter)) {
966 #if DEBUG_CONSISTENCY
967 FPRINTF(ASCERR,"Eligible index = %d \n",v);
968 #endif /* DEBUG_CONSISTENCY */
969 globeli[elnum] = v;
970 elnum++;
971 }
972 }
973 }
974
975 /*
976 * Recursively analysis
977 */
978
979 if((*terminate) == 1) {
980 if(elnum != 0) {
981 #if DEBUG_CONSISTENCY
982 FPRINTF(ASCERR,"All alternatives are square but the \n");
983 FPRINTF(ASCERR,"Eligible set is not null\n");
984 #endif /* DEBUG_CONSISTENCY */
985 destroy_array(globeli);
986 }
987 return 1;
988 }else{
989 if(elnum == 0) {
990 #if DEBUG_CONSISTENCY
991 FPRINTF(ASCERR,"No globally eligible variables to be fixed.\n");
992 #endif /* DEBUG_CONSISTENCY */
993 return 0;
994 }
995
996 for (v=0; v<elnum; v++) {
997 iter = 1;
998 mvar = vmlist[globeli[v]];
999 var_set_fixed(mvar,TRUE);
1000 var_set_potentially_fixed(mvar,TRUE);
1001 #if DEBUG_CONSISTENCY
1002 FPRINTF(ASCERR,"Fixing index = %d \n",globeli[v]);
1003 FPRINTF(ASCERR,"N e s t e d S e a r c h \n");
1004 #endif /* DEBUG_CONSISTENCY */
1005 result = consistency(server,asys,bollist,all_subs,&iter);
1006
1007 if(result != 1) {
1008 #if DEBUG_CONSISTENCY
1009 FPRINTF(ASCERR,"%d eliminated\n",globeli[v]);
1010 #endif /* DEBUG_CONSISTENCY */
1011 var_set_fixed(mvar,FALSE);
1012 var_set_potentially_fixed(mvar,FALSE);
1013 continue;
1014 }else{
1015 if(iter == 1) {
1016 (*terminate) = 1;
1017 #if DEBUG_CONSISTENCY
1018 FPRINTF(ASCERR,"%d Acepted \n",globeli[v]);
1019 #endif /* DEBUG_CONSISTENCY */
1020 destroy_array(globeli);
1021 return 1;
1022 }else{
1023 var_set_fixed(mvar,FALSE);
1024 var_set_potentially_fixed(mvar,FALSE);
1025 continue;
1026 }
1027 }
1028 }
1029 destroy_array(globeli);
1030 #if DEBUG_CONSISTENCY
1031 FPRINTF(ASCERR,"returning 0 after nested search\n");
1032 #endif /* DEBUG_CONSISTENCY */
1033 return 0;
1034 }
1035 }
1036
1037 #if 0 /** unused function eligible_set_for_neighboring_subregions */
1038 /* might appear if debug_consistency is true. */
1039
1040 /*
1041 * Get a set of globally eligible variables. Eligible for all the subregions
1042 * visited, or for the previous and current subregions.
1043 */
1044 static int32 get_globally_eligible(slv_system_t server, SlvClientToken asys,
1045 struct gl_list_t *bollist,
1046 int32 all_subs, int32 **eliset)
1047 {
1048 slv9_system_t sys;
1049 struct var_variable **vmlist;
1050 struct var_variable *mvar;
1051 var_filter_t vfilter;
1052 int32 dlen;
1053 int32 mnum, v, elnum;
1054 int32 terminate;
1055 int32 result;
1056
1057 sys = SLV9(asys);
1058 check_system(sys);
1059 /*
1060 * Initializing eligible bit for variables
1061 */
1062 vmlist = slv_get_master_var_list(server);
1063 mnum = slv_get_num_master_vars(server);
1064 for (v=0; v<mnum; v++) {
1065 mvar = vmlist[v];
1066 var_set_eligible(mvar,TRUE);
1067 }
1068
1069 dlen = gl_length(bollist);
1070
1071 /*
1072 * initializing
1073 */
1074 *eliset = NULL;
1075 terminate = 1;
1076
1077 #if DEBUG_CONSISTENCY
1078 FPRINTF(ASCERR,"S e a r c h i n g \n");
1079 #endif /* DEBUG_CONSISTENCY */
1080 result = do_search_alternatives(server,asys,bollist,&terminate,all_subs);
1081
1082 if(result != 1) {
1083 if(terminate == 0) {
1084 #if DEBUG_CONSISTENCY
1085 FPRINTF(ASCERR,"ERROR: some alternatives are either singular or\n");
1086 FPRINTF(ASCERR,"overspecified. All the alternatives have to be\n");
1087 FPRINTF(ASCERR,
1088 "either square or underspecified to complete the analysis\n");
1089 #endif /* DEBUG_CONSISTENCY */
1090 }
1091 return 0;
1092 }
1093
1094 /*
1095 * Getting the "globally" eligible variables
1096 */
1097 vfilter.matchbits = (VAR_INCIDENT | VAR_SVAR | VAR_ELIGIBLE | VAR_FIXED);
1098 vfilter.matchvalue = (VAR_INCIDENT | VAR_SVAR | VAR_ELIGIBLE);
1099 elnum = slv_count_master_vars(server,&vfilter);
1100
1101 *eliset = (int32 *)ascmalloc((elnum+1)*sizeof(int32));
1102 elnum = 0;
1103 for (v=0; v<mnum; v++) {
1104 mvar = vmlist[v];
1105 if(var_apply_filter(mvar,&vfilter)) {
1106 #if DEBUG_CONSISTENCY
1107 FPRINTF(ASCERR,"Eligible index = %d \n",v);
1108 FPRINTF(ASCERR,"Variable : \n");
1109 print_var_name(ASCERR,sys,mvar);
1110 #endif /* DEBUG_CONSISTENCY */
1111 (*eliset)[elnum] = v;
1112 elnum++;
1113 }
1114 }
1115 (*eliset)[elnum] = -1;
1116
1117 if(elnum == 0) {
1118 if(terminate == 0) {
1119 #if DEBUG_CONSISTENCY
1120 FPRINTF(ASCERR,
1121 "Some alternatives are underspecified, but there does\n");
1122 FPRINTF(ASCERR,"not exist a set of eligible variables consistent \n");
1123 FPRINTF(ASCERR,"with all the alternatives\n");
1124 #endif /* DEBUG_CONSISTENCY */
1125 }else{
1126 #if DEBUG_CONSISTENCY
1127 FPRINTF(ASCERR,"All alternatives are already square\n");
1128 #endif /* DEBUG_CONSISTENCY */
1129 }
1130 return 0;
1131 }else{
1132 if(terminate == 1) {
1133 #if DEBUG_CONSISTENCY
1134 FPRINTF(ASCERR,"All alternatives are square but the \n");
1135 FPRINTF(ASCERR,"Eligible set is not null\n");
1136 #endif /* DEBUG_CONSISTENCY */
1137 }
1138 }
1139 return 1;
1140 }
1141
1142
1143
1144 /*
1145 * Store and restore values of the boolean variables of the problem
1146 * and calls for the the set of globally eligible variables.If all_subs
1147 * is 1, the analysis takes in account all of the subregions visited
1148 * by the solution algorithm at the current point if the solution
1149 * procedure. If all_subs is 0, the analysis is only for the current
1150 * and previous subregion.
1151 */
1152 static
1153 int32 consistent_eligible_set_for_subregions(slv_system_t server,
1154 SlvClientToken asys,
1155 int32 **vlist,
1156 int32 all_subs
1157 ){
1158 struct gl_list_t *blist;
1159 struct boolean_values bval;
1160 int32 result;
1161
1162 if(server==NULL || vlist == NULL) {
1163 FPRINTF(ASCERR,
1164 "consistent_eligible_set_for_subregions called with NULL.\n");
1165 return 0;
1166 }
1167
1168 blist = get_list_of_booleans(server,asys);
1169
1170 if((blist == NULL) || (gl_length(blist) == 0) ) {
1171 FPRINTF(ASCERR,"ERROR: (slv9) consistent_eligible_set_for_subregions \n");
1172 FPRINTF(ASCERR," List of boolean vars could not be found\n");
1173 return 0;
1174 }
1175
1176 store_original_bool_values(blist,&(bval));
1177 result = get_globally_eligible(server,asys,blist,all_subs,vlist);
1178
1179 restore_original_bool_values(blist,&(bval));
1180 restore_configuration(server,blist);
1181 gl_destroy(blist);
1182
1183 if(result == 1) {
1184 return 1;
1185 }else{
1186 return 0;
1187 }
1188
1189 }
1190
1191 /*
1192 * Store and restore values of the boolean variables of the problem
1193 * and calls for the consistency analysis of the subregions.If all_subs
1194 * is 1, the analysis takes in account all of the subregions visited
1195 * by the solution algorithm at the current point if the solution
1196 * procedure. If all_subs is 0, the analysis is only for the current
1197 * and previous subregion.
1198 */
1199 static
1200 int32 analyze_subregions(slv_system_t server,SlvClientToken asys,
1201 int32 **vlist, int32 all_subs
1202 ){
1203 slv9_system_t sys;
1204 struct var_variable ** vmlist;
1205 struct var_variable *mvar;
1206 struct gl_list_t *blist;
1207 struct boolean_values bval;
1208 var_filter_t vfilter;
1209 int32 mnum, elnum, v;
1210 int32 result;
1211 int32 terminate;
1212
1213 sys = SLV9(asys);
1214 check_system(sys);
1215
1216 if(server==NULL || vlist == NULL) {
1217 FPRINTF(ASCERR,"(slv9) analyze_subregions called with NULL.\n");
1218 return 0;
1219 }
1220
1221 blist = get_list_of_booleans(server,asys);
1222 if((blist == NULL) || (gl_length(blist) == 0) ) {
1223 FPRINTF(ASCERR,"ERROR: (slv9) analyze_subregions \n");
1224 FPRINTF(ASCERR," List of boolean vars could not be found\n");
1225 return 0;
1226 }
1227
1228 store_original_bool_values(blist,&(bval));
1229 /*
1230 * initializing
1231 */
1232 terminate = 1;
1233 (*vlist) = NULL;
1234
1235 vmlist = slv_get_master_var_list(server);
1236 mnum = slv_get_num_master_vars(server);
1237
1238 vfilter.matchbits = (VAR_POTENTIALLY_FIXED);
1239 vfilter.matchvalue = (VAR_POTENTIALLY_FIXED);
1240
1241 result = consistency(server,asys,blist,all_subs,&terminate);
1242
1243 if(result == 1) {
1244 /*
1245 * Getting the set of eligible variables
1246 */
1247 elnum = slv_count_master_vars(server,&vfilter);
1248 *vlist = (int32 *)ascmalloc((elnum+1)*sizeof(int32));
1249 elnum = 0;
1250 for (v=0; v<mnum; v++) {
1251 mvar = vmlist[v];
1252 if(var_apply_filter(mvar,&vfilter)) {
1253 var_set_fixed(mvar,FALSE);
1254 var_set_potentially_fixed(mvar,FALSE);
1255 #if DEBUG_CONSISTENCY
1256 FPRINTF(ASCERR,"Variable in consistent set: \n");
1257 print_var_name(ASCERR,sys,mvar);
1258 #endif /* DEBUG_CONSISTENCY */
1259 (*vlist)[elnum] = v;
1260 elnum++;
1261 }
1262 }
1263 (*vlist)[elnum] = -1;
1264
1265 restore_original_bool_values(blist,&(bval));
1266 restore_configuration(server,blist);
1267 gl_destroy(blist);
1268 return 1;
1269 }else{
1270 for (v=0; v<mnum; v++) {
1271 mvar = vmlist[v];
1272 if(var_apply_filter(mvar,&vfilter)) {
1273 var_set_fixed(mvar,FALSE);
1274 var_set_potentially_fixed(mvar,FALSE);
1275 }
1276 }
1277 restore_original_bool_values(blist,&(bval));
1278 restore_configuration(server,blist);
1279 gl_destroy(blist);
1280 return 0;
1281 }
1282 }
1283
1284
1285 /*
1286 * Finds the globally eligible set of variables only for the current and
1287 * previous subregions
1288 */
1289 static
1290 int32 eligible_set_for_neighboring_subregions(slv_system_t server,
1291 SlvClientToken asys,
1292 int32 **vlist
1293 ){
1294 slv9_system_t sys;
1295
1296 sys = SLV9(asys);
1297 check_system(sys);
1298
1299 if(sys->mdvlist == NULL ) {
1300 FPRINTF(ASCERR,"ERROR: (slv9) eligible_set_for_neighboring_subregions\n");
1301 FPRINTF(ASCERR," Discrete Variable list was never set.\n");
1302 return 0;
1303 }
1304
1305 if(!(sys->need_consistency_analysis)) {
1306 FPRINTF(ASCERR,"Globally eligible set not necessary\n");
1307 FPRINTF(ASCERR,"All the subregions have the same structure \n");
1308 return 0;
1309 }
1310
1311 if(consistent_eligible_set_for_subregions(server,asys,vlist,0)) {
1312 return 1;
1313 }
1314
1315 return 0;
1316 }
1317
1318
1319 /*
1320 * Perform the consistency analysis algorithm only for the current and
1321 * previous subregions
1322 */
1323 static
1324 int32 consistency_for_neighboring_subregions(slv_system_t server,
1325 SlvClientToken asys,
1326 int32 **vlist
1327 ){
1328 slv9_system_t sys;
1329
1330 sys = SLV9(asys);
1331 check_system(sys);
1332
1333 if(sys->mdvlist == NULL ) {
1334 FPRINTF(ASCERR,"ERROR: (slv9) consistency_for_neighboring_subregions\n");
1335 FPRINTF(ASCERR," Discrete Variable list was never set.\n");
1336 return 0;
1337 }
1338
1339 if(!(sys->need_consistency_analysis)) {
1340 FPRINTF(ASCERR,"consistency_analysis is not required\n");
1341 FPRINTF(ASCERR,"All the subregions have the same structure \n");
1342 return 0;
1343 }
1344
1345 if(analyze_subregions(server,asys,vlist,0)) {
1346 return 1;
1347 }
1348
1349 return 0;
1350 }
1351
1352
1353
1354 /*
1355 * Consistency analysis for visisted subregions. This function
1356 * gets the subregions that the solution algorithm has visited and
1357 * analyzes them.
1358 */
1359 static
1360 int32 eligible_set_for_subregions(slv_system_t server,
1361 SlvClientToken asys,
1362 int32 **vlist
1363 ){
1364 slv9_system_t sys;
1365
1366 sys = SLV9(asys);
1367 check_system(sys);
1368
1369 if(sys->mdvlist == NULL ) {
1370 FPRINTF(ASCERR,"ERROR: (slv9) eligible_set_for_subregions \n");
1371 FPRINTF(ASCERR," Discrete Variable list was never set.\n");
1372 return 0;
1373 }
1374
1375 if(!(sys->need_consistency_analysis)) {
1376 FPRINTF(ASCERR,"Globally eligible set not necessary \n");
1377 FPRINTF(ASCERR,"All the subregions have the same structure \n");
1378 return 0;
1379 }
1380
1381 if(consistent_eligible_set_for_subregions(server,asys,vlist,1)) {
1382 return 1;
1383 }
1384
1385 return 0;
1386 }
1387
1388
1389 /*
1390 * Consistency analysis for visisted subregions. This function
1391 * gets the subregions that the solution algorithm has visited and
1392 * analyzes them.
1393 */
1394 static
1395 int32 consistency_analysis_for_subregions(slv_system_t server,
1396 SlvClientToken asys,
1397 int32 **vlist
1398 ){
1399 slv9_system_t sys;
1400
1401 sys = SLV9(asys);
1402 check_system(sys);
1403
1404 if(sys->mdvlist == NULL ) {
1405 FPRINTF(ASCERR,"ERROR: (slv9) consistency_analysis_for_subregions\n");
1406 FPRINTF(ASCERR," Discrete Variable list was never set.\n");
1407 return 0;
1408 }
1409
1410 if(!(sys->need_consistency_analysis)) {
1411 FPRINTF(ASCERR,"consistency_analysis is not required\n");
1412 FPRINTF(ASCERR,"All the subregions have the same structure \n");
1413 return 0;
1414 }
1415
1416 if(analyze_subregions(server,asys,vlist,1)) {
1417 return 1;
1418 }
1419
1420 return 0;
1421 }
1422
1423 #endif /*#if 0 unused functions */
1424
1425
1426 /*
1427 * Handling of solution of the Logical Equations
1428 * ---------------------------------------------------------
1429 * This is made this way because it is a process which will be
1430 * required very often.
1431 */
1432
1433 /*
1434 * Solution of the logical relations encountered in the system based on
1435 * the current values of the discrete variables.
1436 */
1437 static
1438 void solve_logical_relations(slv_system_t server){
1439 slv_set_client_token(server,token[LOGICAL_SOLVER]);
1440 slv_set_solver_index(server,solver_index[LOGICAL_SOLVER]);
1441 slv_presolve(server);
1442 #if SHOW_LOGICAL_DETAILS
1443 FPRINTF(ASCERR,"Solving Logical Relations\n");
1444 #endif /* SHOW_LOGICAL_DETAILS */
1445 slv_solve(server);
1446 }
1447
1448
1449
1450 /*
1451 * Handling the modification of parameters in external solvers
1452 * ---------------------------------------------------------
1453 */
1454
1455 /*
1456 * different types of parameter values
1457 */
1458 union param_value {
1459 int32 i;
1460 real64 r;
1461 int32 b;
1462 char *c;
1463 };
1464
1465
1466 /*
1467 * Setting the value of a parameter in a subsidiary solver
1468 */
1469 static
1470 void set_param_in_solver(slv_system_t server, int32 solver,
1471 enum parm_type types, char *param,
1472 union param_value *value
1473 ){
1474 slv_parameters_t p;
1475 int32 len,length;
1476 SlvClientToken origtoken = slv_get_client_token(server);
1477
1478 slv_set_client_token(server,token[solver]);
1479 slv_set_solver_index(server,solver_index[solver]);
1480 slv_get_parameters(server,&p);
1481 length = p.num_parms;
1482 for (len = 0; len < length; len++) {
1483 if(p.parms[len].type == types) {
1484 switch (p.parms[len].type) {
1485 case bool_parm:
1486 if(strcmp(param,p.parms[len].name) == 0) {
1487 p.parms[len].info.b.value = value->b;
1488 }
1489 break;
1490 case real_parm:
1491 if(strcmp(param,p.parms[len].name) == 0) {
1492 p.parms[len].info.r.value = value->r;
1493 }
1494 break;
1495 case char_parm:
1496 if(strcmp(param,p.parms[len].name) == 0) {
1497 p.parms[len].info.c.value = value->c;
1498 }
1499 break;
1500 case int_parm:
1501 if(strcmp(param,p.parms[len].name) == 0) {
1502 p.parms[len].info.i.value = value->i;
1503 }
1504 break;
1505 default:
1506 break;
1507 }
1508 }
1509 }
1510
1511 /* return to original state */
1512 slv_set_solver_index(server,SOLVER_CMSLV);
1513 slv_set_client_token(server,origtoken);
1514
1515 return;
1516 }
1517
1518
1519 /*
1520 * Analysis of Discrete Variables
1521 * -------------------------------
1522 */
1523
1524 /*
1525 * Compare current values of the discrete variables with their previous values
1526 * in order to know if some of them have changed.
1527 */
1528 static
1529 int32 some_dis_vars_changed(slv_system_t server, SlvClientToken asys){
1530 struct dis_discrete **dv, *cur_dis;
1531 int32 numdvs, ind;
1532 slv9_system_t sys;
1533
1534 sys = SLV9(asys);
1535 check_system(sys);
1536
1537 if(sys->dvlist == NULL ) {
1538 FPRINTF(ASCERR,"ERROR: (slv9) some_dis_vars_changed\n");
1539 FPRINTF(ASCERR," Discrete variable list was never set.\n");
1540 return 0;
1541 }
1542
1543 dv = sys->dvlist;
1544 numdvs = slv_get_num_solvers_dvars(server);
1545 for( ind = 0; ind < numdvs; ind++ ) {
1546 cur_dis = dv[ind];
1547 #if SHOW_LOGICAL_DETAILS
1548 FPRINTF(ASCERR,"Boundary index = %d \n",ind);
1549 FPRINTF(ASCERR,"Current Value = %d\n",dis_value(cur_dis));
1550 FPRINTF(ASCERR,"Previous Value = %d\n",dis_previous_value(cur_dis));
1551 #endif /* SHOW_LOGICAL_DETAILS */
1552 if((dis_kind(cur_dis)==e_dis_boolean_t ) && dis_inwhen(cur_dis) ) {
1553 if(dis_value(cur_dis) != dis_previous_value(cur_dis)) {
1554 return 1;
1555 }
1556 }
1557 }
1558 return 0;
1559 }
1560
1561 /*
1562 * Compare the original value of a discrete boolean variable (before
1563 * perturbation of boundaries) with its values after a solution
1564 * of the logical relations with some perturbed values for boundaries.
1565 * If those values are different, the bit VAL_MODIFIED is set to
1566 * TRUE. This will give us the boolean variable which will change as a
1567 * consequence of a boundary crossing.
1568 */
1569 static
1570 void search_for_modified_dvars(struct dis_discrete **dv,
1571 int32 numdvs,
1572 struct boolean_values *bval
1573 ){
1574 struct dis_discrete *cur_dis;
1575 int32 d;
1576 int32 orig_value;
1577
1578 for (d=0; d<numdvs; d++) {
1579 cur_dis = dv[d];
1580 if(dis_inwhen(cur_dis) && dis_boolean(cur_dis)) {
1581 orig_value = bval->cur_val[d];
1582 if(orig_value != dis_value(cur_dis)) {
1583 dis_set_val_modified(cur_dis,TRUE);
1584 }
1585 }
1586 }
1587 }
1588
1589
1590 /*
1591 * Analysis of Boundaries
1592 * ----------------------------
1593 */
1594
1595 /*
1596 * Evaluates the current status (satisfied? , at zero?) of a boundary
1597 * and sets its flags accordingly. At the same time, it updates the
1598 * residual of the relation included in the boundary (see
1599 * bndman_calc_satisfied).
1600 */
1601
1602 static
1603 void update_boundaries(slv_system_t server, SlvClientToken asys){
1604 struct bnd_boundary **bp;
1605 int32 numbnds, ind, value;
1606 slv9_system_t sys;
1607
1608 sys = SLV9(asys);
1609 check_system(sys);
1610
1611 if(sys->blist == NULL ) {
1612 FPRINTF(ASCERR,"ERROR: (slv9) update_boundaries.\n");
1613 FPRINTF(ASCERR," Boundary list was never set.\n");
1614 return;
1615 }
1616
1617 bp = sys->blist;
1618 numbnds = slv_get_num_solvers_bnds(server);
1619
1620 for( ind = 0; ind < numbnds; ++ind ) {
1621 value = bnd_status_cur(bp[ind]);
1622 bnd_set_pre_status(bp[ind],value);
1623 value = bndman_calc_satisfied(bp[ind]);
1624 bnd_set_cur_status(bp[ind],value);
1625 if((bnd_status_cur(bp[ind]) != bnd_status_pre(bp[ind])) &&
1626 bnd_kind(bp[ind]) == e_bnd_rel && !bnd_at_zero(bp[ind])) {
1627 bnd_set_crossed(bp[ind],TRUE);
1628 }else{
1629 bnd_set_crossed(bp[ind],FALSE);
1630 }
1631 if(bnd_kind(bp[ind]) == e_bnd_rel) {
1632 value = bndman_calc_at_zero(bp[ind]);
1633 bnd_set_at_zero(bp[ind],value);
1634 }else{
1635 bnd_set_at_zero(bp[ind],FALSE);
1636 }
1637 }
1638 }
1639
1640
1641 /*
1642 * Look for some boundary with the CROSSED bit active. If this boundary
1643 * is used in some logical relation, the function returns 1, else returns 0
1644 */
1645 static
1646 int32 some_boundaries_crossed(slv_system_t server, SlvClientToken asys){
1647 struct bnd_boundary **bp, *cur_bnd;
1648 int32 numbnds, ind;
1649 slv9_system_t sys;
1650
1651 sys = SLV9(asys);
1652 check_system(sys);
1653
1654 if(sys->blist == NULL ) {
1655 FPRINTF(ASCERR,"ERROR: (slv9) some_boundaries_crossed\n");
1656 FPRINTF(ASCERR," Boundary list was never set.\n");
1657 return 0;
1658 }
1659
1660 bp = sys->blist;
1661 numbnds = slv_get_num_solvers_bnds(server);
1662 for( ind = 0; ind < numbnds; ++ind ) {
1663 cur_bnd = bp[ind];
1664 if(bnd_crossed(cur_bnd) && bnd_in_logrel(cur_bnd)) {
1665 return 1;
1666 }
1667 }
1668 return 0;
1669 }
1670
1671 /*
1672 * Look for some boundary with the AT_ZERO bit active.If this boundary
1673 * is used in some logical relation, the function returns 1, else returns 0
1674 */
1675 static
1676 int32 some_boundaries_at_zero(slv_system_t server, SlvClientToken asys){
1677 struct bnd_boundary **bp, *cur_bnd;
1678 int32 numbnds, ind;
1679 slv9_system_t sys;
1680
1681 sys = SLV9(asys);
1682 check_system(sys);
1683
1684 if(sys->blist == NULL ) {
1685 FPRINTF(ASCERR,"ERROR: (slv9) some_boundaries_at_zero\n");
1686 FPRINTF(ASCERR," Boundary list was never set.\n");
1687 return 0;
1688 }
1689
1690 bp = sys->blist;
1691 numbnds = slv_get_num_solvers_bnds(server);
1692 for( ind = 0; ind < numbnds; ++ind ) {
1693 cur_bnd = bp[ind];
1694 if(bnd_at_zero(cur_bnd) && bnd_in_logrel(cur_bnd)) {
1695 return 1;
1696 }
1697 }
1698 return 0;
1699 }
1700
1701 /*
1702 * Perform the combinatorial perturbation of the boundaries which are
1703 * at their zero. That means: We are going to perform a combinatorial
1704 * search, changing the truth value of a SATISFIED term (for the
1705 * specified boundaries) ON and OFF, and finding the boolean variables
1706 * affected for those changes in value of the SATISFIED terms.
1707 */
1708 static
1709 void do_perturbation_combinations(slv_system_t server,
1710 struct boolean_values *bval,
1711 struct bnd_boundary **bp,
1712 struct dis_discrete **dv,
1713 int32 numdvs,int32 *bndatzero,
1714 int32 ind, int32 numbndf
1715 ){
1716 slv_status_t status;
1717 int32 indpo;
1718
1719 if(ind<(numbndf-1)) {
1720 indpo = ind + 1;
1721 bnd_set_perturb(bp[bndatzero[ind]],TRUE);
1722 do_perturbation_combinations(server,bval,bp,dv,numdvs,
1723 bndatzero,indpo,numbndf);
1724 bnd_set_perturb(bp[bndatzero[ind]],FALSE);
1725 do_perturbation_combinations(server,bval,bp,dv,numdvs,
1726 bndatzero,indpo,numbndf);
1727 }else{
1728 if(ind < numbndf) {
1729 bnd_set_perturb(bp[bndatzero[ind]],TRUE);
1730 solve_logical_relations(server);
1731 slv_get_status(server,&status);
1732 if(!status.converged) {
1733 FPRINTF(ASCERR,"WARNING: \n");
1734 FPRINTF(ASCERR,"(slv9) do_perturbation_combinations\n");
1735 FPRINTF(ASCERR," Not convergence in logical solver \n");
1736 }else{
1737 search_for_modified_dvars(dv,numdvs,bval);
1738 }
1739 bnd_set_perturb(bp[bndatzero[ind]],FALSE);
1740 solve_logical_relations(server);
1741 slv_get_status(server,&status);
1742 if(!status.converged) {
1743 FPRINTF(ASCERR,"WARNING: \n");
1744 FPRINTF(ASCERR,"(slv9) do_perturbation_combinations\n");
1745 FPRINTF(ASCERR," Not convergence in logical solver \n");
1746 }else{
1747 search_for_modified_dvars(dv,numdvs,bval);
1748 }
1749 }else{
1750 FPRINTF(ASCERR,"ERROR: (slv9) do_perturbation_combinations\n");
1751 FPRINTF(ASCERR," Wrong boundary index as argument\n");
1752 }
1753 }
1754 return;
1755 }
1756
1757
1758 /*
1759 * Perform the combinatorial search of the subregions. That means:
1760 * We perform a combinatorial search, changing the value of the
1761 * discrete variables (given in disvars) TRUE and FALSE, and
1762 * finding which cases (in the WHENs) applies for each of the
1763 * combinations.
1764 */
1765 static
1766 void do_dvar_values_combinations(struct gl_list_t *disvars,
1767 struct matching_cases *cases,
1768 int numdvf, int d,
1769 int *pos_cases
1770 ){
1771 struct dis_discrete *cur_dis;
1772 int32 *cur_cases;
1773 int32 ncases, dpo;
1774
1775 if(d < numdvf) {
1776 dpo = d + 1;
1777 cur_dis = (struct dis_discrete *)(gl_fetch(disvars,d));
1778 dis_set_boolean_value(cur_dis,TRUE);
1779 do_dvar_values_combinations(disvars,cases,numdvf,dpo,pos_cases);
1780 dis_set_boolean_value(cur_dis,FALSE);
1781 do_dvar_values_combinations(disvars,cases,numdvf,dpo,pos_cases);
1782 }else{
1783 if(d == numdvf) {
1784 cur_dis = (struct dis_discrete *)(gl_fetch(disvars,d));
1785 dis_set_boolean_value(cur_dis,TRUE);
1786 cur_cases = cases_matching(disvars,&ncases);
1787 cases[(*pos_cases)].case_list = cur_cases;
1788 cases[(*pos_cases)].ncases = ncases;
1789 cases[(*pos_cases)].diff_subregion = 1;
1790 (*pos_cases)++;
1791 dis_set_boolean_value(cur_dis,FALSE);
1792 cur_cases = cases_matching(disvars,&ncases);
1793 cases[(*pos_cases)].case_list = cur_cases;
1794 cases[(*pos_cases)].ncases = ncases;
1795 cases[(*pos_cases)].diff_subregion = 1;
1796 (*pos_cases)++;
1797 }else{
1798 FPRINTF(ASCERR,"ERROR: (slv9) do_dvar_values_combinations\n");
1799 FPRINTF(ASCERR," Wrong discrete var index as argument\n");
1800 }
1801 }
1802 return;
1803 }
1804
1805
1806 /*
1807 * Orders of the elements of each array of cases,
1808 * so that we can compare them easier.
1809 */
1810 static
1811 void order_case(int32 *case_list, int32 *newcaselist, int ncases){
1812 int32 cur_case,pos=0,tmp_num,c,ind;
1813
1814 for (c=1; c<=ncases; c++) {
1815 tmp_num = 0;
1816 for (ind=1; ind<=ncases; ind++) {
1817 cur_case = case_list[ind];
1818 if(tmp_num < cur_case) {
1819 pos = ind;
1820 tmp_num = cur_case;
1821 }
1822 }
1823 case_list[pos] = 0;
1824 newcaselist[ncases-c] = tmp_num;
1825 }
1826 }
1827
1828
1829
1830 /*
1831 * Calls for the ordering of the elements of each array of cases,
1832 * so that we can compare them easier.
1833 */
1834 static
1835 void order_cases(struct matching_cases *cases,int pos_cases){
1836 int32 *caselist;
1837 int32 cur_ncase,c;
1838 int32 *newcaselist;
1839
1840 for (c=0; c<pos_cases;c++) {
1841 caselist = cases[c].case_list;
1842 cur_ncase = cases[c].ncases;
1843 if(cur_ncase > 1) {
1844 newcaselist = create_array(cur_ncase,int32);
1845 order_case(caselist,newcaselist,cur_ncase);
1846 cases[c].case_list = newcaselist;
1847 destroy_array(caselist);
1848 }else{
1849 if(cur_ncase == 1) {
1850 newcaselist = create_array(1,int32);
1851 newcaselist[0] = caselist[1];
1852 cases[c].case_list = newcaselist;
1853 destroy_array(caselist);
1854 }
1855 }
1856 }
1857
1858 }
1859
1860
1861
1862 /*
1863 * Compare two arrays of cases (integer numbers). It returns 1 if they are
1864 * equal, else it returns 0.
1865 */
1866 static
1867 int32 compare_case(int32 *cur_set, int32 *comp_set, int cur_ncases){
1868 int32 cur_case, comp_case, ind;
1869
1870 for (ind=0; ind<cur_ncases; ind++) {
1871 cur_case = cur_set[ind];
1872 comp_case = comp_set[ind];
1873 if(cur_case != comp_case) {
1874 return 0;
1875 }
1876 }
1877 return 1;
1878 }
1879
1880
1881 /*
1882 * Compare the arrays of cases so that we can find the number of
1883 * different alternatives (subregions)
1884 */
1885 static
1886 void compare_cases(struct matching_cases *cases,int pos_cases){
1887 int32 *cur_set, *comp_set, cur_ncases, comp_ncases;
1888 int32 c,d;
1889
1890 for (c=0; c<pos_cases; c++) {
1891 cur_set = cases[c].case_list;
1892 cur_ncases = cases[c].ncases;
1893 if(cur_ncases == 0) {
1894 cases[c].diff_subregion = 0;
1895 continue;
1896 }
1897 for(d=0; d<c; d++) {
1898 comp_set = cases[d].case_list;
1899 comp_ncases = cases[d].ncases;
1900 if(cur_ncases != comp_ncases) {
1901 continue;
1902 }else{
1903 if(compare_case(cur_set,comp_set,cur_ncases)) {
1904 cases[c].diff_subregion = 0;
1905 break;
1906 }
1907 }
1908 }
1909 }
1910 }
1911
1912
1913 /*
1914 * Finds if my current point lies at a "real" boundary. By "real"
1915 * I mean a boundary which really causes a change in the
1916 * configuration. It returns 0 if the boundary at zero does not
1917 * affect the configuration. If the configuration is affected,
1918 * this function will find the number of subregions existing
1919 * for the current point as well as the cases (in WHENs) corresponding
1920 * to each of the subregions. At the end, the number of subregions is
1921 * n_subregions and the cases applying for each of them is stored
1922 * in the structure subregions.
1923 */
1924 static
1925 int32 at_a_boundary(slv_system_t server, SlvClientToken asys,
1926 int32 *n_subregions,
1927 struct matching_cases **subregions,
1928 int32 *cur_subregion,
1929 struct gl_list_t *disvars
1930 ){
1931 slv9_system_t sys;
1932 struct bnd_boundary **bp, *cur_bnd;
1933 struct dis_discrete **dv, *cur_dis;
1934 struct boolean_values bval;
1935 dis_filter_t dfilter;
1936 bnd_filter_t bfilter;
1937 struct matching_cases *cases;
1938 int32 *bndatzero;
1939 int32 *dvarmodified;
1940 int32 *cur_cases;
1941 int32 *caselist, *newcaselist;
1942 int32 numbnds, numbndf, b, ind;
1943 int32 numdvs, numdvf, d;
1944 int32 cur_ncases, assign_cur_sub;
1945 int32 pos_cases, comb;
1946 char *param;
1947 union param_value u;
1948
1949 sys = SLV9(asys);
1950 check_system(sys);
1951
1952 if(sys->blist == NULL ) {
1953 FPRINTF(ASCERR,"ERROR: (slv9) at_a_boundary\n");
1954 FPRINTF(ASCERR," Boundary list was never set.\n");
1955 return 0;
1956 }
1957
1958 if(sys->dvlist == NULL ) {
1959 FPRINTF(ASCERR,"ERROR: (slv9) at_a_boundary\n");
1960 FPRINTF(ASCERR," Discrete Variable list was never set.\n");
1961 return 0;
1962 }
1963
1964 if(!some_boundaries_at_zero(server,asys)) {
1965 return 0;
1966 }
1967
1968 bp = sys->blist;
1969 numbnds = slv_get_num_solvers_bnds(server);
1970 bfilter.matchbits = (BND_AT_ZERO);
1971 bfilter.matchvalue = (BND_AT_ZERO);
1972 numbndf = slv_count_solvers_bnds(server,&bfilter);
1973 bndatzero = create_array(numbndf,int32);
1974 ind = 0;
1975 for (b=0; b<numbnds; b++) {
1976 cur_bnd = bp[b];
1977 bnd_set_perturb(cur_bnd,FALSE);
1978 if(bnd_at_zero(cur_bnd)) {
1979 #if SHOW_BOUNDARY_ANALYSIS_DETAILS
1980 FPRINTF(ASCERR,"boundary at zero = %d\n",b);
1981 #endif /* SHOW_BOUNDARY_ANALYSIS_DETAILS */
1982 bndatzero[ind] = b;
1983 ind++;
1984 }
1985 }
1986
1987 dv = sys->dvlist;
1988 numdvs = slv_get_num_solvers_dvars(server);
1989 bval.cur_val = create_array(numdvs,int32);
1990 bval.pre_val = create_array(numdvs,int32);
1991
1992 for (d=0; d<numdvs; d++) {
1993 cur_dis = dv[d];
1994 dis_set_val_modified(cur_dis,FALSE);
1995 bval.cur_val[d] = dis_value(cur_dis);
1996 bval.pre_val[d] = dis_previous_value(cur_dis);
1997 }
1998
1999 #if SHOW_BOUNDARY_ANALYSIS_DETAILS
2000 FPRINTF(ASCERR,"Executing combinatorial perturbation of boundaries\n");
2001 #endif /* SHOW_BOUNDARY_ANALYSIS_DETAILS */
2002
2003 /*
2004 * Setting the value of the perturbation mode flag in the logical solver
2005 * to 1.
2006 * PERTURB_BOUNDARY is a boolean parameter of the logical solver
2007 * LRSlv. This parameter tells the solver whether it should change
2008 * the truth value of the SATISFIED terms or not (only for the
2009 * boundaries specified). This trick is important while finding
2010 * the number of subregions around a/several boundary(ies).
2011 */
2012 param = "perturbboundaries";
2013 u.b = 1;
2014 set_param_in_solver(server,LOGICAL_SOLVER,bool_parm,param,&u);
2015
2016 ind = 0;
2017 do_perturbation_combinations(server,&(bval),bp,dv,numdvs,
2018 bndatzero,ind,numbndf);
2019 /*
2020 * Setting the value of the perturbation mode flag in the logical solver
2021 * to 0.
2022 */
2023 u.b = 0;
2024 set_param_in_solver(server,LOGICAL_SOLVER,bool_parm,param,&u);
2025
2026 destroy_array(bndatzero);
2027
2028 dfilter.matchbits = (DIS_VAL_MODIFIED);
2029 dfilter.matchvalue = (DIS_VAL_MODIFIED);
2030 numdvf = slv_count_solvers_dvars(server,&dfilter);
2031
2032 if(numdvf == 0) {
2033 FPRINTF(ASCERR,"Not really at a boundary\n");
2034 for (d=0; d<numdvs; d++) {
2035 cur_dis = dv[d];
2036 dis_set_boolean_value(cur_dis,bval.cur_val[d]);
2037 dis_set_value(cur_dis,bval.cur_val[d]);
2038 dis_set_previous_value(cur_dis,bval.pre_val[d]);
2039 }
2040 destroy_array(bval.cur_val);
2041 destroy_array(bval.pre_val);
2042 return 0;
2043 }
2044
2045 dvarmodified = create_array(numdvf,int32);
2046 ind = 0;
2047 for (d=0; d<numdvs; d++) {
2048 cur_dis = dv[d];
2049 if(dis_val_modified(cur_dis)) {
2050 dvarmodified[ind] = d;
2051 gl_append_ptr(disvars,cur_dis);
2052 dis_set_val_modified(cur_dis,FALSE);
2053 ind++;
2054 }
2055 }
2056
2057 for (d=0; d<numdvs; d++) {
2058 cur_dis = dv[d];
2059 dis_set_boolean_value(cur_dis,bval.cur_val[d]);
2060 dis_set_value(cur_dis,bval.cur_val[d]);
2061 dis_set_previous_value(cur_dis,bval.pre_val[d]);
2062 }
2063
2064 pos_cases = 1;
2065 for (d = 1; d<=numdvf; d++) {
2066 pos_cases = pos_cases * 2;
2067 }
2068
2069 cases = (struct matching_cases *)
2070 (ascmalloc((pos_cases)*sizeof(struct matching_cases)));
2071
2072 #if SHOW_BOUNDARY_ANALYSIS_DETAILS
2073 FPRINTF(ASCERR,"Executing combinatorial search for subregions \n");
2074 #endif /* SHOW_BOUNDARY_ANALYSIS_DETAILS */
2075
2076 d = 1;
2077 comb = 0;
2078 do_dvar_values_combinations(disvars,cases,numdvf,d,&(comb));
2079
2080 order_cases(cases,pos_cases);
2081 compare_cases(cases,pos_cases);
2082
2083 (*n_subregions) = 0;
2084 for(comb=0; comb<pos_cases;comb++) {
2085 if(cases[comb].diff_subregion) {
2086 (*n_subregions)++;
2087 }
2088 }
2089
2090 if((*n_subregions)==0) {
2091 FPRINTF(ASCERR,"ERROR: at least one subregion must be found\n");
2092 for (d=0; d<numdvs; d++) {
2093 cur_dis = dv[d];
2094 dis_set_boolean_value(cur_dis,bval.cur_val[d]);
2095 dis_set_value(cur_dis,bval.cur_val[d]);
2096 dis_set_previous_value(cur_dis,bval.pre_val[d]);
2097 }
2098 destroy_array(bval.cur_val);
2099 destroy_array(bval.pre_val);
2100 for(comb=0; comb<pos_cases;comb++) {
2101 destroy_array(cases[comb].case_list);
2102 }
2103 destroy_array(cases);
2104 return 0;
2105 }
2106
2107 if((*n_subregions)==1) {
2108 FPRINTF(ASCERR,"Not really at a boundary\n");
2109 for (d=0; d<numdvs; d++) {
2110 cur_dis = dv[d];
2111 dis_set_boolean_value(cur_dis,bval.cur_val[d]);
2112 dis_set_value(cur_dis,bval.cur_val[d]);
2113 dis_set_previous_value(cur_dis,bval.pre_val[d]);
2114 }
2115 destroy_array(bval.cur_val);
2116 destroy_array(bval.pre_val);
2117 for(comb=0; comb<pos_cases;comb++) {
2118 destroy_array(cases[comb].case_list);
2119 }
2120 destroy_array(cases);
2121 return 0;
2122 }
2123
2124 if((*n_subregions) > 0) {
2125 (*subregions) = (struct matching_cases *)
2126 (ascmalloc(((*n_subregions))*sizeof(struct matching_cases)));
2127 (*n_subregions) = 0;
2128 for(comb=0; comb<pos_cases;comb++) {
2129 if(cases[comb].diff_subregion) {
2130 (*subregions)[(*n_subregions)].case_list = cases[comb].case_list;
2131 cases[comb].case_list = NULL;
2132 (*subregions)[(*n_subregions)].ncases = cases[comb].ncases;
2133 cases[comb].ncases = 0;
2134 (*subregions)[(*n_subregions)].diff_subregion = 1;
2135 (*n_subregions)++;
2136 }
2137 }
2138 }
2139
2140 for(comb=0; comb<pos_cases;comb++) {
2141 destroy_array(cases[comb].case_list);
2142 }
2143 destroy_array(cases);
2144
2145
2146 assign_cur_sub = 0;
2147 /*
2148 * Finding the subregion corresponding to the "original" configuration
2149 */
2150 for (d=0; d<numdvs; d++) {
2151 cur_dis = dv[d];
2152 dis_set_boolean_value(cur_dis,bval.cur_val[d]);
2153 dis_set_value(cur_dis,bval.cur_val[d]);
2154 dis_set_previous_value(cur_dis,bval.pre_val[d]);
2155 }
2156 cur_cases = cases_matching(disvars,&cur_ncases);
2157 caselist = cur_cases;
2158 if(cur_ncases > 1) {
2159 newcaselist = create_array(cur_ncases,int32);
2160 order_case(caselist,newcaselist,cur_ncases);
2161 cur_cases = newcaselist;
2162 destroy_array(caselist);
2163 }else{
2164 if(cur_ncases == 1) {
2165 newcaselist = create_array(1,int32);
2166 newcaselist[0] = caselist[1];
2167 cur_cases = newcaselist;
2168 destroy_array(caselist);
2169 }
2170 }
2171 for(comb=0; comb<(*n_subregions);comb++) {
2172 if((*subregions)[comb].ncases == cur_ncases) {
2173 if(compare_case((*subregions)[comb].case_list,cur_cases,cur_ncases)) {
2174 (*cur_subregion) = comb;
2175 assign_cur_sub = 1;
2176 break;
2177 }
2178 }
2179 }
2180
2181 if(!assign_cur_sub) {
2182 FPRINTF(ASCERR,"PANIC: original configuration not found\n");
2183 }
2184
2185 destroy_array(cur_cases);
2186 destroy_array(dvarmodified);
2187 destroy_array(bval.cur_val);
2188 destroy_array(bval.pre_val);
2189 return 1;
2190 }
2191
2192
2193 /*
2194 * If some boundary(ies) has been crossed in the iterative scheme,
2195 * this function finds the boundary crossed (the first one, if many).
2196 * It returns the factor (less than 1) by which the step length has
2197 * to be multiplied son that the new point will lie precisely
2198 * at that boundary. This factor is found by using the method of
2199 * bisection
2200 */
2201 static
2202 real64 return_to_first_boundary(slv_system_t server,
2203 SlvClientToken asys,
2204 struct real_values *rvalues,
2205 var_filter_t *vfilter
2206 ){
2207 slv9_system_t sys;
2208 struct bnd_boundary **bp, *cur_bnd;
2209 struct var_variable **incidences, **bnd_incidences;
2210 struct var_variable *cur_var;
2211 bnd_filter_t bfilter;
2212 struct boolean_values bval;
2213 real64 factor=0.0,fup,flo,newvalue;
2214 int32 *bndcrossed;
2215 int32 *inc_vars;
2216 int32 count,n_incidences,inc,conv_flag,still_crossed;
2217 int32 numbnds,numbndf,b,ind;
2218 int32 iter,n_iterations;
2219 FILE *lif;
2220
2221 sys = SLV9(asys);
2222 check_system(sys);
2223 lif = LIF(sys);
2224
2225 if(sys->blist == NULL ) {
2226 FPRINTF(ASCERR,"ERROR: (slv9) return_to_first_boundary\n");
2227 FPRINTF(ASCERR," Boundary list was never set.\n");
2228 return 1.0;
2229 }
2230
2231 if(!some_boundaries_crossed(server,asys)) {
2232 return 1.0;
2233 }
2234
2235 bp = sys->blist;
2236 numbnds = slv_get_num_solvers_bnds(server);
2237 bfilter.matchbits = (BND_CROSSED);
2238 bfilter.matchvalue = (BND_CROSSED);
2239 numbndf = slv_count_solvers_bnds(server,&bfilter);
2240 bndcrossed = create_array(numbndf,int32);
2241 bval.cur_val = create_array(numbndf,int32);
2242 bval.pre_val = create_array(numbndf,int32);
2243 ind = 0;
2244 for (b=0; b<numbnds; b++) {
2245 cur_bnd = bp[b];
2246 if(bnd_crossed(cur_bnd)) {
2247 bndcrossed[ind] = b;
2248 bval.cur_val[ind] = bnd_status_cur(cur_bnd);
2249 bval.pre_val[ind] = bnd_status_pre(cur_bnd);
2250 ind++;
2251 }
2252 }
2253
2254 count = 0;
2255 for (b=0; b<numbndf; b++) {
2256 cur_bnd = bp[bndcrossed[b]];
2257 n_incidences = bnd_n_real_incidences(cur_bnd);
2258 count = count + n_incidences;
2259 }
2260
2261 incidences = (struct var_variable **)
2262 ( ascmalloc((count)*sizeof(struct var_variable *)));
2263 inc_vars = create_array(count,int32);
2264 count = 0;
2265 for (b=0; b<numbndf; b++) {
2266 cur_bnd = bp[bndcrossed[b]];
2267 bnd_incidences = bnd_real_incidence(cur_bnd);
2268 n_incidences = bnd_n_real_incidences(cur_bnd);
2269 #if SHOW_BOUNDARY_ANALYSIS_DETAILS
2270 FPRINTF(lif,"boundary crossed = %d\n",bndcrossed[b]);
2271 FPRINTF(lif,"previous boundary status = %d\n",bval.pre_val[b]);
2272 FPRINTF(lif,"current boundary status = %d\n",bval.cur_val[b]);
2273 #endif /* SHOW_BOUNDARY_ANALYSIS_DETAILS */
2274 for (inc=0; inc<n_incidences; inc++) {
2275 incidences[count] = bnd_incidences[inc];
2276 inc_vars[count] = var_mindex(incidences[count]);
2277 count++;
2278 }
2279 }
2280
2281 /* bisection to find first boundary crossed */
2282 fup = 1.0;
2283 flo = 0.0;
2284 conv_flag = 0;
2285 iter = 0;
2286
2287 /*
2288 * Maximum number of bisection iterations. This must be modified
2289 * so that it becomes a parameter to be defined by the user
2290 */
2291 n_iterations = ITER_BIS_LIMIT;
2292
2293 #if SHOW_BOUNDARY_ANALYSIS_DETAILS
2294 for (inc=0; inc<count; inc++) {
2295 cur_var = incidences[inc];
2296 if(var_apply_filter(cur_var,vfilter)) {
2297 FPRINTF(lif,"Variable ");
2298 print_var_name(lif,sys,cur_var); PUTC('\n',lif);
2299 FPRINTF(lif,
2300 "previous value = %f\n",rvalues->pre_values[inc_vars[inc]]);
2301 FPRINTF(lif,"current value = %f\n",rvalues->cur_values[inc_vars[inc]]);
2302 }
2303 }
2304 #endif /* SHOW_BOUNDARY_ANALYSIS_DETAILS */
2305
2306 while (conv_flag == 0) {
2307 iter++;
2308 if(iter>n_iterations) {
2309 FPRINTF(ASCERR,"ERROR: (slv9) return_to_first_boundary\n");
2310 FPRINTF(ASCERR,"Could not find the first boundary crossed \n");
2311 FPRINTF(ASCERR,"Returning the last factor calculated\n");
2312 break;
2313 }
2314 still_crossed = 0;
2315 factor = ( fup + flo ) / 2.0;
2316 #if SHOW_BISECTION_DETAILS
2317 FPRINTF(lif,"fup = %f\n",fup);
2318 FPRINTF(lif,"flo = %f\n",flo);
2319 FPRINTF(lif,"factor = %f\n",factor);
2320 #endif /* SHOW_BISECTION_DETAILS */
2321 for (inc=0; inc<count; inc++) {
2322 cur_var = incidences[inc];
2323 if(var_apply_filter(cur_var,vfilter)) {
2324 newvalue = rvalues->pre_values[inc_vars[inc]] + factor *
2325 ( rvalues->cur_values[inc_vars[inc]] -
2326 rvalues->pre_values[inc_vars[inc]] );
2327 var_set_value(cur_var,newvalue);
2328 #if SHOW_BISECTION_DETAILS
2329 FPRINTF(lif,"Variable ");
2330 print_var_name(lif,sys,cur_var); PUTC('\n',lif);
2331 FPRINTF(lif,"value after factor = %f\n",newvalue);
2332 #endif /* SHOW_BISECTION_DETAILS */
2333 }
2334 }
2335
2336 update_boundaries(server,asys);
2337 for (b=0; b<numbndf; b++) {
2338 cur_bnd = bp[bndcrossed[b]];
2339 #if SHOW_BISECTION_DETAILS
2340 FPRINTF(lif,"previous status = %d\n", bval.pre_val[b]);
2341 FPRINTF(lif,"status aftert factor = %d\n",bnd_status_cur(cur_bnd));
2342 #endif /* SHOW_BISECTION_DETAILS */
2343 if(bnd_status_cur(cur_bnd) != bval.pre_val[b] ) {
2344 still_crossed = 1;
2345 }
2346 }
2347 #if SHOW_BISECTION_DETAILS
2348 FPRINTF(lif,"still_crossed = %d\n",still_crossed);
2349 #endif /* SHOW_BISECTION_DETAILS */
2350 if(still_crossed) {
2351 fup = factor;
2352 }else{
2353 flo = factor;
2354 for (b=0; b<numbndf; b++) {
2355 cur_bnd = bp[bndcrossed[b]];
2356 bnd_set_pre_status(cur_bnd,bval.pre_val[b]);
2357 bnd_set_cur_status(cur_bnd,bval.pre_val[b]);
2358 if(bnd_at_zero(cur_bnd)) {
2359 #if SHOW_BOUNDARY_ANALYSIS_DETAILS
2360 FPRINTF(ASCERR,"boundary at zero = %d\n",bndcrossed[b]);
2361 FPRINTF(lif,"factor = %f\n",factor);
2362 for (inc=0; inc<count; inc++) {
2363 cur_var = incidences[inc];
2364 if(var_apply_filter(cur_var,vfilter)) {
2365 FPRINTF(lif,"Variable ");
2366 print_var_name(lif,sys,cur_var); PUTC('\n',lif);
2367 FPRINTF(lif,"value after factor = %f\n",var_value(cur_var));
2368 }
2369 }
2370 #endif /* SHOW_BOUNDARY_ANALYSIS_DETAILS */
2371 conv_flag = 1;
2372 }
2373 }
2374 }
2375 }
2376 destroy_array(bndcrossed);
2377 destroy_array(inc_vars);
2378 destroy_array(bval.cur_val);
2379 destroy_array(bval.pre_val);
2380 destroy_array(incidences);
2381
2382 return factor;
2383 }
2384
2385
2386 /*
2387 * Storing values of real variables.
2388 * ---------------------------------
2389 *
2390 * We use the master list of variables since its order does not change
2391 * and it is given by the master index. We do not touch the master list,
2392 * we only use its order.
2393 */
2394
2395 /*
2396 * Store the values of the var_variables before a newton-like iteration
2397 */
2398 static
2399 void store_real_pre_values(slv_system_t server,
2400 struct real_values *rvalues
2401 ){
2402 struct var_variable **master;
2403 struct var_variable *var;
2404 int v, vlen;
2405
2406 master = slv_get_master_var_list(server);
2407 vlen = slv_get_num_master_vars(server);
2408
2409 rvalues->pre_values = create_array(vlen,real64);
2410
2411 for (v=0; v<vlen; v++) {
2412 var = master[v];
2413 rvalues->pre_values[v] = var_value(var);
2414 }
2415 }
2416
2417 /*
2418 * Store the values of the var_variables after a newton-like iteration
2419 */
2420 static
2421 void store_real_cur_values(slv_system_t server,
2422 struct real_values *rvalues
2423 ){
2424 struct var_variable **master;
2425 struct var_variable *var;
2426 int v, vlen;
2427
2428 master = slv_get_master_var_list(server);
2429 vlen = slv_get_num_master_vars(server);
2430
2431 rvalues->cur_values = create_array(vlen,real64);
2432
2433 for (v=0; v<vlen; v++) {
2434 var = master[v];
2435 rvalues->cur_values[v] = var_value(var);
2436 }
2437 }
2438
2439 /*
2440 * After the length of the step has been modified so that the current point
2441 * lies at a boundary, the values of all the variables is updated so that
2442 * they all reduce the length of their step by the same factor.
2443 */
2444 static
2445 void update_real_var_values(slv_system_t server,
2446 struct real_values *rvalues,
2447 var_filter_t *vfilter, real64 factor
2448 ){
2449 struct var_variable **master;
2450 struct var_variable *var;
2451 real64 newvalue;
2452 int v, vlen;
2453
2454 master = slv_get_master_var_list(server);
2455 vlen = slv_get_num_master_vars(server);
2456
2457 for (v=0; v<vlen; v++) {
2458 var = master[v];
2459 if(var_apply_filter(var,vfilter)) {
2460 newvalue = rvalues->pre_values[v] +
2461 factor * (rvalues->cur_values[v] - rvalues->pre_values[v]);
2462 var_set_value(var,newvalue);
2463 }
2464 }
2465 destroy_array(rvalues->cur_values);
2466 destroy_array(rvalues->pre_values);
2467 }
2468
2469
2470 /*
2471 * Set the flagbit NONBASIC for all the variables in the list
2472 * to the value passed as argument
2473 */
2474 static
2475 void set_nonbasic_status_in_var_list(slv_system_t server,
2476 uint32 value
2477 ){
2478 struct var_variable **master;
2479 struct var_variable *var;
2480 int v, vlen;
2481
2482 master = slv_get_master_var_list(server);
2483 vlen = slv_get_num_master_vars(server);
2484
2485 for (v=0; v<vlen; v++) {
2486 var = master[v];
2487 var_set_nonbasic(var,value);
2488 }
2489 }
2490
2491
2492 /*
2493 * After the length of the step has been modified so that the current point
2494 * lies at a boundary, the residuals of the equations are updated.
2495 */
2496 static void update_relations_residuals(slv_system_t server)
2497 {
2498 struct rel_relation **master;
2499 struct rel_relation *rel;
2500 rel_filter_t rfilter;
2501 real64 resid;
2502 int32 r, rlen, status;
2503
2504 master = slv_get_master_rel_list(server);
2505 rlen = slv_get_num_master_rels(server);
2506
2507 rfilter.matchbits = (REL_INCLUDED | REL_EQUALITY);
2508 rfilter.matchvalue = (REL_INCLUDED | REL_EQUALITY);
2509
2510 #ifdef ASC_SIGNAL_TRAPS
2511 Asc_SignalHandlerPush(SIGFPE,SIG_IGN);
2512 #endif
2513
2514 for (r=0; r<rlen; r++) {
2515 rel = master[r];
2516 if(rel_apply_filter(rel,&rfilter)) {
2517 resid = relman_eval(rel,&status,1);
2518 }
2519 }
2520 #ifdef ASC_SIGNAL_TRAPS
2521 Asc_SignalHandlerPop(SIGFPE,SIG_IGN);
2522 #endif
2523
2524 }
2525
2526
2527 #ifdef ASC_WITH_CONOPT
2528 /*------------------------------------------------------------------------------
2529 CALLBACK ROUTINES FOR CONOPT
2530 */
2531
2532 /*
2533 * COIRMS Based on the information provided in Coispz, CONOPT will
2534 * allocate the number of vectors into which the user can define
2535 * the details of the model. The details of the model are defined
2536 * here.
2537 *
2538 * COIRMS(lower, curr, upper, vsta, type,rhs, fv, esta, colsta,
2539 * rowno, value, nlflag, n, m, nz, usrmem)
2540 *
2541 * lower - lower bounds on the variables
2542 * curr - intial values of the variables
2543 * upper - upper bounds on the variables
2544 * vsta - initial status of the variable(o nonbasic, 1 basic)
2545 * type - types of equations (0 equality,1 greater,2 less)
2546 * rhs - values of the right hand sides
2547 * fv - sum of the nonlinear terms in the initial point
2548 * esta - initial status of the slack in the constraint (nonbasic,basic)
2549 * colsta- start of column pointers
2550 * rowno - row or equation numbers of the nonzeros
2551 * value - values of the jacobian elements
2552 * nlflag- nonlinearity flags(0 nonzero constant,1 varying)
2553 * n - number of variables
2554 * m - number of constraints
2555 * nz - number of jacobian elements
2556 * usrmem- user memory defined by conopt
2557 */
2558 static
2559 int COI_CALL slv9_conopt_readmatrix(
2560 double *lower, double *curr, double *upper
2561 , int *vsta, int *type, double *rhs
2562 , int *esta, int *colsta, int *rowno
2563 , double *value, int *nlflag, int *n, int *m, int *nz
2564 , double *usrmem
2565 ){
2566 slv9_system_t sys;
2567 struct var_variable *var;
2568 struct var_variable **varlist;
2569 struct opt_matrix *coeff_matrix;
2570 real64 /*obj_val,*/ deriv;
2571 real64 nominal, up, low, uplow;
2572 int32 num_var, n_subregions, c, num_eqns;
2573 int32 numnz, eq;
2574 int32 count, totvar;
2575 double limit;
2576
2577 static var_filter_t vfilter = {
2578 VAR_ACTIVE_AT_BND | VAR_INCIDENT | VAR_SVAR | VAR_FIXED
2579 ,VAR_ACTIVE_AT_BND | VAR_INCIDENT | VAR_SVAR | 0
2580 };
2581
2582 UNUSED_PARAMETER(vsta);
2583 UNUSED_PARAMETER(esta);
2584
2585 sys = (slv9_system_t)usrmem;
2586 n_subregions = sys->subregions;
2587 coeff_matrix = sys->coeff_matrix;
2588 num_var = (*n) - n_subregions;
2589 num_eqns = num_var + 1;
2590
2591 varlist = sys->mvlist;
2592 totvar = sys->mvtot;
2593
2594 /* fetch the configured bound from solver parameters */
2595 limit = ASC_INFINITY;
2596
2597 /* CONSOLE_DEBUG("Got limit value of %g",limit); */
2598
2599 /*
2600 * Variables: Current Value, lower value and upper value. Note that for
2601 * this problem the variables are the vector of steps dx. So we "invent"
2602 * approximations for the bounds based on the bounds of the real
2603 * variables of the problem. The use of the parameter ASC_INFINITY is
2604 * Hack to keep CONOPT from complaining for large bounds.
2605 */
2606
2607 count = 0;
2608 for (c=0; c<totvar; c++) {
2609 var = varlist[c];
2610 if(var_apply_filter(var,&vfilter)) {
2611 nominal = var_nominal(var);
2612 low = var_lower_bound(var);
2613 up = var_upper_bound(var);
2614 uplow = fabs( up - low);
2615
2616 if(-uplow > -limit){
2617 lower[count] = -uplow;
2618 }else{
2619 lower[count] = -0.5*limit;
2620 /* CONSOLE_DEBUG("Reducing lower bound limit for var %d to %e",count,lower[count]); */
2621 }
2622
2623 if(uplow < limit){
2624 upper[count] = uplow;
2625 }else{
2626 upper[count] = 0.5*limit;
2627 /* CONSOLE_DEBUG("Reducing upper bound limit for var %d to %e",count,upper[count]); */
2628 }
2629
2630 curr[count] = 0.5 * nominal;
2631 count++;
2632 }
2633 }
2634 /* alphas for each subregion */
2635 for (c=count; c<(*n); c++) {
2636 lower[c] = 0.0;
2637 upper[c] = 1.0;
2638 curr[c] = 1.0;
2639 }
2640
2641 /*CONSOLE_DEBUG("ALL BOUNDS:");
2642 for(c=0;c<(*n);++c){
2643 fprintf(stderr,"%d: lower = %g, upper = %g\n",c,lower[c],upper[c]);
2644 }*/
2645
2646 /*
2647 * vsta not in use since STATOK, ipsz[14], is zero
2648 */
2649
2650 /*
2651 * All the equations, but the last row (which is the objective), are
2652 * equalities.
2653 */
2654 for (c = 0; c < (*m); c++) {
2655 type[c] = 0;
2656 }
2657 type[(*m)-1] = 3;
2658
2659
2660 /*
2661 * RHS. It is zero for all the equations except the summation of
2662 * alphas, whose RHS is one.
2663 */
2664 for (c = 0; c < (*m); c++) {
2665 rhs[c] = 0;
2666 }
2667 rhs[(*m)-2] = 1.0;
2668
2669 #ifdef DISUSED_CONOPT_PARAMETER
2670 /*
2671 * fv =0 for all linear relations. For the objective is the two
2672 * norm
2673 */
2674 for (c = 0; c < (*m); c++) {
2675 fv[c] = 0;
2676 }
2677 obj_val = 0.0;
2678 for (c = 0; c<num_var; c++) {
2679 obj_val = obj_val + (curr[c] * curr[c]);
2680 }
2681 fv[(*m)-1] = obj_val;
2682 #endif
2683
2684 /*
2685 * esta not used since STATOK is zero
2686 */
2687
2688
2689 /*
2690 * For the following parameters, it is important ot see that:
2691 * 1) The values for the rows and nonzeros that conopt wants start
2692 * with 1, not with 0.
2693 * 2) The indeces of the arrays that we are using in the C side start
2694 * with 0.
2695 */
2696
2697 /*
2698 * colsta
2699 */
2700
2701 for (c=0; c<num_var; c++) {
2702 colsta[c] = 2 * c;
2703 }
2704
2705 for (c=num_var; c<(*n); c++) {
2706 colsta[c] = 2 * num_var + num_eqns * (c - num_var);
2707 }
2708
2709 colsta[*n] = *nz; /** @TODO check this */
2710
2711 /*
2712 rowno, value and nlflag can be done in same loop. The use of the
2713 parameter RTMAXJ is really a Hack to keep CONOPT from complaining
2714 about large derivatives
2715 */
2716
2717 numnz = 0;
2718 for (c=0; c<num_var; c++) {
2719 rowno[numnz] = c;
2720 nlflag[numnz] = 0;
2721 value[numnz] = -1;
2722 numnz++;
2723 rowno[numnz] = *m - 1;
2724 nlflag[numnz] = 1;
2725 numnz++;
2726 }
2727
2728 for (c=num_var; c<(*n); c++) {
2729 numnz = 2 * num_var + num_eqns * (c - num_var);
2730 for(eq = 0; eq<num_eqns-1; eq++) {
2731 rowno[numnz] = eq;
2732 nlflag[numnz] = 0;
2733 deriv = -1.0 * (coeff_matrix->cols[c - num_var].element[eq]);
2734 if(deriv > RTMAXJ ) {
2735 deriv = 0.5 * RTMAXJ;
2736 }else{
2737 if(deriv < -RTMAXJ ) {
2738 deriv = -0.5*RTMAXJ;
2739 }
2740 }
2741 value[numnz] = deriv;
2742 numnz++;
2743 }
2744 rowno[numnz] = num_eqns - 1;
2745 nlflag[numnz] = 0;
2746 value[numnz] = 1.0;
2747 }
2748
2749 return 0;
2750 }
2751
2752 #if 0 /* not in API any more */
2753 /*
2754 * COIFBL Defines the nonlinearities of the model by returning
2755 * numerical values. It works on a block of rows during each call.
2756 * COIFBL( x, g, otn, nto, from, to, jac, stcl, rnum, cnum, nl, strw,
2757 * llen, indx, mode, errcnt, n, m, n1, m1, nz, usrmem)
2758 *
2759 * x - punt of evaluation provided by conopt
2760 * g - vector of function values
2761 * otn - old to new permutation vector
2762 * nto - new to old permutation vector
2763 * from - range in permutation
2764 * to - range in permutation
2765 * jac - vector of jacobian values.
2766 * The following are vectors defining the jacobian structure
2767 * stcl - start of column pointers
2768 * rnum - row numbers
2769 * cnum - column numbers
2770 * nl - nonlinearity flags
2771 * strw - start row pointers
2772 * llen - count of linear jacobian elements
2773 * indx - pointers from the row-wise representation
2774 * mode - indicator of mode of evaluation
2775 * errcnt- number of function evaluation errors
2776 * n - umber of variables
2777 * m - number of constraints
2778 * n1 - n+1
2779 * m1 - m+1
2780 * nz - number of jacobian elements
2781 * usrmem- user memory defined by conopt
2782 */
2783 static void slv9_coifbl(real64 *x, real64 *g, int32 *otn, int32 *nto,
2784 int32 *from, int32 *to, real64 *jac, int32 *stcl,
2785 int32 *rnum, int32 *cnum, int32 *nl, int32 *strw,
2786 int32 *llen, int32 *indx, int32 *mode, int32 *errcnt,
2787 int32 *n, int32 *m, int32 *n1, int32 *m1,
2788 int32 *nz, real64 *usrmem)
2789 {
2790 /* non defined for this solver */
2791
2792 /* stop gcc whining about unused parameter */
2793 (void)x; (void)g; (void)otn; (void)nto; (void)from; (void)to;
2794 (void)jac; (void)stcl; (void)rnum; (void)cnum; (void)nl; (void)strw;
2795 (void)llen; (void)indx; (void)mode; (void)errcnt; (void)n; (void)m;
2796 (void)n1; (void)m1; (void)nz;
2797 (void)usrmem;
2798
2799 return;
2800 }
2801 #endif
2802
2803 /*
2804 * COIFDE Defines the nonlinearities of the model by returning
2805 * numerical values. It works on one row or equation at a time
2806 * COIFDE(x, g, jac, rowno, jcnm, mode, errcnt, newpt, n, nj, usrmem)
2807 *
2808 * x - punt of evaluation provided by conopt
2809 * g - function value
2810 * jac - jacobian values
2811 * rowno - number of the row for which nonlinearities will be eval
2812 * jcnm - list of column number fon the NL nonzeros
2813 * mode - indicator of mode of evaluation
2814 * errcnt - sum of number of func evaluation errors thus far
2815 * newpt - new point indicator
2816 * nj - number of nonlinear nonzero jacobian elements
2817 * n - number of variables
2818 * usrmem - user memory
2819 *
2820 * For the optimization problem at a boundary, this subroutine will
2821 * be called only of the objective function, constraint number m.
2822 *
2823 */
2824 static
2825 int COI_CALL slv9_conopt_fdeval(
2826 double *x, double *g, double *jac
2827 , int *rowno, int *jcnm, int *mode, int *ignerr
2828 , int *errcnt, int *newpt, int *n, int *nj
2829 , double *usrmem
2830 ){
2831 slv9_system_t sys;
2832 int32 num_vars, v;
2833 real64 obj, deriv;
2834
2835 UNUSED_PARAMETER(jcnm);
2836 UNUSED_PARAMETER(errcnt);
2837 UNUSED_PARAMETER(newpt);
2838 UNUSED_PARAMETER(n);
2839 UNUSED_PARAMETER(nj);
2840
2841 sys = (slv9_system_t)usrmem;
2842 num_vars = sys->con.n - sys->subregions;
2843
2844 if(*mode == 1 || *mode == 3) {
2845 if(*rowno == sys->con.m - 1){
2846 obj = 0.0;
2847 for (v=0; v<num_vars; v++) {
2848 obj = obj + (x[v] * x[v]);
2849 }
2850 *g = obj;
2851 }else{
2852 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Wrong number of constraints");
2853 return 1;
2854 }
2855 }
2856
2857 /*
2858 * The use of the parameter RTMAXJ is really a Hack to keep CONOPT
2859 * from complaining about large derivatives.
2860 */
2861
2862 if(*mode == 2 || *mode == 3) {
2863 if(*rowno == sys->con.m - 1){
2864 for (v=0; v<num_vars; v++) {
2865 deriv = 2.0 * x[v];
2866 if(deriv > RTMAXJ ) {
2867 deriv = 0.5*RTMAXJ;
2868 }else{
2869 if(deriv < -RTMAXJ ) {
2870 deriv = -0.5*RTMAXJ;
2871 }
2872 }
2873 jac[v] = deriv;
2874 }
2875 }else{
2876 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Wrong number of constraints");
2877 return 1;
2878 }
2879 }
2880
2881 return 0;
2882 }
2883
2884
2885 /*
2886 * COISTA Pass the solution from CONOPT to the modeler. It returns
2887 * completion status
2888 * COISTA(modsta, solsts, iter, objval, usrmem)
2889 *
2890 * modsta - model status
2891 * solsta - solver status
2892 * iter - number of iterations
2893 * objval - objective value
2894 * usrmem - user memory
2895 */
2896 static
2897 int COI_CALL slv9_conopt_status(int *modsta, int *solsta, int *iter
2898 , double *objval, double *usrmem
2899 ){
2900 slv9_system_t sys;
2901
2902 sys = (slv9_system_t)usrmem;
2903
2904 sys->con.modsta = *modsta;
2905 sys->con.solsta = *solsta;
2906 sys->con.iter = *iter;
2907 sys->con.obj = *objval;
2908
2909 return 0;
2910 }
2911
2912 /**
2913 CONOPT error message reporting
2914 */
2915 int COI_CALL slv9_conopt_errmsg( int* ROWNO, int* COLNO, int* POSNO, int* MSGLEN
2916 , double* USRMEM, char* MSG, int LENMSG
2917 ){
2918 slv9_system_t sys;
2919 char *varname=NULL;
2920 struct var_variable **vp;
2921
2922 sys = (slv9_system_t)USRMEM;
2923
2924
2925 if(*COLNO!=-1){
2926 vp=sys->mvlist;
2927 vp = vp + *COLNO;
2928 assert(*vp!=NULL);
2929 varname= var_make_name(SERVER,*vp);
2930 }
2931
2932 ERROR_REPORTER_START_NOLINE(ASC_PROG_ERR);
2933 if(*ROWNO == -1){
2934 FPRINTF(ASCERR,"Variable %d (Maybe it's '%s'): ",*COLNO,varname);
2935 ASC_FREE(varname);
2936 }else if(*COLNO == -1 ){
2937 FPRINTF(ASCERR,"Relation %d: ",*ROWNO);
2938 }else{
2939 FPRINTF(ASCERR,"Variable %d (Maybe it's '%s') appearing in relation %d: ",*COLNO,varname,*ROWNO);
2940 ASC_FREE(varname);
2941 }
2942 FPRINTF(ASCERR,"%*s", *MSGLEN, MSG);
2943 error_reporter_end_flush();
2944 return 0;
2945 }
2946
2947
2948 /*
2949 * COIRS Pass the solution from CONOPT to the modeler. It returns
2950 * solution values
2951 * COIRS(val, xmar, xbas, xsta, yval, ymar, ybas, ysta, n, m, usrmem)
2952 *
2953 * xval - the solution values of the variables
2954 * xmar - corresponding marginal values
2955 * xbas - basis indicator for column (at bound, basic, nonbasic)
2956 * xsta - status of column (normal, nonoptimal, infeasible,unbounded)
2957 * yval - values of the left hand side in all the rows
2958 * ymar - corresponding marginal values
2959 * ybas - basis indicator for row
2960 * ysta - status of row
2961 * n - number of variables
2962 * m - number of constraints
2963 * usrmem - user memory
2964 */
2965 static
2966 int COI_CALL slv9_conopt_solution(double *xval, double *xmar, int *xbas, int *xsta,
2967 double *yval, double *ymar, int *ybas, int * ysta,
2968 int *n, int *m, double *usrmem
2969 ){
2970 slv9_system_t sys;
2971 struct opt_vector *opt_var_values;
2972 int32 c;
2973 real64 value;
2974
2975 UNUSED_PARAMETER(xmar);UNUSED_PARAMETER(xbas);UNUSED_PARAMETER(xsta);
2976 UNUSED_PARAMETER(yval);UNUSED_PARAMETER(ymar);UNUSED_PARAMETER(ybas);
2977 UNUSED_PARAMETER(ysta);UNUSED_PARAMETER(m);
2978
2979 sys = (slv9_system_t)usrmem;
2980 opt_var_values = sys->opt_var_values;
2981
2982 for (c = 0; c < (*n); c++) {
2983 value = xval[c];
2984 opt_var_values->element[c] = value;
2985 }
2986
2987 return 0;
2988 }
2989
2990 #if 0
2991 /*
2992 * COIUSZ communicates and update of an existing model to CONOPT
2993 * COIUSZ(nintg, ipsz, nreal, rpsz, usrmem)
2994 *
2995 * nintg - number of positions in ipsz
2996 * ipsz - array describing problem size and options
2997 * nreal - number of positions in rpsz
2998 * rpsz - array of reals describing problem size and options
2999 * usrmem- user memory
3000 */
3001 static void slv9_coiusz(int32 *nintg, int32 *ipsz, int32 *nreal, real64 *rpsz,
3002 real64 *usrmem)
3003 {
3004 /* non defined for this solver */
3005
3006 /*
3007 * stop gcc whining about unused parameter
3008 */
3009 (void)nintg; (void)ipsz; (void)nreal; (void)rpsz;
3010 (void)usrmem;
3011
3012 return;
3013 }
3014 #endif
3015
3016 /*
3017 * COIOPT communicates non-default option values to CONOPT
3018 * COIOPT(name, rval, ival, lval, usrmem)
3019 * name - the name of a CONOPT CR-cell defined by the modeler
3020 * rval - the value to be assigned to name if the cells contains a real
3021 * ival - the value to be assigned to name if the cells contains an int
3022 * lval - the value to be assigned to name if the cells contains a log value
3023 * usrmem - user memory
3024 */
3025 static
3026 int COI_CALL slv9_conopt_option(
3027 int *NCALL, double *rval, int *ival, int *logical
3028 , double *usrmem, char *name, int lenname
3029 ){
3030 slv9_system_t sys;
3031 sys = (slv9_system_t)usrmem;
3032
3033 UNUSED_PARAMETER(logical);
3034
3035 name = memset(name,' ',8);
3036 while (sys->con.opt_count < slv9_PA_SIZE) {
3037 if(strlen(sys->p.parms[sys->con.opt_count].interface_label) == 6) {
3038 if(strncmp(sys->p.parms[sys->con.opt_count].interface_label,
3039 "R",1) == 0) {
3040 name = strncpy(name, sys->p.parms[sys->con.opt_count]. /* . break */
3041 interface_label,6);
3042 *rval = sys->p.parms[sys->con.opt_count].info.r.value;
3043 sys->con.opt_count++;
3044 return 0;
3045 } else if(strncmp(sys->p.parms[sys->con.opt_count]. /* . break */
3046 interface_label,"L",1) == 0) {
3047 name = strncpy(name,sys->p.parms[sys->con.opt_count]. /* . break */
3048 interface_label,6);
3049 *ival = sys->p.parms[sys->con.opt_count].info.i.value;
3050 sys->con.opt_count++;
3051 return 0;
3052 }
3053 }
3054 sys->con.opt_count++;
3055 }
3056
3057 /* sending blank to quit iterative calling */
3058 name = memset(name,' ',8);
3059 return 0;
3060 }
3061
3062 #if 0 /* see slv_conopt_iterate */
3063 /*
3064 * COIPSZ communicates the model size and structure to CONOPT
3065 * COIPSZ(nintgr, ipsz, nreal, rpsz, usrmem)
3066 *
3067 * ningtr - number of positions in ipsz
3068 * ipsz - array describing problem size and options
3069 * nreal - number of positions in rpsz
3070 * rpsz - array of reals describing problem size and options
3071 * usrmem - user memory
3072 */
3073 static void slv9_coipsz(int32 *nintg, int32 *ipsz, int32 *nreal, real64 *rpsz,
3074 real64 *usrmem)
3075 {
3076 slv9_system_t sys;
3077
3078 /*
3079 * stop gcc whining about unused parameter
3080 */
3081 (void)nintg; (void)nreal;
3082
3083 sys = (slv9_system_t)usrmem;
3084 /*
3085 * Integer array
3086 */
3087 ipsz[F2C(1)] = sys->con.n; /* variables */
3088 ipsz[F2C(2)] = sys->con.m; /* constraints including objective */
3089 ipsz[F2C(3)] = sys->con.nz; /* non zeros in Jacobian */
3090 ipsz[F2C(4)] = sys->con.nz - (sys->con.m - 2); /* linear nonzeros */
3091 ipsz[F2C(5)] = sys->con.m - 2; /* nonlinear nonzeros */
3092 ipsz[F2C(6)] = -1; /* direction of optimization min */
3093 ipsz[F2C(7)] = sys->con.m; /* objective will be last row */
3094 ipsz[F2C(8)] = OPT_ITER_LIMIT; /* iteration limit */
3095 ipsz[F2C(9)] = DOMLIM; /* max number of error in func evals */
3096 ipsz[F2C(10)] = 0; /* output to file */
3097 ipsz[F2C(11)] = 1; /* progress info to screen */
3098 ipsz[F2C(12)] = 1; /* correct value of func in coirms */
3099 ipsz[F2C(13)] = 0; /* not correct value of jacs in coirms */
3100 ipsz[F2C(14)] = 0; /* status not known by modeler */
3101 ipsz[F2C(15)] = 0; /* function value include only NL terms */
3102 ipsz[F2C(16)] = 1; /* Objective is a constraint */
3103 ipsz[F2C(17)] = 0; /* sorted order for jacobian */
3104 ipsz[F2C(18)] = 0; /* append the log file after restarts */
3105 ipsz[F2C(19)] = 0; /* one subroutine call to coirms */
3106 ipsz[F2C(20)] = 0; /* eval subroutine is coifde */
3107 ipsz[F2C(21)] = 0; /* no debugging of derivatives */
3108 ipsz[F2C(22)] = 0; /* coifde not called for linear eqns */
3109 /*
3110 * skipping remainder of ipsz which are fortran io parameters
3111 */
3112
3113 /*
3114 * Real array
3115 */
3116 rpsz[F2C(1)] = ASC_INFINITY; /* infinity */
3117 rpsz[F2C(2)] = -ASC_INFINITY; /* -infinity */
3118 rpsz[F2C(3)] = UNDEFINED; /* undefined */
3119 rpsz[F2C(6)] = 0; /* work space allocated by conopt */
3120 rpsz[F2C(7)] = TIME_LIMIT; /* resource limit (time) */
3121 rpsz[F2C(8)] = 1; /* initial value for vars if none given */
3122
3123
3124 }
3125 #endif
3126
3127
3128 /**
3129 Perform CONOPT solution. For the details of what this does in the larger
3130 context of CMSlv, read (???)
3131
3132 @TODO document this.
3133
3134 @see conopt.h
3135 */
3136 static
3137 void slv_conopt_iterate(slv9_system_t sys){
3138
3139 if(sys->con.cntvect == NULL){
3140 sys->con.cntvect = ASC_NEW_ARRAY(int,COIDEF_Size());
3141 }
3142
3143 COIDEF_Ini(sys->con.cntvect);
3144
3145 /*
3146 We pass pointer to sys as usrmem data.
3147 Cast back to slv9_system_t to access the information required
3148 */
3149 COIDEF_UsrMem(sys->con.cntvect,(double *)sys);
3150
3151 COIDEF_NumVar(sys->con.cntvect, &(sys->con.n));
3152 COIDEF_NumCon(sys->con.cntvect, &(sys->con.m)); /* include the obj fn */
3153 COIDEF_NumNZ(sys->con.cntvect, &(sys->con.nz));
3154 COIDEF_NumNlNz(sys->con.cntvect, &(sys->con.nlnz));
3155 COIDEF_OptDir(sys->con.cntvect, &(sys->con.optdir));
3156
3157 COIDEF_ObjCon(sys->con.cntvect, &(sys->con.objcon)); /* objective will be last row */
3158 COIDEF_Base(sys->con.cntvect, &(sys->con.base));
3159 COIDEF_ErrLim(sys->con.cntvect, &(DOMLIM));
3160 COIDEF_ItLim(sys->con.cntvect, &(OPT_ITER_LIMIT));
3161
3162 COIDEF_ReadMatrix(sys->con.cntvect, &slv9_conopt_readmatrix);
3163 COIDEF_FDEval(sys->con.cntvect, &slv9_conopt_fdeval);
3164 COIDEF_Option(sys->con.cntvect, &slv9_conopt_option);
3165 COIDEF_Solution(sys->con.cntvect, &slv9_conopt_solution);
3166 COIDEF_Status(sys->con.cntvect, &slv9_conopt_status);
3167 COIDEF_Message(sys->con.cntvect, &asc_conopt_message);
3168 COIDEF_ErrMsg(sys->con.cntvect, &slv9_conopt_errmsg);
3169 COIDEF_Progress(sys->con.cntvect, &asc_conopt_progress);
3170
3171 /** @TODO implement the following options as well... */
3172 #if 0
3173 ipsz[F2C(10)] = 0; /* output to file */
3174 ipsz[F2C(11)] = 1; /* progress info to screen */
3175 ipsz[F2C(12)] = 1; /* correct value of func in coirms */
3176 ipsz[F2C(13)] = 0; /* not correct value of jacs in coirms */
3177 ipsz[F2C(14)] = 0; /* status not known by modeler */
3178 ipsz[F2C(15)] = 0; /* function value include only NL terms */
3179 ipsz[F2C(16)] = 1; /* Objective is a constraint */
3180 ipsz[F2C(17)] = 0; /* sorted order for jacobian */
3181 ipsz[F2C(18)] = 0; /* append the log file after restarts */
3182 ipsz[F2C(19)] = 0; /* one subroutine call to coirms */
3183 ipsz[F2C(20)] = 0; /* eval subroutine is coifde */
3184 ipsz[F2C(21)] = 0; /* no debugging of derivatives */
3185 ipsz[F2C(22)] = 0; /* coifde not called for linear eqns */
3186 /*
3187 * skipping remainder of ipsz which are fortran io parameters
3188 */
3189
3190 /*
3191 * Real array
3192 */
3193 rpsz[F2C(1)] = ASC_INFINITY; /* infinity */
3194 rpsz[F2C(2)] = -ASC_INFINITY; /* -infinity */
3195 rpsz[F2C(3)] = UNDEFINED; /* undefined */
3196 rpsz[F2C(6)] = 0; /* work space allocated by conopt */
3197 rpsz[F2C(7)] = TIME_LIMIT; /* resource limit (time) */
3198 rpsz[F2C(8)] = 1; /* initial value for vars if none given */
3199 #endif
3200
3201 /*
3202 * reset count on coiopt calls
3203 */
3204 sys->con.opt_count = 0;
3205
3206 /*
3207 * do not keep model in memory after solution
3208 */
3209 sys->con.kept = 0;
3210
3211 COI_Solve(sys->con.cntvect);
3212 /* conopt_start(&(sys->con.kept), usrmem, &(sys->con.lwork),
3213 sys->con.work, &(sys->con.maxusd), &(sys->con.curusd)); */
3214
3215 /*
3216 * We assume that we get convergence in optimization problem at
3217 * boundary
3218 */
3219 sys->con.optimized = 1;
3220 }
3221
3222 #endif /* ASC_WITH_CONOPT */
3223
3224 /*-------------------end of conopt callbacks----------------------------------*/
3225
3226
3227 /*
3228 * Creates an array of columns (containing an array of real elements
3229 * each) to storage the linear coefficient matrix of the optimization problem.
3230 * It also creates the arrays of reals required to storage the values
3231 * of the gradients of a subregion, which change depending on whether the
3232 * problem is a simulation or an optimization.
3233 */
3234 static
3235 void create_opt_matrix_and_vectors(int32 num_opt_eqns,
3236 int32 n_subregions,
3237 struct opt_matrix *coeff_matrix,
3238 struct opt_vector *opt_var_values,
3239 struct opt_vector *invariant,
3240 struct opt_vector *variant,
3241 struct opt_vector *gradient,
3242 struct opt_matrix *multipliers
3243 ){
3244 int32 c;
3245 int32 num_vars;
3246
3247 num_vars = num_opt_eqns - 1 + n_subregions;
3248
3249 coeff_matrix->cols = ASC_NEW_ARRAY(struct opt_vector,n_subregions);
3250
3251 if(g_optimizing) {
3252 multipliers->cols = ASC_NEW_ARRAY(struct opt_vector,n_subregions);
3253 }
3254
3255 for (c=0; c<n_subregions; c++) {
3256 coeff_matrix->cols[c].element = ASC_NEW_ARRAY(real64,num_opt_eqns);
3257 }
3258 opt_var_values->element = ASC_NEW_ARRAY(real64,num_vars);
3259
3260 if(g_optimizing) {
3261 gradient->element = ASC_NEW_ARRAY(real64,num_opt_eqns);
3262 }else{
3263 invariant->element = ASC_NEW_ARRAY(real64,num_opt_eqns);
3264 variant->element = ASC_NEW_ARRAY(real64,num_opt_eqns);
3265 }
3266 }
3267
3268
3269 /*
3270 * destroy the arrays created to storage the gradients for the optimization
3271 * problem
3272 */
3273 static
3274 void destroy_opt_matrix_and_vectors(int32 n_subregions,
3275 struct opt_matrix *coeff_matrix,
3276 struct opt_vector *opt_var_values,
3277 struct opt_vector *invariant,
3278 struct opt_vector *variant,
3279 struct opt_vector *gradient,
3280 struct opt_matrix *multipliers
3281 ){
3282 int32 c;
3283 for (c=0; c<n_subregions; c++) {
3284 destroy_array(coeff_matrix->cols[c].element);
3285 if(g_optimizing) {
3286 destroy_array(multipliers->cols[c].element);
3287 }
3288 }
3289 destroy_array(coeff_matrix->cols);
3290 destroy_array(opt_var_values->element);
3291 if(g_optimizing) {
3292 destroy_array(multipliers->cols);
3293 destroy_array(gradient->element);
3294 }else{
3295 destroy_array(invariant->element);
3296 destroy_array(variant->element);
3297 }
3298 }
3299
3300
3301
3302 /*
3303 * Set Factorization Options
3304 */
3305 static
3306 void set_factor_options (linsolqr_system_t lsys){
3307 linsolqr_prep(lsys,linsolqr_fmethod_to_fclass(ranki_ba2));
3308 linsolqr_set_pivot_zero(lsys, 1e-12);
3309 linsolqr_set_drop_tolerance(lsys,1e-16);
3310 linsolqr_set_pivot_tolerance(lsys, 0.1);
3311 linsolqr_set_condition_tolerance(lsys, 0.1);
3312 }
3313
3314
3315 /*
3316 * Calculating the Lagrange Multipliers for each subregion
3317 *
3318 * We are assuming here that the matrix is structurally nonsingular
3319 * and than the rank is equal to the number of rows in the matrix.
3320 * Much more efficient checking must be done.
3321 */
3322 static
3323 void get_multipliers(SlvClientToken asys,
3324 int32 subregion,
3325 int32 nrel,
3326 real64 *grad_obj,
3327 struct opt_matrix *multipliers
3328 ){
3329 slv9_system_t sys;
3330 linsolqr_system_t lsys;
3331 mtx_region_t *newblocks, *oneblock;
3332 int32 rank;
3333 int32 c, cr, len, row;
3334 real64 *weights;
3335 real64 summ;
3336
3337 sys = SLV9(asys);
3338 check_system(sys);
3339
3340 mtx_output_assign(sys->lin_mtx,nrel,nrel);
3341 rank = mtx_symbolic_rank(sys->lin_mtx);
3342 mtx_partition(sys->lin_mtx);
3343 len = mtx_number_of_blocks(sys->lin_mtx);
3344 newblocks = ASC_NEW_ARRAY(mtx_region_t,len);
3345 if(newblocks == NULL) {
3346 mtx_destroy(sys->lin_mtx);
3347 return;
3348 }
3349 for (c = 0 ; c < len; c++) {
3350 mtx_block(sys->lin_mtx,c,&(newblocks[c]));
3351 }
3352 for (c = 0 ; c < len; c++) {
3353 mtx_reorder(sys->lin_mtx,&(newblocks[c]),mtx_SPK1);
3354 }
3355
3356 /* unifying block */
3357 oneblock = (mtx_region_t *)ascmalloc(sizeof(mtx_region_t));
3358 oneblock->row.low = oneblock->col.low = 0;
3359 oneblock->row.high = nrel-1;
3360 oneblock->col.high = nrel-1;
3361
3362 /*
3363 * Scaling of the linear system
3364 */
3365
3366 /*
3367 *Calculating weights
3368 */
3369 weights = ASC_NEW_ARRAY(real64,nrel);
3370 for (row=0; row<nrel; row++) {
3371 summ = mtx_sum_sqrs_in_row(sys->lin_mtx,row,&(oneblock->col));
3372 if(summ <= 0.0) {
3373 weights[row] = 1.0;
3374 }else{
3375 weights[row] = 1.0 / sqrt(summ);
3376 }
3377 #if DEBUG
3378 FPRINTF(ASCERR," weight of row %d = %f \n",row,summ);
3379 #endif /* DEBUG */
3380 }
3381
3382 /*
3383 * Dividing rows by weights
3384 */
3385 for (row=0; row<nrel; row++) {
3386 mtx_mult_row(sys->lin_mtx,row,weights[row],&(oneblock->col));
3387 }
3388
3389 /*
3390 * dividing rhs
3391 */
3392 for (row=0; row<nrel; row++) {
3393 grad_obj[mtx_row_to_org(sys->lin_mtx,row)] =
3394 grad_obj[mtx_row_to_org(sys->lin_mtx,row)] * weights[row];
3395 }
3396
3397 /*
3398 * End of scaling
3399 */
3400
3401 lsys = linsolqr_create();
3402 linsolqr_set_matrix(lsys,sys->lin_mtx);
3403
3404 for (cr=0; cr<nrel; cr++) {
3405 multipliers->cols[subregion].element[cr] = 0.0;
3406 }
3407
3408 set_factor_options(lsys);
3409 /* rhs for multipliers */
3410 linsolqr_add_rhs(lsys,grad_obj,FALSE);
3411 linsolqr_set_region(lsys,*oneblock);
3412 linsolqr_factor(lsys,ranki_ba2);
3413 linsolqr_solve(lsys,grad_obj);
3414 for (cr=0; cr<nrel; cr++) {
3415 multipliers->cols[subregion].element[cr] = linsolqr_var_value
3416 (lsys,grad_obj,cr);
3417 #if SHOW_LAGRANGE_DETAILS
3418 FPRINTF(ASCERR, " Row = %d \n",cr);
3419 FPRINTF(ASCERR,
3420 "Multiplier = %f \n",multipliers->cols[subregion].element[cr]);
3421 #endif /* SHOW_LAGRANGE_DETAILS */
3422 }
3423 linsolqr_set_matrix(lsys,NULL);
3424 mtx_destroy(sys->lin_mtx);
3425 linsolqr_destroy(lsys);
3426 destroy_array(newblocks);
3427 destroy_array(weights);
3428 ascfree(oneblock);
3429 }
3430
3431
3432 /*
3433 * Calculate the invariant part of the gradients of the subregions
3434 */
3435 static
3436 void get_gradient_in_subregion(slv_system_t server,
3437 SlvClientToken asys,
3438 int32 subregion,
3439 int32 num_opt_eqns,
3440 struct opt_vector *gradient,
3441 struct opt_matrix *multipliers
3442 ){
3443 slv9_system_t sys;
3444 struct rel_relation **rlist;
3445 struct var_variable **vlist;
3446 struct rel_relation *rel;
3447 struct var_variable *var;
3448 var_filter_t vfilter;
3449 rel_filter_t rfilter;
3450 mtx_coord_t coord;
3451 real64 *tmp_value;
3452 real64 *derivatives, resid;
3453 real64 *grad_obj, *func_val;
3454 real64 *f_red_grad;
3455 struct opt_matrix rel_red_grad;
3456 int32 *variables_master, *variables_solver, count;
3457 int32 nvar, nrel, ntotvar, ntotrel;
3458 int32 countrel,countvar,cr,cv,len,vind;
3459 int32 nvnb, countnbv;
3460 FILE *lif;
3461
3462 sys = SLV9(asys);
3463 check_system(sys);
3464 lif = LIF(sys);
3465
3466 rlist = slv_get_master_rel_list(server);
3467 vlist = slv_get_master_var_list(server);
3468 ntotvar = slv_get_num_master_vars(server);
3469 ntotrel = slv_get_num_master_rels(server);
3470 tmp_value = ASC_NEW_ARRAY(real64,ntotvar);
3471
3472 vfilter.matchbits = (VAR_ACTIVE | VAR_INCIDENT | VAR_NONBASIC
3473 | VAR_SVAR | VAR_FIXED);
3474 vfilter.matchvalue = (VAR_ACTIVE | VAR_INCIDENT | VAR_SVAR);
3475 nvar = slv_count_master_vars(server,&vfilter);
3476
3477 rfilter.matchbits = (REL_INCLUDED | REL_EQUALITY | REL_ACTIVE );
3478 rfilter.matchvalue =(REL_INCLUDED | REL_EQUALITY | REL_ACTIVE );
3479 nrel = slv_count_master_rels(server,&rfilter);
3480
3481 if(nrel != nvar) {
3482 FPRINTF(ASCERR," nrel = %d\n",nrel);
3483 FPRINTF(ASCERR," nvar = %d\n",nvar);
3484 FPRINTF(ASCERR,
3485 "PANIC: number relations does not match number of variables\n");
3486 }
3487
3488 /*
3489 * residual of the relations in the subregion
3490 */
3491 func_val = ASC_NEW_ARRAY(real64,nrel);
3492
3493 /*
3494 * Lagrange Multipliers of the subregion
3495 */
3496 multipliers->cols[subregion].element =
3497 (real64 *)(ascmalloc(nrel*sizeof(real64)));
3498 /*
3499 * Gradients of the objective function
3500 */
3501 grad_obj = ASC_NEW_ARRAY(real64,nvar);
3502
3503 /*
3504 * Matrix for solving linear system
3505 */
3506 sys->lin_mtx = mtx_create();
3507 mtx_set_order(sys->lin_mtx,nrel);
3508
3509 /*
3510 * Counting nonbasic variables
3511 */
3512 vfilter.matchbits = (VAR_ACTIVE | VAR_INCIDENT | VAR_NONBASIC
3513 | VAR_SVAR | VAR_FIXED);
3514 vfilter.matchvalue = (VAR_ACTIVE | VAR_INCIDENT | VAR_NONBASIC
3515 | VAR_SVAR);
3516 nvnb = slv_count_master_vars(server,&vfilter);
3517
3518 /*
3519 * Information for reduced gradient
3520 */
3521 f_red_grad = ASC_NEW_ARRAY(real64,nvnb);
3522 rel_red_grad.cols = (struct opt_vector *)
3523 (ascmalloc(nvnb*sizeof(struct opt_vector)));
3524 for (cv=0; cv<nvnb; cv++) {
3525 rel_red_grad.cols[cv].element =
3526 (real64 *)(ascmalloc(nrel*sizeof(real64)));
3527 }
3528
3529 /*
3530 * Setting every sindex to -1
3531 */
3532 for (cv=0; cv<ntotvar; cv++) {
3533 var_set_sindex(vlist[cv],-1);
3534 }
3535 for (cr=0; cr<ntotrel; cr++) {
3536 rel_set_sindex(rlist[cr],-1);
3537 }
3538
3539 /*
3540 * Initializing values
3541 */
3542 for (cv=0; cv<ntotvar;cv++) {
3543 tmp_value[cv] = 0.0;
3544 }
3545 for (cv=0; cv<num_opt_eqns;cv++) {
3546 gradient->element[cv] = 0.0;
3547 }
3548
3549 for (cr=0; cr<nrel; cr++) {
3550 func_val[cr] = 0.0;
3551 multipliers->cols[subregion].element[cr] = 0.0;
3552 }
3553
3554 for (cv=0; cv<nvnb; cv++) {
3555 f_red_grad[cv] = 0.0;
3556 for (cr=0; cr<nrel; cr++) {
3557 rel_red_grad.cols[cv].element[cr] = 0.0;
3558 }
3559 }
3560
3561 for (cv=0; cv<nvar; cv++) {
3562 grad_obj[cv] = 0.0;
3563 }
3564
3565 /*
3566 * Calculate Values
3567 */
3568 vfilter.matchbits = (VAR_ACTIVE_AT_BND | VAR_INCIDENT
3569 | VAR_SVAR | VAR_FIXED);
3570 vfilter.matchvalue = (VAR_ACTIVE_AT_BND | VAR_INCIDENT | VAR_SVAR);
3571
3572 /*
3573 * List of relations
3574 */
3575 countrel = 0;
3576 countvar = 0;
3577 countnbv = 0;
3578 for (cr=0; cr<ntotrel; cr++) {
3579 rel = rlist[cr];
3580 if(rel_apply_filter(rel,&rfilter)) {
3581 rel_set_sindex(rel,countrel);
3582 coord.col = rel_sindex(rel);
3583 len = rel_n_incidences(rel);
3584 variables_master = ASC_NEW_ARRAY(int32,len);
3585 variables_solver = ASC_NEW_ARRAY(int32,len);
3586 derivatives = ASC_NEW_ARRAY(real64,len);
3587 relman_diff_grad(rel,&vfilter,derivatives,variables_master,
3588 variables_solver,&count,&resid,1);
3589 func_val[countrel] = resid;
3590 #if SHOW_LAGRANGE_DETAILS
3591 FPRINTF(ASCERR,"Equation = %d \n",coord.col);
3592 FPRINTF(ASCERR,"Residual = %f \n",resid);
3593 #endif /* SHOW_LAGRANGE_DETAILS */
3594 for (cv=0; cv<count;cv++) {
3595 var = vlist[variables_master[cv]];
3596 if(!var_nonbasic(var)) {
3597 tmp_value[variables_master[cv]] = tmp_value[variables_master[cv]] +
3598 derivatives[cv] * RHO * resid;
3599 if(var_active(var)) {
3600 coord.row = var_sindex(var);
3601 if(coord.row == -1) {
3602 var_set_sindex(var,countvar);
3603 coord.row = countvar;
3604 countvar++;
3605 }
3606 assert(coord.col >= 0 && coord.col < mtx_order(sys->lin_mtx));
3607 #if SHOW_LAGRANGE_DETAILS
3608 FPRINTF(ASCERR,"Coordinate row = %d \n",coord.row);
3609 FPRINTF(ASCERR,"Coordinate col = %d \n",coord.col);
3610 FPRINTF(ASCERR,"Derivative = %f \n",derivatives[cv]);
3611 #endif /* SHOW_LAGRANGE_DETAILS */
3612 mtx_fill_org_value(sys->lin_mtx,&coord,derivatives[cv]);
3613 }
3614 }else{
3615 if(var_sindex(var)== -1) {
3616 var_set_sindex(var,countnbv);
3617 countnbv++;
3618 }
3619 rel_red_grad.cols[var_sindex(var)].element[countrel] =
3620 derivatives[cv];
3621 #if SHOW_LAGRANGE_DETAILS
3622 FPRINTF(lif,"Nonbasic Variable ");
3623 print_var_name(lif,sys,var); PUTC('\n',lif);
3624 FPRINTF(ASCERR,"Derivative = %f \n",derivatives[cv]);
3625 #endif /* SHOW_LAGRANGE_DETAILS */
3626 }
3627 }
3628 destroy_array(variables_master);
3629 destroy_array(variables_solver);
3630 destroy_array(derivatives);
3631 countrel++;
3632 }
3633 }
3634
3635 /*
3636 * Objective function
3637 */
3638 rel = sys->obj;
3639 len = rel_n_incidences(rel);
3640 variables_master = ASC_NEW_ARRAY(int32,len);
3641 variables_solver = ASC_NEW_ARRAY(int32,len);
3642 derivatives = ASC_NEW_ARRAY(real64,len);
3643 relman_diff_grad(rel,&vfilter,derivatives,variables_master,
3644 variables_solver,&count,&resid,1);
3645 for (cv=0; cv<count;cv++) {
3646 var = vlist[variables_master[cv]];
3647 if(!var_nonbasic(var)) {
3648 #if SHOW_LAGRANGE_DETAILS
3649 FPRINTF(ASCERR,"Objective row = %d \n",var_sindex(var));
3650 FPRINTF(ASCERR,"Derivative = %f \n",derivatives[cv]);
3651 #endif /* SHOW_LAGRANGE_DETAILS */
3652 grad_obj[var_sindex(var)] = -1.0 * derivatives[cv];
3653 }else{
3654 #if SHOW_LAGRANGE_DETAILS
3655 FPRINTF(ASCERR,"Non Basic Variable = %d \n",var_sindex(var));
3656 FPRINTF(ASCERR,"Derivative in Objective = %f \n",derivatives[cv]);
3657 #endif /* SHOW_LAGRANGE_DETAILS */
3658 f_red_grad[var_sindex(var)] = derivatives[cv] ;
3659 }
3660 }
3661 destroy_array(variables_master);
3662 destroy_array(variables_solver);
3663 destroy_array(derivatives);
3664
3665 /*
3666 * Solving Linear System
3667 */
3668 get_multipliers(asys,subregion,nrel,grad_obj,multipliers);
3669
3670 countvar = 0;
3671 for (cv = 0; cv<ntotvar; cv++) {
3672 var = vlist[cv];
3673 if(var_apply_filter(var,&vfilter)) {
3674 if(!var_nonbasic(var)) {
3675 gradient->element[countvar] = tmp_value[cv];
3676 countvar++;
3677 }else{
3678 vind = var_sindex(var);
3679 if((vind != -1) && (vind < nvnb) ) {
3680 gradient->element[countvar] = f_red_grad[vind];
3681 for (cr=0; cr<nrel; cr++) {
3682 gradient->element[countvar] = gradient->element[countvar] +
3683 ( rel_red_grad.cols[vind].element[cr] *
3684 ( multipliers->cols[subregion].element[cr] +
3685 ( RHO * func_val[cr] ) ) );
3686 }
3687 countvar++;
3688 }
3689 }
3690 }
3691 }
3692 gradient->element[countvar] = 1.0;
3693
3694 destroy_array(tmp_value);
3695 destroy_array(func_val);
3696 destroy_array(grad_obj);
3697 destroy_array(f_red_grad);
3698 for (cv=0; cv<nvnb; cv++) {
3699 destroy_array(rel_red_grad.cols[cv].element);
3700 }
3701 destroy_array(rel_red_grad.cols);
3702
3703 if(countrel != nrel) {
3704 FPRINTF(ASCERR,"PANIC: number of invariant relations does not match\n");
3705 }
3706
3707 if(countvar != ( num_opt_eqns - 1)) {
3708 FPRINTF(ASCERR,"PANIC: number of variables does not match at boundary\n");
3709 }
3710 /*
3711 if(countvar != nvar) {
3712 FPRINTF(ASCERR,"PANIC: number of variables does not match at boundary\n");
3713 }
3714 */
3715 }
3716
3717
3718 /*
3719 * Calculate the invariant part of the norm of the objective function
3720 */
3721 static
3722 real64 get_augmented_function_in_subregion(slv_system_t server,
3723 SlvClientToken asys,
3724 int32 subregion,
3725 struct opt_matrix *multipliers)
3726 {
3727 slv9_system_t sys;
3728 struct rel_relation **rlist;
3729 struct rel_relation *rel;
3730 rel_filter_t rfilter;
3731 real64 resid, sqrnorm;
3732 int32 status;
3733 int32 nrel,ntotrel;
3734 int32 countrel,cr;
3735
3736 sys = SLV9(asys);
3737 check_system(sys);
3738
3739 rlist = slv_get_master_rel_list(server);
3740 ntotrel = slv_get_num_master_rels(server);
3741
3742 rfilter.matchbits = (REL_INCLUDED | REL_EQUALITY
3743 | REL_ACTIVE);
3744 rfilter.matchvalue =(REL_INCLUDED | REL_EQUALITY
3745 | REL_ACTIVE);
3746 nrel = slv_count_master_rels(server,&rfilter);
3747
3748 sqrnorm = 0.0;
3749 countrel = 0;
3750
3751 #ifdef ASC_SIGNAL_TRAPS
3752 Asc_SignalHandlerPush(SIGFPE,SIG_IGN);
3753 #endif
3754
3755 for (cr=0; cr<ntotrel; cr++) {
3756 rel = rlist[cr];
3757 if(rel_apply_filter(rel,&rfilter)) {
3758 resid = relman_eval(rel, &status, 1);
3759 sqrnorm = sqrnorm + (resid *
3760 ( multipliers->cols[subregion].element[countrel] +
3761 ( (RHO/2) *resid ) ) );
3762 countrel++;
3763 }
3764 }
3765 rel = sys->obj;
3766 resid = relman_eval(rel, &status, 1);
3767
3768 #ifdef ASC_SIGNAL_TRAPS
3769 Asc_SignalHandlerPop(SIGFPE,SIG_IGN);
3770 #endif
3771
3772 sqrnorm = sqrnorm + resid;
3773
3774 if(countrel != nrel) {
3775 FPRINTF(ASCERR,"PANIC: number of invariant relations does not match\n");
3776 }
3777 return sqrnorm;
3778 }
3779
3780
3781 /*
3782 * Calculate the invariant part of the gradients of the subregions
3783 */
3784 static
3785 void get_invariant_of_gradient_in_subregions(slv_system_t server,
3786 int32 num_opt_eqns,
3787 struct opt_vector *invariant
3788 ){
3789 struct rel_relation **rlist;
3790 struct var_variable **vlist;
3791 struct rel_relation *rel;
3792 var_filter_t vfilter;
3793 rel_filter_t rfilter;
3794 real64 *tmp_value;
3795 real64 *derivatives, resid;
3796 int32 *variables, *varsindex, count;
3797 int32 nvar, nrel, ntotvar, ntotrel;
3798 int32 countrel,countvar,cr,cv,len;
3799
3800 rlist = slv_get_master_rel_list(server);
3801 vlist = slv_get_master_var_list(server);
3802 ntotvar = slv_get_num_master_vars(server);
3803 ntotrel = slv_get_num_master_rels(server);
3804 tmp_value = ASC_NEW_ARRAY(real64,ntotvar);
3805
3806 vfilter.matchbits = (VAR_ACTIVE_AT_BND | VAR_INCIDENT
3807 | VAR_SVAR | VAR_FIXED);
3808 vfilter.matchvalue = (VAR_ACTIVE_AT_BND | VAR_INCIDENT | VAR_SVAR);
3809 nvar = slv_count_master_vars(server,&vfilter);
3810
3811 rfilter.matchbits = (REL_INCLUDED | REL_EQUALITY
3812 | REL_ACTIVE | REL_INVARIANT);
3813 rfilter.matchvalue =(REL_INCLUDED | REL_EQUALITY
3814 | REL_ACTIVE | REL_INVARIANT);
3815 nrel = slv_count_master_rels(server,&rfilter);
3816
3817 for (cv=0; cv<ntotvar;cv++) {
3818 tmp_value[cv] = 0.0;
3819 }
3820
3821 for (cv=0; cv<num_opt_eqns;cv++) {
3822 invariant->element[cv] = 0.0;
3823 }
3824
3825 countrel = 0;
3826 for (cr=0; cr<ntotrel; cr++) {
3827 rel = rlist[cr];
3828 if(rel_apply_filter(rel,&rfilter)) {
3829 len = rel_n_incidences(rel);
3830 variables = ASC_NEW_ARRAY(int32,len);
3831 derivatives = ASC_NEW_ARRAY(real64,len);
3832 varsindex = ASC_NEW_ARRAY(int32,len);
3833 relman_diff_grad(rel,&vfilter,derivatives,variables,varsindex,
3834 &count,&resid,1);
3835 for (cv=0; cv<count;cv++) {
3836 tmp_value[variables[cv]] = tmp_value[variables[cv]] +
3837 derivatives[cv] * resid;
3838 }
3839 destroy_array(variables);
3840 destroy_array(varsindex);
3841 destroy_array(derivatives);
3842 countrel++;
3843 }
3844 }
3845
3846 countvar = 0;
3847 for (cv = 0; cv<ntotvar; cv++) {
3848 if(var_apply_filter(vlist[cv],&vfilter)) {
3849 invariant->element[countvar] = tmp_value[cv];
3850 countvar++;
3851 }
3852 }
3853 invariant->element[countvar] = 1.0;
3854 destroy_array(tmp_value);
3855
3856 if(countrel != nrel) {
3857 FPRINTF(ASCERR,"PANIC: number of invariant relations does not match\n");
3858 }
3859
3860 if(countvar != ( num_opt_eqns - 1)) {
3861 FPRINTF(ASCERR,"PANIC: number of variables does not match at boundary\n");
3862 }
3863
3864 if(countvar != nvar) {
3865 FPRINTF(ASCERR,"PANIC: number of variables does not match at boundary\n");
3866 }
3867
3868 }
3869
3870
3871 /*
3872 * Calculate the variant part of the gradients for the current subregion
3873 */
3874 static
3875 void get_variant_of_gradient_in_subregion(slv_system_t server,
3876 int32 num_opt_eqns,
3877 struct opt_vector *variant
3878 ){
3879 struct rel_relation **rlist;
3880 struct var_variable **vlist;
3881 struct rel_relation *rel;
3882 var_filter_t vfilter;
3883 rel_filter_t rfilter;
3884 real64 *tmp_value;
3885 real64 *derivatives, resid;
3886 int32 *variables, *varsindex, count;
3887 int32 nvar, nrel, ntotvar, ntotrel;
3888 int32 countrel,countvar,cr,cv,len;
3889
3890 rlist = slv_get_master_rel_list(server);
3891 vlist = slv_get_master_var_list(server);
3892 ntotvar = slv_get_num_master_vars(server);
3893 ntotrel = slv_get_num_master_rels(server);
3894 tmp_value = ASC_NEW_ARRAY(real64,ntotvar);
3895
3896 vfilter.matchbits = (VAR_ACTIVE_AT_BND | VAR_INCIDENT
3897 | VAR_SVAR | VAR_FIXED);
3898 vfilter.matchvalue = (VAR_ACTIVE_AT_BND | VAR_INCIDENT | VAR_SVAR);
3899 nvar = slv_count_master_vars(server,&vfilter);
3900
3901 rfilter.matchbits = (REL_INCLUDED | REL_EQUALITY
3902 | REL_ACTIVE | REL_IN_CUR_SUBREGION);
3903 rfilter.matchvalue =(REL_INCLUDED | REL_EQUALITY
3904 | REL_ACTIVE | REL_IN_CUR_SUBREGION);
3905 nrel = slv_count_master_rels(server,&rfilter);
3906
3907 for (cv=0; cv<ntotvar;cv++) {
3908 tmp_value[cv] = 0.0;
3909 }
3910
3911 for (cv=0; cv<num_opt_eqns;cv++) {
3912 variant->element[cv] = 0.0;
3913 }
3914
3915 countrel = 0;
3916 for (cr=0; cr<ntotrel; cr++) {
3917 rel = rlist[cr];
3918 if(rel_apply_filter(rel,&rfilter)) {
3919 len = rel_n_incidences(rel);
3920 variables = ASC_NEW_ARRAY(int32,len);
3921 derivatives = ASC_NEW_ARRAY(real64,len);
3922 varsindex = ASC_NEW_ARRAY(int32,len);
3923 relman_diff_grad(rel,&vfilter,derivatives,variables,varsindex,
3924 &count,&resid,1);
3925 for (cv=0; cv<count;cv++) {
3926 tmp_value[variables[cv]] = tmp_value[variables[cv]] +
3927 derivatives[cv] * resid;
3928 }
3929 destroy_array(variables);
3930 destroy_array(varsindex);
3931 destroy_array(derivatives);
3932 countrel++;
3933 }
3934 }
3935
3936 countvar = 0;
3937 for (cv = 0; cv<ntotvar; cv++) {
3938 if(var_apply_filter(vlist[cv],&vfilter)) {
3939 variant->element[countvar] = tmp_value[cv];
3940 countvar++;
3941 }
3942 }
3943 variant->element[countvar] = 0.0;
3944 destroy_array(tmp_value);
3945
3946 if(countrel != nrel) {
3947 FPRINTF(ASCERR,"PANIC: number of variant relations does not match\n");
3948 }
3949
3950 if(countvar != ( num_opt_eqns - 1)) {
3951 FPRINTF(ASCERR,"PANIC: number of variables does not match at boundary\n");
3952 }
3953
3954 if(countvar != nvar) {
3955 FPRINTF(ASCERR,"PANIC: number of variables does not match at boundary\n");
3956 }
3957
3958 }
3959
3960 /*
3961 * Calculate the invariant part of the norm of the objective function
3962 */
3963 static
3964 real64 get_invariant_of_obj_norm_in_subregions(slv_system_t server){
3965 struct rel_relation **rlist;
3966 struct rel_relation *rel;
3967 rel_filter_t rfilter;
3968 real64 resid, sqrnorm;
3969 int32 status;
3970 int32 nrel,ntotrel;
3971 int32 countrel,cr;
3972
3973 rlist = slv_get_master_rel_list(server);
3974 ntotrel = slv_get_num_master_rels(server);
3975
3976 rfilter.matchbits = (REL_INCLUDED | REL_EQUALITY
3977 | REL_ACTIVE | REL_INVARIANT);
3978 rfilter.matchvalue =(REL_INCLUDED | REL_EQUALITY
3979 | REL_ACTIVE | REL_INVARIANT);
3980 nrel = slv_count_master_rels(server,&rfilter);
3981
3982 sqrnorm = 0.0;
3983 countrel = 0;
3984
3985 #ifdef ASC_SIGNAL_TRAPS
3986 Asc_SignalHandlerPush(SIGFPE,SIG_IGN);
3987 #endif
3988
3989 for (cr=0; cr<ntotrel; cr++) {
3990 rel = rlist[cr];
3991 if(rel_apply_filter(rel,&rfilter)) {
3992 resid = relman_eval(rel, &status, 1);
3993 sqrnorm = sqrnorm + (resid * resid);
3994 countrel++;
3995 }
3996 }
3997
3998 #ifdef ASC_SIGNAL_TRAPS
3999 Asc_SignalHandlerPop(SIGFPE,SIG_IGN);
4000 #endif
4001
4002 if(countrel != nrel) {
4003 FPRINTF(ASCERR,"PANIC: number of invariant relations does not match\n");
4004 }
4005 return sqrnorm;
4006 }
4007
4008
4009 /*
4010 * Calculate the variant part of the norm of the objective function for a
4011 * particular subregion
4012 */
4013 static
4014 real64 get_variant_of_obj_norm_in_subregion(slv_system_t server){
4015 struct rel_relation **rlist;
4016 struct rel_relation *rel;
4017 rel_filter_t rfilter;
4018 real64 resid, sqrnorm;
4019 int32 status;
4020 int32 nrel,ntotrel;
4021 int32 countrel,cr;
4022
4023 rlist = slv_get_master_rel_list(server);
4024 ntotrel = slv_get_num_master_rels(server);
4025
4026 rfilter.matchbits = (REL_INCLUDED | REL_EQUALITY
4027 | REL_ACTIVE | REL_IN_CUR_SUBREGION);
4028 rfilter.matchvalue =(REL_INCLUDED | REL_EQUALITY
4029 | REL_ACTIVE | REL_IN_CUR_SUBREGION);
4030 nrel = slv_count_master_rels(server,&rfilter);
4031
4032 sqrnorm = 0.0;
4033 countrel = 0;
4034
4035 #ifdef ASC_SIGNAL_TRAPS
4036 Asc_SignalHandlerPush(SIGFPE,SIG_IGN);
4037 #endif
4038
4039 for (cr=0; cr<ntotrel; cr++) {
4040 rel = rlist[cr];
4041 if(rel_apply_filter(rel,&rfilter)) {
4042 resid = relman_eval(rel, &status, 1);
4043 sqrnorm = sqrnorm + (resid * resid);
4044 countrel++;
4045 }
4046 }
4047
4048 #ifdef ASC_SIGNAL_TRAPS
4049 Asc_SignalHandlerPop(SIGFPE,SIG_IGN);
4050 #endif
4051
4052 if(countrel != nrel) {
4053 FPRINTF(ASCERR,"PANIC: number of variant relations does not match\n");
4054 }
4055 return sqrnorm;
4056 }
4057
4058
4059 /*
4060 * Fill a column of the coefficient matrix used for the optimization
4061 * problem at a boundary
4062 */
4063 static
4064 void fill_opt_matrix_cols_with_vectors(int32 num_opt_eqns, int32 n,
4065 struct opt_matrix *coeff_matrix,
4066 struct opt_vector *invariant,
4067 struct opt_vector *variant,
4068 struct opt_vector *gradient
4069 ){
4070 int32 num_eqn;
4071 real64 norm2;
4072
4073 norm2 = 0.0;
4074 for(num_eqn=0; num_eqn<num_opt_eqns; num_eqn++) {
4075 if(g_optimizing) {
4076 coeff_matrix->cols[n].element[num_eqn] = gradient->element[num_eqn];
4077 }else{
4078 coeff_matrix->cols[n].element[num_eqn] = invariant->element[num_eqn] +
4079 variant->element[num_eqn];
4080 }
4081 if(num_eqn < (num_opt_eqns - 1) ) {
4082 #if SHOW_OPTIMIZATION_DETAILS
4083 if(g_optimizing) {
4084 FPRINTF(ASCERR," gradient = %f \n", gradient->element[num_eqn]);
4085 }else{
4086 FPRINTF(ASCERR," variant = %f \n", variant->element[num_eqn]);
4087 FPRINTF(ASCERR," invariant = %f \n", invariant->element[num_eqn]);
4088 }
4089 #endif /* SHOW_OPTIMIZATION_DETAILS */
4090 norm2 = norm2 + ( coeff_matrix->cols[n].element[num_eqn] *
4091 coeff_matrix->cols[n].element[num_eqn] );
4092 }
4093 }
4094
4095 norm2 = sqrt(norm2);
4096
4097 for(num_eqn=0; num_eqn<num_opt_eqns-1; num_eqn++) {
4098
4099 #if SHOW_OPTIMIZATION_DETAILS
4100 FPRINTF(ASCERR," coefficient before normalize = %f \n",
4101 coeff_matrix->cols[n].element[num_eqn]);
4102 #endif /* SHOW_OPTIMIZATION_DETAILS */
4103 coeff_matrix->cols[n].element[num_eqn] =
4104 coeff_matrix->cols[n].element[num_eqn] / norm2;
4105 #if SHOW_OPTIMIZATION_DETAILS
4106 FPRINTF(ASCERR," coefficient = %f \n",
4107 coeff_matrix->cols[n].element[num_eqn]);
4108 #endif /* SHOW_OPTIMIZATION_DETAILS */
4109 }
4110 }
4111
4112
4113
4114 /*
4115 * Analyzes the result of the optimization problem.
4116 * Adds to each var value the var step given by the optimization problem
4117 * at a boundary.
4118 * It projects a variable to its bounds if required.
4119 */
4120 static
4121 void apply_optimization_step(slv_system_t server, SlvClientToken asys,
4122 int32 n_subregions,
4123 struct opt_vector *values,
4124 real64 factor,
4125 struct real_values *rvalues
4126 ){
4127 slv9_system_t sys;
4128 struct var_variable **vlist;
4129 struct var_variable *var;
4130 var_filter_t vfilter;
4131 int32 totvars, num_vars, num_tot, c, count;
4132 real64 nominal, up, low, pre_val;
4133 real64 value, dx, test_value,norm2;
4134 FILE *lif;
4135
4136 sys = SLV9(asys);
4137 check_system(sys);
4138 lif = LIF(sys);
4139
4140 vfilter.matchbits = (VAR_ACTIVE_AT_BND | VAR_INCIDENT
4141 | VAR_SVAR | VAR_FIXED);
4142 vfilter.matchvalue = (VAR_ACTIVE_AT_BND | VAR_INCIDENT | VAR_SVAR);
4143 vlist = slv_get_master_var_list(server);
4144 num_vars = slv_count_master_vars(server,&vfilter);
4145 totvars = slv_get_num_master_vars(server);
4146
4147 count = 0;
4148 norm2 = 0.0;
4149 for (c=0; c<totvars; c++) {
4150 var = vlist[c];
4151 if(var_apply_filter(var,&vfilter)) {
4152 norm2 = norm2 + ( values->element[count] * values->element[count] );
4153 count++;
4154 }
4155 }
4156 norm2 = sqrt(norm2);
4157
4158 count = 0;
4159 for (c=0; c<totvars; c++) {
4160 var = vlist[c];
4161 pre_val = rvalues->pre_values[c];
4162 if(var_apply_filter(var,&vfilter)) {
4163 nominal = var_nominal(var);
4164 low = var_lower_bound(var);
4165 up = var_upper_bound(var);
4166 dx = factor * ( values->element[count] / norm2 );
4167 #if SHOW_OPTIMIZATION_DETAILS
4168 FPRINTF(lif,"Variable ");
4169 print_var_name(lif,sys,var); PUTC('\n',lif);
4170 FPRINTF(lif,"dx = %f\n",dx);
4171 #endif /* SHOW_OPTIMIZATION_DETAILS */
4172 test_value = pre_val + dx;
4173 if((test_value < low) || (test_value > up) ) {
4174 if(test_value < low) {
4175 value = low;
4176 if(SHOW_LESS_IMPT) {
4177 FPRINTF(lif,"%-40s ---> ",
4178 " Variable projected to lower bound");
4179 print_var_name(lif,sys,var); PUTC('\n',lif);
4180 }
4181 }else{
4182 value = up;
4183 if(SHOW_LESS_IMPT) {
4184 FPRINTF(lif,"%-40s ---> ",
4185 " Variable projected to upper bound");
4186 print_var_name(lif,sys,var); PUTC('\n',lif);
4187 }
4188 }
4189 }else{
4190 value = test_value;
4191 }
4192 var_set_value(var,value);
4193 #if SHOW_OPTIMIZATION_DETAILS
4194 FPRINTF(lif,"value = %f\n",value);
4195 #endif /* SHOW_OPTIMIZATION_DETAILS */
4196 count++;
4197 }
4198 }
4199 /*
4200 * num_tot is to stop gcc whining about unused parameters
4201 */
4202 num_tot = num_vars+n_subregions;
4203
4204 #if DEBUG
4205 for(c=count; c<num_tot; c++) {
4206 FPRINTF(ASCERR," coefficient of subregion %d = %f \n",
4207 c-count+1,values->element[c]);
4208 }
4209 #endif /* DEBUG */
4210 }
4211
4212
4213 /*
4214 * Creates the problem at a boundary and call the appropriate CONOPT
4215 * subroutines to perform the optimization problem.
4216 */
4217 static
4218 int32 optimize_at_boundary(slv_system_t server, SlvClientToken asys,
4219 int32 *n_subregions,
4220 struct matching_cases *subregions,
4221 int32 *cur_subregion,
4222 struct gl_list_t *disvars,
4223 struct real_values *rvalues
4224 ){
4225 slv9_system_t sys;
4226 struct rel_relation **rlist;
4227 struct var_variable **vlist;
4228 struct opt_matrix coeff_matrix;
4229 struct opt_vector opt_var_values;
4230 struct opt_vector invariant_vect_values;
4231 struct opt_vector variant_vect_values;
4232 struct opt_vector gradient;
4233 struct opt_matrix multipliers;
4234 var_filter_t vfilter;
4235 int32 num_vars,num_opt_eqns, num_opt_vars;
4236 int32 n, return_value, niter;
4237 int32 global_decrease, red_step;
4238 real64 obj_val=0.0, factor;
4239 real64 invnorm=0.0, *varnorm, *testnorm;
4240 int32 ntotvar, ntotrel, cr, cv;
4241 int32 *var_ind, *rel_ind;
4242
4243 #if SHOW_OPTIMIZATION_DETAILS
4244 int32 nc; /* stop gcc whining about unused variables */
4245 #endif
4246
4247 sys = SLV9(asys);
4248 check_system(sys);
4249
4250 rlist = slv_get_master_rel_list(server);
4251 vlist = slv_get_master_var_list(server);
4252 ntotvar = slv_get_num_master_vars(server);
4253 ntotrel = slv_get_num_master_rels(server);
4254 /*
4255 * keep current sindex of variables and relations
4256 */
4257 var_ind = ASC_NEW_ARRAY(int32,ntotvar);
4258 rel_ind = ASC_NEW_ARRAY(int32,ntotrel);
4259 for (cv=0; cv<ntotvar; cv++) {
4260 var_ind[cv] = var_sindex(vlist[cv]);
4261 }
4262 for (cr=0; cr<ntotrel; cr++) {
4263 rel_ind[cr] = rel_sindex(rlist[cr]);
4264 }
4265
4266
4267 set_active_vars_at_bnd(server,disvars);
4268 vfilter.matchbits = (VAR_ACTIVE_AT_BND | VAR_INCIDENT
4269 | VAR_SVAR | VAR_FIXED);
4270 vfilter.matchvalue = (VAR_ACTIVE_AT_BND | VAR_INCIDENT | VAR_SVAR);
4271 num_vars = slv_count_master_vars(server,&vfilter);
4272 num_opt_eqns = num_vars + 1;
4273 num_opt_vars = num_vars + (*n_subregions);
4274
4275 create_opt_matrix_and_vectors(num_opt_eqns,(*n_subregions),&coeff_matrix,
4276 &opt_var_values,&invariant_vect_values,
4277 &variant_vect_values,&gradient,&multipliers);
4278
4279 identify_invariant_rels_at_bnd(server,disvars);
4280
4281 if(!g_optimizing) {
4282 get_invariant_of_gradient_in_subregions(server,num_opt_eqns,
4283 &invariant_vect_values);
4284 }
4285
4286 for (n=0;n<(*n_subregions);n++) {
4287 #if SHOW_OPTIMIZATION_DETAILS
4288 FPRINTF(ASCERR, "subregion = %d \n",n+1);
4289 for (nc=0; nc<subregions[n].ncases; nc++) {
4290 FPRINTF(ASCERR, "case %d = %d \n",nc+1,subregions[n].case_list[nc]);
4291 }
4292 #endif /* SHOW_OPTIMIZATION_DETAILS */
4293 set_active_rels_in_subregion(server,subregions[n].case_list,
4294 subregions[n].ncases,disvars);
4295 set_active_vars_in_subregion(server);
4296 identify_variant_rels_in_subregion(server);
4297 if(g_optimizing) {
4298 get_gradient_in_subregion(server,asys,n,num_opt_eqns,
4299 &gradient,&multipliers);
4300 }else{
4301 get_variant_of_gradient_in_subregion(server,num_opt_eqns,
4302 &variant_vect_values);
4303 }
4304 fill_opt_matrix_cols_with_vectors(num_opt_eqns,n,&coeff_matrix,
4305 &invariant_vect_values,&variant_vect_values,
4306 &gradient);
4307 }
4308
4309 sys->coeff_matrix = &coeff_matrix;
4310 sys->opt_var_values = &opt_var_values;
4311 sys->subregions = (*n_subregions);
4312
4313 #ifdef ASC_WITH_CONOPT
4314 /* CONOPT parameters */
4315 sys->con.n = num_opt_vars;
4316 sys->con.m = num_opt_eqns + 1; /*including objective function */
4317 sys->con.objcon = num_opt_eqns; /* last row is the objective fn */
4318 sys->con.nz = (num_opt_eqns * sys->subregions) + 2 * num_vars;
4319 /* sys->con.nlnz = sys->con.nz - (num_opt_eqns - 1); */
4320 sys->con.nlnz = num_opt_vars - sys->subregions;
4321 sys->con.base = 0; /* C calling convention */
4322 sys->con.optdir = -1; /* minimisation */
4323
4324 CONSOLE_DEBUG("%d vars, %d rows",sys->con.n,sys->con.m);
4325 CONSOLE_DEBUG("objective constraint: %d",sys->con.objcon);
4326 CONSOLE_DEBUG("nonzeros: %d",sys->con.nz);
4327 CONSOLE_DEBUG("nonlinear nonzeros: %d",sys->con.nlnz);
4328
4329 /* Perform optimisation using CONOPT */
4330 slv_conopt_iterate(sys);
4331 obj_val = sys->con.obj;
4332
4333 #if DEBUG
4334 FPRINTF(ASCERR," objective function = %f \n",obj_val);
4335 #endif /* DEBUG */
4336
4337 #endif /* ASC_WITH_CONOPT */
4338
4339 /*
4340 * Analyze and apply CONOPT step
4341 */
4342
4343 if(fabs(obj_val) > OBJ_TOL) {
4344
4345 return_value = 1;
4346
4347 varnorm = (real64 *)ascmalloc((*n_subregions)*sizeof(real64));
4348
4349 identify_invariant_rels_at_bnd(server,disvars);
4350
4351 if(!g_optimizing) {
4352 invnorm = get_invariant_of_obj_norm_in_subregions(server);
4353 }
4354
4355 #if SHOW_LINEAR_SEARCH_DETAILS
4356 FPRINTF(ASCERR,"Norms of subregions before gradient step:\n");
4357 #endif /* SHOW_LINEAR_SEARCH_DETAILS */
4358
4359 for (n=0;n<(*n_subregions);n++) {
4360 varnorm[n] = 0.0;
4361 set_active_rels_in_subregion(server,subregions[n].case_list,
4362 subregions[n].ncases,disvars);
4363 set_active_vars_in_subregion(server);
4364 identify_variant_rels_in_subregion(server);
4365 if(g_optimizing) {
4366 varnorm[n] = get_augmented_function_in_subregion(server,asys,n,
4367 &multipliers);
4368 }else{
4369 varnorm[n] = get_variant_of_obj_norm_in_subregion(server);
4370 varnorm[n] = varnorm[n] + invnorm;
4371 varnorm[n] = sqrt(varnorm[n]);
4372 }
4373 #if SHOW_LINEAR_SEARCH_DETAILS
4374 FPRINTF(ASCERR,"Norm of subregion %d = %f \n",n+1,varnorm[n]);
4375 #endif /* SHOW_LINEAR_SEARCH_DETAILS */
4376 }
4377
4378 global_decrease = 0;
4379 niter = 0;
4380 factor = LINEAR_SEARCH_FACTOR;
4381
4382 #if SHOW_LINEAR_SEARCH_DETAILS
4383 FPRINTF(ASCERR,"Initial factor in linear search = %f \n",factor);
4384 #endif /* SHOW_LINEAR_SEARCH_DETAILS */
4385
4386 testnorm = (real64 *)ascmalloc((*n_subregions)*sizeof(real64));
4387
4388 while (global_decrease == 0) {
4389 niter++;
4390 if(niter > ITER_BIS_LIMIT) {
4391 ERROR_REPORTER_HERE(ASC_PROG_WARNING,"Could not reduce the residuals of all the neighboring subregions.");
4392 return_value = 0;
4393 break;
4394 }
4395
4396 if((factor*factor*obj_val) < OBJ_TOL) {
4397 ERROR_REPORTER_HERE(ASC_PROG_WARNING,"Could not reduce the residuals of all the neighboring subregions.");
4398 return_value = 0;
4399 break;
4400 }
4401
4402 apply_optimization_step(server,asys,*n_subregions,
4403 sys->opt_var_values,factor,rvalues);
4404 identify_invariant_rels_at_bnd(server,disvars);
4405 if(!g_optimizing) {
4406 invnorm = get_invariant_of_obj_norm_in_subregions(server);
4407 }
4408
4409 for (n=0;n<(*n_subregions);n++) {
4410 testnorm[n] = 0.0;
4411 set_active_rels_in_subregion(server,subregions[n].case_list,
4412 subregions[n].ncases,disvars);
4413 identify_variant_rels_in_subregion(server);
4414
4415 if(g_optimizing) {
4416 testnorm[n] = get_augmented_function_in_subregion(server,asys,n,
4417 &multipliers);
4418 }else{
4419 testnorm[n] = get_variant_of_obj_norm_in_subregion(server);
4420 testnorm[n] = testnorm[n] + invnorm;
4421 testnorm[n] = sqrt(testnorm[n]);
4422 }
4423 }
4424
4425 red_step = 0;
4426 for (n=0;n<(*n_subregions);n++) {
4427 if(testnorm[n] > varnorm[n]) {
4428 factor = 0.5 * factor;
4429 red_step = 1;
4430 #if SHOW_LINEAR_SEARCH_DETAILS
4431 FPRINTF(ASCERR,"Subregion %d :\n",n+1);
4432 FPRINTF(ASCERR,"Norm after gradient step > Norm before step\n");
4433 FPRINTF(ASCERR," %f > %f\n",testnorm[n],varnorm[n]);
4434 FPRINTF(ASCERR,"New factor = %f \n",factor);
4435 #endif /* SHOW_LINEAR_SEARCH_DETAILS */
4436 break;
4437 }
4438 }
4439
4440 if(!red_step) {
4441 global_decrease = 1;
4442 #if SHOW_LINEAR_SEARCH_DETAILS
4443 FPRINTF(ASCERR,"factor accepted \n");
4444 FPRINTF(ASCERR,"factor in linear search = %f \n",factor);
4445 FPRINTF(ASCERR,"\n");
4446 #endif /* SHOW_LINEAR_SEARCH_DETAILS */
4447 }
4448 }
4449 /*
4450 * destroy arrays containing the two norm of the subregion
4451 */
4452 destroy_array(varnorm);
4453 destroy_array(testnorm);
4454 }else{
4455 return_value = 0;
4456 }
4457
4458 /*
4459 * Returning to initial configuration
4460 */
4461 set_active_rels_in_subregion(server,subregions[(*cur_subregion)].case_list,
4462 subregions[(*cur_subregion)].ncases,disvars);
4463 set_active_vars_in_subregion(server);
4464 identify_variant_rels_in_subregion(server);
4465
4466 /*
4467 * Assigning initial value of sindex for variables and relations
4468 */
4469 for (cv=0; cv<ntotvar; cv++) {
4470 var_set_sindex(vlist[cv],var_ind[cv]);
4471 }
4472 for (cr=0; cr<ntotrel; cr++) {
4473 rel_set_sindex(rlist[cr],rel_ind[cr]);
4474 }
4475
4476 /*
4477 * destroy matrix, arrays of reals containing gradients, the
4478 * list of cases for each subregion and the array subregion.
4479 */
4480
4481 destroy_opt_matrix_and_vectors((*n_subregions),&coeff_matrix,
4482 &opt_var_values,&invariant_vect_values,
4483 &variant_vect_values,&gradient,
4484 &multipliers);
4485 sys->coeff_matrix = NULL;
4486 if((*n_subregions) > 0) {
4487 for(n=0; n<(*n_subregions);n++) {
4488 destroy_array(subregions[n].case_list);
4489 }
4490 }
4491 destroy_array(subregions);
4492 destroy_array(var_ind);
4493 destroy_array(rel_ind);
4494 return return_value;
4495 }
4496
4497
4498 /*------------------------------------------------------------------------------
4499 ITERATION BEGIN/END ROUTINES
4500
4501 iteration_begins(sys)
4502 iteration_ends(sys)
4503 */
4504
4505 /*
4506 * Prepares sys for entering an iteration, increasing the iteration counts
4507 * and starting the clock.
4508 */
4509 static
4510 void iteration_begins(slv9_system_t sys){
4511 sys->clock = tm_cpu_time();
4512 ++(sys->s.block.iteration);
4513 ++(sys->s.iteration);
4514 if(SHOW_LESS_IMPT&& (sys->s.block.current_size >1 )) {
4515 FPRINTF(LIF(sys),"\n%-40s ---> %d\n",
4516 "Iteration", sys->s.block.iteration);
4517 FPRINTF(LIF(sys),"%-40s ---> %d\n",
4518 "Total iteration", sys->s.iteration);
4519 }
4520 }
4521
4522 /*
4523 * Prepares sys for exiting an iteration, stopping the clock and recording
4524 * the cpu time.
4525 */
4526 static
4527 void iteration_ends( slv9_system_t sys){
4528 double cpu_elapsed; /* elapsed this iteration */
4529
4530 cpu_elapsed = (double)(tm_cpu_time() - sys->clock);
4531 sys->s.block.cpu_elapsed += cpu_elapsed;
4532 sys->s.cpu_elapsed += cpu_elapsed;
4533 if(SHOW_LESS_IMPT && (sys->s.block.current_size >1 )) {
4534 FPRINTF(LIF(sys),"%-40s ---> %g\n",
4535 "Elapsed time", sys->s.block.cpu_elapsed);
4536 FPRINTF(LIF(sys),"%-40s ---> %g\n",
4537 "Total elapsed time", sys->s.cpu_elapsed);
4538 }
4539 }
4540
4541
4542 /*
4543 * Updates the solver status.
4544 */
4545 static
4546 void update_status( slv9_system_t sys){
4547 boolean unsuccessful;
4548
4549 if(!sys->s.converged ) {
4550 sys->s.time_limit_exceeded = (sys->s.block.cpu_elapsed >= TIME_LIMIT);
4551 sys->s.iteration_limit_exceeded = (sys->s.block.iteration >= ITER_LIMIT);
4552 }
4553
4554 unsuccessful = sys->s.diverged || sys->s.inconsistent ||
4555 sys->s.iteration_limit_exceeded || sys->s.time_limit_exceeded;
4556
4557 sys->s.ready_to_solve = !unsuccessful && !sys->s.converged;
4558 sys->s.ok = !unsuccessful && sys->s.calc_ok && !sys->s.struct_singular;
4559 }
4560
4561
4562 /*
4563 * Updates the value of the flag unsuccessful based on the information
4564 * of the nonlinear solver (square or optimizer)
4565 */
4566 static
4567 boolean update_unsuccessful( slv9_system_t sys, slv_status_t *status){
4568 boolean unsuccessful;
4569
4570 sys->s.time_limit_exceeded = (sys->s.block.cpu_elapsed >= TIME_LIMIT);
4571 sys->s.iteration_limit_exceeded = (sys->s.block.iteration >= ITER_LIMIT);
4572
4573 unsuccessful = status->diverged || status->inconsistent ||
4574 sys->s.iteration_limit_exceeded || sys->s.time_limit_exceeded;
4575
4576 return unsuccessful;
4577 }
4578
4579
4580 /*
4581 * Updates structural information
4582 */
4583 static
4584 void update_struct_info( slv9_system_t sys, slv_status_t *status){
4585 sys->s.over_defined = status->over_defined;
4586 sys->s.under_defined = status->under_defined;
4587 sys->s.struct_singular = status->struct_singular;
4588 }
4589
4590
4591 /*
4592 * Updates the values of the block information in the conditional
4593 * solver (main) based on the information of the nonlinear solver (slave:
4594 * square solver or optimizer).
4595 * We definitely have to find a better way of communicating status
4596 * among solvers. I think the structure of the slv_status would have to be
4597 * modified accordingly to the need of each solver, however, the GUI is
4598 * completely dependent of the current structure, so I did not modify
4599 * that structure at all.
4600 */
4601 static
4602 void update_real_status(slv_status_t *main, slv_status_t *slave, int32 niter){
4603 main->block.number_of = slave->block.number_of;
4604 main->costsize = 1+slave->block.number_of;
4605 main->block.residual = slave->block.residual;
4606 main->block.current_size = slave->block.current_size;
4607 main->block.current_block = slave->block.current_block;
4608 if(niter ==1 ) {
4609 main->block.iteration = slave->block.iteration;
4610 }
4611 main->block.previous_total_size = slave->block.previous_total_size;
4612 }
4613
4614 /*------------------------------------------------------------------------------
4615 PARAMETER ASSIGNMENT
4616 */
4617
4618 static
4619 int32 slv9_get_default_parameters(slv_system_t server,
4620 SlvClientToken asys,
4621 slv_parameters_t *parameters
4622 ){
4623 slv9_system_t sys = NULL;
4624 union parm_arg lo,hi,val;
4625 struct slv_parameter *new_parms = NULL;
4626 int32 make_macros = 0;
4627 static char *logical_names[] = {
4628 "LRSlv"
4629 };
4630 static char *nonlinear_names[] = {
4631 "QRSlv"
4632 };
4633 static char *optimization_names[] = {
4634 "CONOPT"
4635 };
4636
4637 if(server != NULL && asys != NULL) {
4638 sys = SLV9(asys);
4639 make_macros = 1;
4640 }
4641
4642 if(parameters->parms == NULL) {
4643 /* an external client wants our parameter list.
4644 * an instance of slv9_system_structure has this pointer
4645 * already set in slv9_create
4646 */
4647 new_parms = (struct slv_parameter *)
4648 ascmalloc((slv9_PA_SIZE)*sizeof(struct slv_parameter));
4649 if(new_parms == NULL) {
4650 return -1;
4651 }
4652
4653 parameters->parms = new_parms;
4654 parameters->dynamic_parms = 1;
4655 }
4656 parameters->num_parms = 0;
4657
4658 /* begin defining parameters */
4659
4660 slv_define_parm(parameters, char_parm,
4661 "logsolvers", "logical solver", "logical solver",
4662 U_p_string(val,logical_names[0]),
4663 U_p_strings(lo,logical_names),
4664 U_p_int(hi,sizeof(logical_names)/sizeof(char *)),1);
4665 SLV_CPARM_MACRO(LOGSOLVER_OPTION_PTR,parameters);
4666
4667 slv_define_parm(parameters, char_parm,
4668 "nlsolvers", "nonlinear solver", "nonlinear solver",
4669 U_p_string(val,nonlinear_names[0]),
4670 U_p_strings(lo,nonlinear_names),
4671 U_p_int(hi,sizeof(nonlinear_names)/sizeof(char *)),1);
4672 SLV_CPARM_MACRO(NONLISOLVER_OPTION_PTR,parameters);
4673
4674 slv_define_parm(parameters, char_parm,
4675 "optsolvers", "optimization solver", "optimization solver",
4676 U_p_string(val,optimization_names[0]),
4677 U_p_strings(lo,optimization_names),
4678 U_p_int(hi,sizeof(optimization_names)/sizeof(char *)),1);
4679 SLV_CPARM_MACRO(OPTSOLVER_OPTION_PTR,parameters);
4680
4681 slv_define_parm(parameters, int_parm,
4682 "timelimit", "time limit (CPU sec/block)",
4683 "time limit (CPU sec/block)",
4684 U_p_int(val,1500),U_p_int(lo, 1),U_p_int(hi,20000),1);
4685 SLV_IPARM_MACRO(TIME_LIMIT_PTR,parameters);
4686
4687 slv_define_parm(parameters, int_parm,
4688 "iterationlimit", "max iterations/block",
4689 "max iterations/block",
4690 U_p_int(val, 30),U_p_int(lo, 1),U_p_int(hi,20000),1);
4691 SLV_IPARM_MACRO(ITER_LIMIT_PTR,parameters);
4692
4693 slv_define_parm(parameters, int_parm,
4694 "iterationbislimit",
4695 "max iterations in bisection for boundaries",
4696 "max iterations in bisection for boundaries",
4697 U_p_int(val, 50),U_p_int(lo, 1),U_p_int(hi,20000),1);
4698 SLV_IPARM_MACRO(ITER_BIS_LIMIT_PTR,parameters);
4699
4700 slv_define_parm(parameters, real_parm,
4701 "toosmall", "default for zero nominal",
4702 "default for zero nominal",
4703 U_p_real(val, 1e-8),U_p_real(lo, 1e-12),U_p_real(hi,1.0), 1);
4704 SLV_RPARM_MACRO(TOO_SMALL_PTR,parameters);
4705
4706 slv_define_parm(parameters, real_parm,
4707 "linearfactor", "initial factor for linear search",
4708 "initial factor for linear search",
4709 U_p_real(val, 0.01),U_p_real(lo, 1e-6),U_p_real(hi,1.0), 1);
4710 SLV_RPARM_MACRO(LINEAR_SEARCH_FACTOR_PTR,parameters);
4711
4712 slv_define_parm(parameters, bool_parm,
4713 "showmoreimportant", "showmoreimportant", "showmoreimportant",
4714 U_p_bool(val,1),U_p_bool(lo,0),U_p_bool(hi,1),-1);
4715 SLV_BPARM_MACRO(SHOW_MORE_IMPT_PTR,parameters);
4716
4717 slv_define_parm(parameters, bool_parm,
4718 "showlessimportant", "detailed solving info",
4719 "detailed solving info",
4720 U_p_bool(val, 0),U_p_bool(lo,0),U_p_bool(hi,1), 2);
4721 SLV_BPARM_MACRO(SHOW_LESS_IMPT_PTR,parameters);
4722
4723 slv_define_parm(parameters, bool_parm,
4724 "autoresolve", "auto-resolve", "auto-resolve",
4725 U_p_bool(val,1),U_p_bool(lo,0),U_p_bool(hi,1), 2);
4726 SLV_BPARM_MACRO(AUTO_RESOLVE_PTR,parameters);
4727
4728 slv_define_parm(parameters, real_parm,
4729 "rho", "penalty parameter for optimization",
4730 "penalty parameter",
4731 U_p_real(val,1),U_p_real(lo, 0),U_p_real(hi,10e100), 3);
4732 SLV_RPARM_MACRO(RHO_PTR,parameters);
4733
4734 slv_define_parm(parameters, real_parm,
4735 "undefined", "real considered as undefined by optimizer",
4736 "real considered as undefined",
4737 U_p_real(val, 1.2e20),U_p_real(lo, 0),U_p_real(hi,1.5e20), 3);
4738 SLV_RPARM_MACRO(UNDEFINED_PTR,parameters);
4739
4740 slv_define_parm(parameters, int_parm,
4741 "errlim",
4742 "maximum number of function errors in optimizer",
4743 "limit on function evaluation errors",
4744 U_p_int(val,6),U_p_int(lo,0),U_p_int(hi,MAX_INT),3);
4745 SLV_IPARM_MACRO(DOMLIM_PTR,parameters);
4746
4747 slv_define_parm(parameters, int_parm,
4748 "optiterlimit", "LFITER",
4749 "maximum number of iterations for optimizer",
4750 U_p_int(val, 100),U_p_int(lo, 1),U_p_int(hi,MAX_INT),3);
4751 SLV_IPARM_MACRO(OPT_ITER_LIMIT_PTR,parameters);
4752
4753 ERROR_REPORTER_HERE(ASC_PROG_WARNING,"Default value of RTMAX = %g",CONOPT_BOUNDLIMIT);
4754
4755 slv_define_parm(parameters, real_parm,
4756 "infinity","RTMAXV","internal value of infinity",
4757 U_p_real(val,CONOPT_BOUNDLIMIT),U_p_real(lo,10),U_p_real(hi,MAX_REAL),3);
4758 SLV_RPARM_MACRO(INFINITY_PTR,parameters);
4759
4760 slv_define_parm(parameters, real_parm,
4761 "objtol","RTOBJR",
4762 "relative objective tolerance in optimization step",
4763 U_p_real(val,1e-13),U_p_real(lo,0),U_p_real(hi,1),3);
4764 SLV_RPARM_MACRO(OBJ_TOL_PTR,parameters);
4765
4766 slv_define_parm(parameters, real_parm,
4767 "maxjac","RTMAXJ",
4768 "maximum derivative in optimization step"
4769 ,U_p_real(val,1e5),U_p_real(lo,10),U_p_real(hi,MAX_REAL),3);
4770 SLV_RPARM_MACRO(RTMAXJ_PTR,parameters);
4771
4772 slv_define_parm(parameters, real_parm,
4773 "hessian_ub","RTMXJ2",
4774 "upper bound on 2nd derivatives in optimization step",
4775 U_p_real(val,1e4),U_p_real(lo,0),U_p_real(hi,MAX_REAL),3);
4776
4777 slv_define_parm(parameters, real_parm,
4778 "maxfeastol", "RTNWMA",
4779 "max residual considered feasible in optimization step",
4780 U_p_real(val, 1e-3),U_p_real(lo, 1e-13),U_p_real(hi,10e10),3);
4781
4782 slv_define_parm(parameters, real_parm,
4783 "minfeastol", "RTNWMI",
4784 "residuals below this considered feasible in optimization step",
4785 U_p_real(val, 4e-10),U_p_real(lo, 1e-20),U_p_real(hi,10e10),3);
4786
4787 slv_define_parm(parameters, real_parm,
4788 "oneDsearch","RTONED",
4789 "accuracy of one dimensional search in optimization step"
4790 ,U_p_real(val,0.2),U_p_real(lo,0.1),U_p_real(hi,0.7),3);
4791
4792 slv_define_parm(parameters, real_parm,
4793 "stepmult","RVSTLM",
4794 "steplength multiplier in optimization step",
4795 U_p_real(val,4),U_p_real(lo,0),U_p_real(hi,MAX_REAL),3);
4796
4797 slv_define_parm(parameters, real_parm,
4798 "pivottol","RTPIVA",
4799 "absolute pivot tolerance in optimization step",
4800 U_p_real(val,1e-7),U_p_real(lo,1e-15),U_p_real(hi,1),3);
4801
4802 slv_define_parm(parameters, real_parm,
4803 "pivtolrel","RTPIVR",
4804 "relative pivot tolerance in optimization step",
4805 U_p_real(val,0.05),U_p_real(lo,0),U_p_real(hi,1),3);
4806
4807 slv_define_parm(parameters, real_parm,
4808 "opttol","RTREDG",
4809 "optimality tolerance in optimization step",
4810 U_p_real(val,2e-5),U_p_real(lo,0),U_p_real(hi,MAX_REAL),3);
4811
4812 return 1;
4813 }
4814
4815 /*------------------------------------------------------------------------------
4816 EXTERNAL ROUTINES
4817 */
4818
4819 /**
4820 Create the tokens for the nonlinear solver and the logical solver.
4821 The token of the conditional solver will be assigned until the
4822 end slv9_create, which calls this function. Regarding the optimizer,
4823 we use CONOPT in two different ways. We are using only calls
4824 for solving optmization at aboundary, but we can also use a token
4825 created by slv8.c if the problem is itself an optimization problem.
4826 The vars and rels for the optimization problem at the boundary do
4827 not correspond to the vars of the slv, and therefore we have to
4828 create the data and calculate the gradients and residuals on the
4829 fly. In order to check for the existence of CONOPT, we look
4830 for the registration number of slv8.c. Here we are assuming that
4831 slv8 was registred only if CONOPT is available.
4832
4833 This function will return 0 if successful. If some of the solvers
4834 required by the nonlinear, logical or optimization steps are not
4835 available, the function will return 1, and the system will not be
4836 created.
4837 */
4838 static
4839 int32 get_solvers_tokens(slv9_system_t sys, slv_system_t server){
4840 int32 newsolver;
4841 int32 num_log_reg, num_nl_reg, num_opt_reg, num_cond_reg;
4842 int32 si;
4843 char *param;
4844 union param_value u;
4845
4846 const SlvFunctionsT *S;
4847 S = solver_engine_named(LOGSOLVER_OPTION);
4848 if(!S){
4849 FPRINTF(ASCERR,"Solver %s not available\n",LOGSOLVER_OPTION);
4850 return 1;
4851 }
4852 num_log_reg = S->number;
4853
4854 S = solver_engine_named(NONLISOLVER_OPTION);
4855 if(!S){
4856 FPRINTF(ASCERR,"Solver %s not available\n",NONLISOLVER_OPTION);
4857 return 1;
4858 }
4859 num_nl_reg = S->number;
4860
4861 S = solver_engine_named(OPTSOLVER_OPTION);
4862 if(!S){
4863 FPRINTF(ASCERR,"Solver %s not available\n",OPTSOLVER_OPTION);
4864 return 1;
4865 }
4866 CONSOLE_DEBUG("CONOPT found with name '%s'",S->name);
4867 CONSOLE_DEBUG("CONOPT found with number '%d'",S->number);
4868 num_opt_reg = S->number;
4869
4870 /* this is us! */
4871 S = solver_engine_named("CMSlv");
4872 if(!S){
4873 FPRINTF(ASCERR,"Solver CMSlv was not registered\n");
4874 return 1;
4875 }
4876 num_cond_reg = S->number;
4877
4878 /*
4879 Create solver tokens
4880 */
4881
4882 CONSOLE_DEBUG("SETTING UP SUB-SOLVERS");
4883
4884 CONSOLE_DEBUG("SETTING UP CMSLV");
4885 solver_index[CONDITIONAL_SOLVER] = num_cond_reg;
4886
4887 CONSOLE_DEBUG("SETTING UP LRSLV");
4888 newsolver = slv_switch_solver(server,num_log_reg);
4889 token[LOGICAL_SOLVER] = slv_get_client_token(server);
4890 solver_index[LOGICAL_SOLVER] = slv_get_selected_solver(server);
4891
4892 CONSOLE_DEBUG("SETTING UP QRSLV");
4893 newsolver = slv_switch_solver(server,num_nl_reg);
4894 token[NONLINEAR_SOLVER] = slv_get_client_token(server);
4895 solver_index[NONLINEAR_SOLVER] = slv_get_selected_solver(server);
4896
4897 CONSOLE_DEBUG("SETTING UP CONOPT (%d)",num_opt_reg);
4898 newsolver = slv_switch_solver(server,num_opt_reg);
4899 token[OPTIMIZATION_SOLVER] = slv_get_client_token(server);
4900 solver_index[OPTIMIZATION_SOLVER] = slv_get_selected_solver(server);
4901
4902 /*
4903 Disabling the partition mode flag in the non linear solver.
4904 PARTITION is a boolean parameter of the nonlinear solver
4905 QRSlv. This parameter tells the solver whether it should block
4906 partition or not.
4907 As long as we do not have a special subroutine to partition
4908 conditional models, this option should be disabled while using
4909 the conditional solver CMSlv
4910 */
4911 CONSOLE_DEBUG("setting QRSlv.partition");
4912 param = "partition";
4913 u.b = 0;
4914 set_param_in_solver(server,NONLINEAR_SOLVER,bool_parm,param,&u);
4915
4916
4917 /*
4918 Setting the value of the number of iterations in the optimizer.
4919 For us, the optimizer is a blackbox. The only way of asking the
4920 values of the variables at each iteration is to stop the optimizer
4921 at each iteration by assigning the number of iterations equal to 1.
4922 We have seen though that, because CONOPT work in four different
4923 phases, we need to assign a number of iterations a little bit bigger,
4924 so that CONOPT is able to determine optimality if we are
4925 already at the solution.
4926 */
4927 CONSOLE_DEBUG("setting CONOPT.iterationlimit");
4928 param = "iterationlimit";
4929 u.i = 20;
4930 set_param_in_solver(server,OPTIMIZATION_SOLVER,int_parm,param,&u);
4931
4932 /*
4933 Maximum number of subsequent iterations in nonlinear solver.
4934 We will give a big value to this parameter, since we really do
4935 not care about the limits in the number of iterations in the
4936 nonlinear solver; what we care about here is in the number
4937 of iterations controlled by CMSlv.
4938 */
4939 CONSOLE_DEBUG("setting QRSlv.iterationlimit");
4940 param = "iterationlimit";
4941 u.i = 150;
4942 set_param_in_solver(server,NONLINEAR_SOLVER,int_parm,param,&u);
4943
4944 return 0;
4945 }
4946
4947
4948 static
4949 SlvClientToken slv9_create(slv_system_t server, int *statusindex){
4950 slv9_system_t sys;
4951
4952 sys = (slv9_system_t)asccalloc(1, sizeof(struct slv9_system_structure) );
4953 if(sys==NULL) {
4954 *statusindex = 1;
4955 return sys;
4956 }
4957 SERVER = server;
4958 sys->p.parms = sys->pa;
4959 sys->p.dynamic_parms = 0;
4960 slv9_get_default_parameters(server,(SlvClientToken)sys,&(sys->p));
4961 sys->integrity = OK;
4962 sys->presolved = 0;
4963 sys->need_consistency_analysis = slv_need_consistency(server);
4964 sys->nliter = 0;
4965 sys->p.output.more_important = stdout;
4966 sys->p.output.less_important = stdout;
4967 sys->p.whose = (*statusindex);
4968 sys->s.ok = TRUE;
4969 sys->s.calc_ok = TRUE;
4970 sys->s.costsize = 0;
4971 sys->s.cost = NULL; /*redundant, but sanity preserving */
4972 sys->vlist = slv_get_solvers_var_list(server);
4973 sys->mvlist = slv_get_master_var_list(server); /* read only */
4974 sys->rlist = slv_get_solvers_rel_list(server);
4975 sys->dvlist = slv_get_solvers_dvar_list(server);
4976 sys->mdvlist = slv_get_master_dvar_list(server);
4977 sys->lrlist = slv_get_solvers_logrel_list(server);
4978 sys->blist = slv_get_solvers_bnd_list(server);
4979 sys->obj = slv_get_obj_relation(server);
4980 sys->rtot = slv_get_num_solvers_rels(server);
4981 sys->vtot = slv_get_num_solvers_vars(server);
4982 sys->mvtot = slv_get_num_master_vars(server);
4983 sys->coeff_matrix = NULL;
4984 sys->opt_var_values = NULL;
4985 if(sys->vlist == NULL) {
4986 ascfree(sys);
4987 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"CMSlv called with no variables.");
4988 *statusindex = -2;
4989 return NULL;
4990 }
4991 if(sys->rlist == NULL && sys->obj == NULL) {
4992 ascfree(sys);
4993 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"CMSlv called with no relations or objective.\n");
4994 *statusindex = -1;
4995 return NULL;
4996 }
4997 if(sys->dvlist == NULL) {
4998 ascfree(sys);
4999 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"CMSlv called with no discrete variables.\n");
5000 *statusindex = -2;
5001 return NULL;
5002 }
5003 if(sys->lrlist == NULL) {
5004 ascfree(sys);
5005 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"CMSlv called with no logrelations.\n");
5006 *statusindex = -1;
5007 return NULL;
5008 }
5009 if(sys->blist == NULL) {
5010 ascfree(sys);
5011 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"CMSlv called with no boundaries.\n");
5012 *statusindex = -2;
5013 return NULL;
5014 }
5015 slv_check_var_initialization(server);
5016 slv_check_dvar_initialization(server);
5017 slv_bnd_initialization(server);
5018
5019 if(get_solvers_tokens(sys,server)) {
5020 ascfree(sys);
5021 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"Solver(s) required by CMSlv were not registered. System cannot be created.");
5022 *statusindex = -1;
5023 return NULL;
5024 }
5025
5026 *statusindex = 0;
5027 token[CONDITIONAL_SOLVER] = (SlvClientToken)sys;
5028 return((SlvClientToken)sys);
5029 }
5030
5031
5032
5033 static
5034 int slv9_eligible_solver(slv_system_t server){
5035 const char *msg;
5036 if(!slv_get_num_solvers_rels(server)){
5037 msg = "No relations were found";
5038 }else if(!slv_get_num_solvers_logrels(server)){
5039 msg = "Model must contain at least one logical relation";
5040 }else if(!slv_get_num_solvers_bnds(server)){
5041 msg = "Model must contain at least one boundary";
5042 }else{
5043 return TRUE;
5044 }
5045
5046 ERROR_REPORTER_HERE(ASC_USER_ERROR
5047 ,"CMSlv not elegible for this model: %s",msg
5048 );
5049 return FALSE;
5050 }
5051
5052 static
5053 void slv9_get_parameters(slv_system_t server, SlvClientToken asys,
5054 slv_parameters_t *parameters
5055 ){
5056 slv9_system_t sys;
5057 (void) server;
5058 sys = SLV9(asys);
5059 if(check_system(sys)) return;
5060 mem_copy_cast(&(sys->p),parameters,sizeof(slv_parameters_t));
5061 }
5062
5063 static
5064 void slv9_set_parameters(slv_system_t server, SlvClientToken asys,
5065 slv_parameters_t *parameters
5066 ){
5067 slv9_system_t sys;
5068 (void) server;
5069 sys = SLV9(asys);
5070 if(check_system(sys)) return;
5071 mem_copy_cast(parameters,&(sys->p),sizeof(slv_parameters_t));
5072 }
5073
5074 static
5075 int slv9_get_status(slv_system_t server, SlvClientToken asys,
5076 slv_status_t *status
5077 ){
5078 slv9_system_t sys;
5079 (void) server;
5080 sys = SLV9(asys);
5081 if(check_system(sys)) return 1;
5082 mem_copy_cast(&(sys->s),status,sizeof(slv_status_t));
5083 return 0;
5084 }
5085
5086 static
5087 void slv9_dump_internals(slv_system_t server,
5088 SlvClientToken sys,int level
5089 ){
5090 check_system(sys);
5091 (void) server;
5092 if(level > 0) {
5093 FPRINTF(ASCERR,"ERROR: (slv9) slv9_dump_internals\n");
5094 FPRINTF(ASCERR," slv9 does not dump its internals.\n");
5095 }
5096 }
5097
5098
5099 /*
5100 * Set to zero the fields of the array cost
5101 */
5102 static
5103 void reset_cost(struct slv_block_cost *cost,int32 costsize){
5104 int32 ci;
5105
5106 for( ci = 0; ci < costsize; ++ci ) {
5107 cost[ci].size = 0;
5108 cost[ci].iterations = 0;
5109 cost[ci].funcs = 0;
5110 cost[ci].jacs = 0;
5111 cost[ci].functime = 0;
5112 cost[ci].jactime = 0;
5113 cost[ci].time = 0;
5114 cost[ci].resid = 0;
5115 }
5116 }
5117
5118 /*
5119 * Update the values for the array cost of the conditional solver
5120 * based on the value obtained from the nonlinear solver (square or
5121 * optimizer).
5122 * We definitely have to find a better way of communicating status
5123 * among solvers. I think the structure of the slv_status would have to be
5124 * modified accordingly to the need of each solver, however, the GUI is
5125 * completely dependent of the current structure, so I did not modify
5126 * that structure at all.
5127 */
5128 static
5129 void update_cost(struct slv_block_cost *cost, slv_status_t *status,
5130 int32 current_block, int32 previous_block
5131 ){
5132 int32 ci;
5133
5134 if(current_block >=0) {
5135 ci=current_block;
5136 cost[current_block].size = status->block.current_size;
5137 cost[current_block].iterations = status->block.iteration;
5138 cost[current_block].funcs = status->block.funcs;
5139 cost[current_block].jacs = status->block.jacs;
5140 cost[current_block].functime = status->block.functime;
5141 cost[current_block].jactime = status->block.jactime;
5142 cost[current_block].time = status->block.cpu_elapsed;
5143 cost[current_block].resid = status->block.residual;
5144 if(previous_block != -1 && previous_block != current_block) {
5145 cost[previous_block].size = status->cost[previous_block].size;
5146 cost[previous_block].iterations=status->cost[previous_block].iterations;
5147 cost[previous_block].funcs = status->cost[previous_block].funcs;
5148 cost[previous_block].jacs = status->cost[previous_block].jacs;
5149 cost[previous_block].functime = status->cost[previous_block].functime;
5150 cost[previous_block].jactime = status->cost[previous_block].jactime;
5151 cost[previous_block].time = status->cost[previous_block].time;
5152 cost[previous_block].resid = status->cost[previous_block].resid;
5153 }
5154 }
5155 }
5156
5157 static
5158 int32 is_an_optimization_problem(slv_system_t server,
5159 SlvClientToken asys
5160 ){
5161 slv9_system_t sys;
5162 slv_status_t status;
5163 mtx_matrix_t Jacobian;
5164 dof_t *dofdata;
5165 var_filter_t vfilter;
5166 int32 optimizing;
5167
5168 sys = SLV9(asys);
5169
5170 /* count free and incident vars */
5171 vfilter.matchbits = (VAR_FIXED | VAR_INCIDENT | VAR_SVAR | VAR_ACTIVE);
5172 vfilter.matchvalue = (VAR_INCIDENT | VAR_SVAR | VAR_ACTIVE);
5173 sys->vused = slv_count_solvers_vars(server,&vfilter);
5174
5175 slv_set_client_token(server,token[NONLINEAR_SOLVER]);
5176 slv_set_solver_index(server,solver_index[NONLINEAR_SOLVER]);
5177 slv_presolve(server);
5178
5179 Jacobian = slv_get_sys_mtx(server);
5180 dofdata = slv_get_dofdata(server);
5181 sys->rank = dofdata->structural_rank;
5182
5183 /* Initialize Status */
5184 slv_get_status(server,&status);
5185 optimizing = sys->obj ? (sys->vused - sys->rank) : 0;
5186 update_struct_info(sys,&status);
5187 slv_set_client_token(server,token[CONDITIONAL_SOLVER]);
5188 slv_set_solver_index(server,solver_index[CONDITIONAL_SOLVER]);
5189 return optimizing;
5190 }
5191
5192 static
5193 int slv9_presolve(slv_system_t server, SlvClientToken asys){
5194 slv9_system_t sys;
5195 struct var_variable **vp;
5196 struct rel_relation **rp;
5197 int32 cap, ind;
5198
5199 CONSOLE_DEBUG("...");
5200
5201 sys = SLV9(asys);
5202 iteration_begins(sys);
5203 check_system(sys);
5204 if(sys->vlist == NULL ) {
5205 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Variable list was never set.");
5206 return 1;
5207 }
5208 if(sys->rlist == NULL && sys->obj == NULL ) {
5209 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Relation list and objective never set.");
5210 return 2;
5211 }
5212
5213 cap = slv_get_num_solvers_rels(server);
5214 sys->cap = slv_get_num_solvers_vars(server);
5215 sys->cap = MAX(sys->cap,cap);
5216
5217 vp=sys->vlist;
5218 for( ind = 0; ind < sys->vtot; ++ind ) {
5219 var_set_in_block(vp[ind],FALSE);
5220 }
5221
5222 rp=sys->rlist;
5223 for( ind = 0; ind < sys->rtot; ++ind ) {
5224 rel_set_in_block(rp[ind],FALSE);
5225 rel_set_satisfied(rp[ind],FALSE);
5226 }
5227
5228 /*
5229 * Information about subregions
5230 *
5231 */
5232 sys->subregion_list.length = 0 ;
5233 sys->subregion_list.capacity = 0;
5234 sys->subregion_list.sub_stack = NULL;
5235
5236 sys->subregions_visited.length = 0 ;
5237 sys->subregions_visited.capacity = 0;
5238 sys->subregions_visited.visited = NULL;
5239
5240 sys->presolved = 1;
5241
5242 /*
5243 * Assume initially that all the variables are basic
5244 */
5245 set_nonbasic_status_in_var_list(server,FALSE);
5246
5247 /*
5248 * Sets value of global variable
5249 */
5250 g_optimizing = is_an_optimization_problem(server,asys);
5251
5252 sys->s.block.current_reordered_block = -2;
5253 /* Reset status */
5254 sys->s.iteration = 0;
5255 sys->nliter = 0;
5256 sys->s.cpu_elapsed = 0.0;
5257 sys->s.converged = sys->s.diverged = sys->s.inconsistent = FALSE;
5258 sys->s.block.previous_total_size = 0;
5259 sys->s.block.current_block = -1;
5260 sys->s.block.current_size = 0;
5261 sys->s.calc_ok = TRUE;
5262 sys->s.block.iteration = 0;
5263
5264 update_status(sys);
5265 iteration_ends(sys);
5266
5267 return 0;
5268 }
5269
5270 static
5271 int slv9_resolve(slv_system_t server, SlvClientToken asys){
5272 struct var_variable **vp;
5273 struct rel_relation **rp;
5274 slv9_system_t sys;
5275
5276 sys = SLV9(asys);
5277 (void) server;
5278 check_system(sys);
5279
5280 for( vp = sys->vlist ; *vp != NULL ; ++vp ) {
5281 var_set_in_block(*vp,FALSE);
5282 }
5283 for( rp = sys->rlist ; *rp != NULL ; ++rp ) {
5284 rel_set_in_block(*rp,FALSE);
5285 rel_set_satisfied(*rp,FALSE);
5286 }
5287
5288 /* Reset status */
5289 sys->nliter = 0;
5290 sys->s.iteration = 0;
5291 sys->s.cpu_elapsed = 0.0;
5292 sys->s.converged = sys->s.diverged = sys->s.inconsistent = FALSE;
5293 sys->s.block.previous_total_size = 0;
5294
5295 /* go to first unconverged block */
5296 sys->s.block.current_block = -1;
5297 sys->s.block.current_size = 0;
5298 sys->s.calc_ok = TRUE;
5299 sys->s.block.iteration = 0;
5300
5301 update_status(sys);
5302
5303 return 0;
5304 }
5305
5306 static
5307 int slv9_iterate(slv_system_t server, SlvClientToken asys){
5308 slv9_system_t sys;
5309 slv_status_t status;
5310 struct matching_cases *subregions;
5311 struct real_values rvalues;
5312 var_filter_t vfilter;
5313 struct gl_list_t *disvars;
5314 real64 factor;
5315 int32 n_subregions, cur_subregion;
5316 int32 previous_block;
5317 boolean unsuccessful;
5318 int32 system_was_reanalyzed;
5319 #if TEST_CONSISTENCY
5320 int32 *test= NULL;
5321 #endif /* TEST_CONSISTENCY */
5322 FILE *mif;
5323 FILE *lif;
5324
5325 sys = SLV9(asys);
5326 mif = MIF(sys);
5327 lif = LIF(sys);
5328
5329 if(server == NULL || sys==NULL) return 1;
5330 if(check_system(SLV9(sys))) return 2;
5331 if(!sys->s.ready_to_solve ) {
5332 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Not ready to solve.");
5333 return 3;
5334 }
5335
5336 unsuccessful = FALSE;
5337 iteration_begins(sys);
5338 system_was_reanalyzed = 0;
5339 disvars = gl_create(1L);
5340 /*
5341 * If the current point is at a boundary, perform optimization step
5342 * at boundary. If the problem is an optimization problem, then it is
5343 * required to analyze the system first, in order to investigate which
5344 * variables are dependent and which are independent. That information
5345 * is not available before iterating with the optimizer, so, an iteration
5346 * with the oprimizer is required before the analysis at the boundary.
5347 */
5348 if((!g_optimizing || (sys->nliter > 0))
5349 && at_a_boundary(
5350 server
5351 ,asys,&(n_subregions),&(subregions),&(cur_subregion), disvars
5352 )
5353 ){
5354 slv_set_client_token(server,token[CONDITIONAL_SOLVER]);
5355 slv_set_solver_index(server,solver_index[CONDITIONAL_SOLVER]);
5356 store_real_pre_values(server,&(rvalues));
5357 ERROR_REPORTER_HERE(ASC_PROG_NOTE,"Solving Optimization Problem at boundary...\n");
5358 if(optimize_at_boundary(server,asys,&(n_subregions),
5359 subregions,&(cur_subregion),disvars,&(rvalues))){
5360 store_real_cur_values(server,&(rvalues));
5361 update_boundaries(server,asys);
5362 if(some_boundaries_crossed(server,asys)) {
5363 vfilter.matchbits = (VAR_ACTIVE_AT_BND | VAR_INCIDENT
5364 | VAR_SVAR | VAR_FIXED);
5365 vfilter.matchvalue = (VAR_ACTIVE_AT_BND | VAR_INCIDENT | VAR_SVAR);
5366 ERROR_REPORTER_HERE(ASC_PROG_NOTE,"Boundary(ies) crossed. Returning to boundary first crossed...\n");
5367 factor = return_to_first_boundary(server,asys,&rvalues,&vfilter);
5368 update_real_var_values(server,&rvalues,&vfilter,factor);
5369 update_boundaries(server,asys);
5370 update_relations_residuals(server);
5371 }else{
5372 destroy_array(rvalues.cur_values);
5373 destroy_array(rvalues.pre_values);
5374 }
5375 update_status(sys);
5376 }else{
5377 destroy_array(rvalues.pre_values);
5378 sys->s.converged = TRUE;
5379 sys->s.ready_to_solve = FALSE;
5380 ERROR_REPORTER_HERE(ASC_PROG_WARNING,"No progress can be achieved: solution at current boundary.");
5381 slv_set_client_token(server,token[CONDITIONAL_SOLVER]);
5382 slv_set_solver_index(server,solver_index[CONDITIONAL_SOLVER]);
5383 }
5384 gl_destroy(disvars);
5385 disvars = NULL;
5386 iteration_ends(sys);
5387 return 0; /* is there an error here? */
5388 }else{
5389 /* solve logical relations */
5390 solve_logical_relations(server);
5391 slv_get_status(server,&status);
5392 sys->s.converged = status.converged;
5393 if(!sys->s.converged ) {
5394 unsuccessful = update_unsuccessful(sys,&status);
5395 if(unsuccessful) {
5396 sys->s.ready_to_solve = !unsuccessful;
5397 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Non-convergence in logical solver.");
5398 slv_set_client_token(server,token[CONDITIONAL_SOLVER]);
5399 slv_set_solver_index(server,solver_index[CONDITIONAL_SOLVER]);
5400 gl_destroy(disvars);
5401 disvars = NULL;
5402 iteration_ends(sys);
5403 return 4;
5404 }
5405 }
5406 /*
5407 * reconfigure the system if necessary
5408 */
5409 if(some_dis_vars_changed(server,asys) ) {
5410 reanalyze_solver_lists(server);
5411 update_relations_residuals(server);
5412 system_was_reanalyzed = 1;
5413 }
5414
5415 /*
5416 * Nonlinear solution technique
5417 */
5418 if(g_optimizing) {
5419 /*
5420 * SetUp Optimizer
5421 */
5422 slv_set_client_token(server,token[OPTIMIZATION_SOLVER]);
5423 slv_set_solver_index(server,solver_index[OPTIMIZATION_SOLVER]);
5424 store_real_pre_values(server,&(rvalues));
5425 set_nonbasic_status_in_var_list(server,FALSE);
5426 (sys->nliter)++;
5427 if(sys->nliter == 1 || system_was_reanalyzed ==1) {
5428 ERROR_REPORTER_HERE(ASC_PROG_NOTE,"Iterating with Optimizer...");
5429 slv_presolve(server);
5430 slv_get_status(server,&status);
5431 update_real_status(&(sys->s),&status,0);
5432 if(sys->s.cost) {
5433 destroy_array(sys->s.cost);
5434 }
5435 sys->s.cost =
5436 create_zero_array(sys->s.costsize,struct slv_block_cost);
5437 reset_cost(sys->s.cost,sys->s.costsize);
5438 }else{
5439 slv_get_status(server,&status);
5440 update_struct_info(sys,&status);
5441 if(status.converged) {
5442 slv_presolve(server);
5443 update_real_status(&(sys->s),&status,0);
5444 if(sys->s.cost) {
5445 destroy_array(sys->s.cost);
5446 }
5447 sys->s.cost =
5448 create_zero_array(sys->s.costsize,struct slv_block_cost);
5449 reset_cost(sys->s.cost,sys->s.costsize);
5450 }else{
5451 if(!status.ready_to_solve) {
5452 slv_resolve(server);
5453 }
5454 }
5455 }
5456 }else{
5457 /*
5458 * SetUp nonlinear solver
5459 */
5460 slv_set_client_token(server,token[NONLINEAR_SOLVER]);
5461 slv_set_solver_index(server,solver_index[NONLINEAR_SOLVER]);
5462 store_real_pre_values(server,&(rvalues));
5463 (sys->nliter)++;
5464 if(sys->nliter == 1 || system_was_reanalyzed ==1) {
5465 ERROR_REPORTER_HERE(ASC_PROG_NOTE,"Iterating with Non Linear solver...\n");
5466 slv_presolve(server);
5467 slv_get_status(server,&status);
5468 update_struct_info(sys,&status);
5469 update_real_status(&(sys->s),&status,sys->nliter);
5470 if(sys->s.cost) {
5471 destroy_array(sys->s.cost);
5472 }
5473 sys->s.cost =
5474 create_zero_array(sys->s.costsize,struct slv_block_cost);
5475 reset_cost(sys->s.cost,sys->s.costsize);
5476 #if TEST_CONSISTENCY
5477 ID_and_storage_subregion_information(server,asys);
5478 CONSOLE_DEBUG("New region, Iteration = %d\n",sys->s.block.iteration);
5479 #endif /* TEST_CONSISTENCY */
5480 }
5481 slv_get_status(server,&status);
5482 update_struct_info(sys,&status);
5483 if(status.converged) {
5484 slv_presolve(server);
5485 update_real_status(&(sys->s),&status,0);
5486 if(sys->s.cost) {
5487 destroy_array(sys->s.cost);
5488 }
5489 sys->s.cost =
5490 create_zero_array(sys->s.costsize,struct slv_block_cost);
5491 reset_cost(sys->s.cost,sys->s.costsize);
5492 }
5493 }
5494 /*
5495 Iteration steps common to optimizer and nonlinear solver
5496 */
5497 previous_block = sys->s.block.current_block;
5498 slv_iterate(server);
5499 store_real_cur_values(server,&(rvalues));
5500 update_boundaries(server,asys);
5501 slv_get_status(server,&status);
5502 sys->s.converged = status.converged;
5503 /*
5504 The following statement was added 4/2
5505 */
5506 update_struct_info(sys,&status);
5507 update_real_status(&(sys->s),&status,0);
5508 update_cost(sys->s.cost,&status,
5509 sys->s.block.current_block,previous_block);
5510 if(!sys->s.converged || some_boundaries_crossed(server,asys) ) {
5511 sys->s.converged = FALSE;
5512 sys->s.ready_to_solve = !sys->s.converged;
5513 if(some_boundaries_crossed(server,asys)) {
5514 vfilter.matchbits = (VAR_ACTIVE | VAR_INCIDENT
5515 | VAR_SVAR | VAR_FIXED);
5516 vfilter.matchvalue = (VAR_ACTIVE | VAR_INCIDENT | VAR_SVAR);
5517 ERROR_REPORTER_HERE(ASC_PROG_NOTE,"Boundary(ies) crossed. Returning to boundary first crossed...\n");
5518 factor = return_to_first_boundary(server,asys,&rvalues,&vfilter);
5519 update_real_var_values(server,&rvalues,&vfilter,factor);
5520 update_boundaries(server,asys);
5521 update_relations_residuals(server);
5522 }else{
5523 destroy_array(rvalues.cur_values);
5524 destroy_array(rvalues.pre_values);
5525 }
5526 unsuccessful = update_unsuccessful(sys,&status);
5527 if(unsuccessful) {
5528
5529 #if TEST_CONSISTENCY
5530 if(sys->s.iteration_limit_exceeded) {
5531 eligible_set_for_subregions(server,asys,&test);
5532 consistency_analysis_for_subregions(server,asys,&test);
5533 if(test != NULL) {
5534 ascfree(test);
5535 }
5536 }
5537 #endif /* TEST_CONSISTENCY */
5538
5539 sys->s.ready_to_solve = !unsuccessful;
5540 ERROR_REPORTER_HERE(ASC_PROG_WARNING,"Non-convergence in nonlinear step.");
5541 }
5542 }else{
5543 sys->s.ready_to_solve = !sys->s.converged;
5544 /*
5545 The following was added 4/2
5546 */
5547 unsuccessful = update_unsuccessful(sys,&status);
5548
5549 #if TEST_CONSISTENCY
5550 if(sys->s.iteration_limit_exceeded) {
5551 consistency_analysis_for_subregions(server,asys,&test);
5552 if(test != NULL) {
5553 ascfree(test);
5554 }
5555 }
5556 #endif /* TEST_CONSISTENCY */
5557
5558 if(unsuccessful){
5559 sys->s.ready_to_solve = !unsuccessful;
5560 ERROR_REPORTER_HERE(ASC_PROG_WARNING,"Non-convergence in nonlinear step.");
5561 }
5562 destroy_array(rvalues.cur_values);
5563 destroy_array(rvalues.pre_values);
5564 }
5565 }
5566 slv_set_client_token(server,token[CONDITIONAL_SOLVER]);
5567 slv_set_solver_index(server,solver_index[CONDITIONAL_SOLVER]);
5568 gl_destroy(disvars);
5569 disvars = NULL;
5570 iteration_ends(sys);
5571 return 0;
5572 }
5573
5574
5575 static int slv9_solve(slv_system_t server, SlvClientToken asys){
5576 slv9_system_t sys;
5577 int err = 0;
5578
5579 sys = SLV9(asys);
5580 if(server == NULL || sys==NULL)return 1;
5581 if(check_system(sys))return 2;
5582
5583 while(sys->s.ready_to_solve)err = err | slv9_iterate(server,sys);
5584
5585 return err;
5586 }
5587
5588
5589 static
5590 mtx_matrix_t slv9_get_matrix(slv_system_t server, SlvClientToken sys){
5591 if(server == NULL || sys==NULL) return NULL;
5592 if(check_system(SLV9(sys))) return NULL;
5593 ERROR_REPORTER_HERE(ASC_PROG_ERR,"slv9 does not get matrix.");
5594 return( NULL );
5595 }
5596
5597 /*
5598 * Destroy the client tokens of the different solvers
5599 */
5600 static
5601 void destroy_solvers_tokens(slv_system_t server){
5602 slv_set_client_token(server,token[LOGICAL_SOLVER]);
5603 slv_set_solver_index(server,solver_index[LOGICAL_SOLVER]);
5604 slv_destroy_client(server);
5605 slv_set_client_token(server,token[NONLINEAR_SOLVER]);
5606 slv_set_solver_index(server,solver_index[NONLINEAR_SOLVER]);
5607 slv_destroy_client(server);
5608 slv_set_client_token(server,token[OPTIMIZATION_SOLVER]);
5609 slv_set_solver_index(server,solver_index[OPTIMIZATION_SOLVER]);
5610 slv_destroy_client(server);
5611 slv_set_client_token(server,token[CONDITIONAL_SOLVER]);
5612 slv_set_solver_index(server,solver_index[CONDITIONAL_SOLVER]);
5613 }
5614
5615 static
5616 int slv9_destroy(slv_system_t server, SlvClientToken asys){
5617 slv9_system_t sys;
5618 sys = SLV9(asys);
5619 if(check_system(sys)) return 1;
5620 destroy_subregion_information(asys);
5621 destroy_solvers_tokens(server);
5622 slv_destroy_parms(&(sys->p));
5623 sys->integrity = DESTROYED;
5624 if(sys->s.cost) ascfree(sys->s.cost);
5625 ascfree( (POINTER)asys );
5626 return 0;
5627 }
5628
5629
5630 static const SlvFunctionsT slv9_internals = {
5631 SOLVER_CMSLV
5632 ,"CMSlv"
5633 ,slv9_create
5634 ,slv9_destroy
5635 ,slv9_eligible_solver
5636 ,slv9_get_default_parameters
5637 ,slv9_get_parameters
5638 ,slv9_set_parameters
5639 ,slv9_get_status
5640 ,slv9_solve
5641 ,slv9_presolve
5642 ,slv9_iterate
5643 ,slv9_resolve
5644 ,NULL
5645 ,slv9_get_matrix
5646 ,slv9_dump_internals
5647 };
5648
5649 int cmslv_register(void){
5650 if(!solver_engine_named("CONOPT")){
5651 ERROR_REPORTER_HERE(ASC_PROG_ERR,"CONOPT must be registered before CMSlv");
5652 return 1;
5653 }
5654 if(!solver_engine_named("LRSlv")){
5655 ERROR_REPORTER_HERE(ASC_PROG_ERR,"LRSlv must be registered before CMSlv");
5656 return 1;
5657 }
5658 if(!solver_engine_named("QRSlv")){
5659 ERROR_REPORTER_HERE(ASC_PROG_ERR,"QRSlv must be registered before CMSlv");
5660 return 1;
5661 }
5662 return solver_register(&slv9_internals);
5663 }
5664

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22