Parent Directory | Revision Log
In slv9, made changes to keep CONOPT from complaining. CMSlv still not working as expected though. Decreased required version of Bison to 2.0. Switched search path for CONOPT on Linux to the CONOPT_PATH env var (LD_LIBRARY_PATH was being interfered with when ASC_DEV=1). Some other debug message changes.
1 | /* ASCEND modelling environment |
2 | Copyright (C) 2006 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 |
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 <compiler/compiler.h> |
36 | #include <compiler/instance_enum.h> |
37 | #include <general/list.h> |
38 | #include <compiler/fractions.h> |
39 | #include <compiler/dimen.h> |
40 | #include <compiler/functype.h> |
41 | #include <compiler/func.h> |
42 | #include "mtx.h" |
43 | #include "mtx_reorder.h" |
44 | #include "linsol.h" |
45 | #include "linsolqr.h" |
46 | #include "slv_types.h" |
47 | #include "var.h" |
48 | #include "rel.h" |
49 | #include "discrete.h" |
50 | #include "conditional.h" |
51 | #include "logrel.h" |
52 | #include "bnd.h" |
53 | #include "calc.h" |
54 | #include "relman.h" |
55 | #include "logrelman.h" |
56 | #include "bndman.h" |
57 | #include "cond_config.h" |
58 | #include "slv_common.h" |
59 | #include "slv_client.h" |
60 | #include "slv9.h" |
61 | #include "slv_stdcalls.h" |
62 | #include "slvDOF.h" |
63 | |
64 | #ifdef ASC_WITH_CONOPT |
65 | # include <solver/conopt.h> |
66 | #else |
67 | # define MAX_INT MAXINT |
68 | # define MAX_REAL MAXDOUBLE |
69 | #endif |
70 | |
71 | #if !defined(STATIC_CMSLV) && !defined(DYNAMIC_CMSLV) |
72 | int slv9_register(SlvFunctionsT *f) |
73 | { |
74 | UNUSED_PARAMETER(f); |
75 | |
76 | ERROR_REPORTER_HERE(ASC_PROG_ERR,"CMSlv was not built in this copy of ASCEND"); |
77 | return 1; |
78 | } |
79 | #else /* either STATIC_CMSLV or DYNAMIC_CMSLV is defined */ |
80 | |
81 | #ifdef DYNAMIC_CMSLV |
82 | /* do dynamic loading stuff. yeah, right */ |
83 | |
84 | #else /* following is used if STATIC_CMSLV is defined */ |
85 | |
86 | |
87 | /* |
88 | * definitions to enable/disable the output of partial results in |
89 | * the solution of a problem |
90 | */ |
91 | #define DEBUG FALSE |
92 | #define SHOW_LOGICAL_DETAILS FALSE |
93 | #define SHOW_BOUNDARY_ANALYSIS_DETAILS FALSE |
94 | #define SHOW_OPTIMIZATION_DETAILS FALSE |
95 | #define SHOW_BISECTION_DETAILS FALSE |
96 | #define SHOW_LINEAR_SEARCH_DETAILS FALSE |
97 | #define SHOW_LAGRANGE_DETAILS FALSE |
98 | #define DEBUG_CONSISTENCY FALSE |
99 | #define TEST_CONSISTENCY FALSE |
100 | #define USE_CONSISTENCY FALSE |
101 | |
102 | /* |
103 | * system definitions |
104 | */ |
105 | #define SLV9(s) ((slv9_system_t)(s)) |
106 | #define SERVER (sys->slv) |
107 | #define slv9_PA_SIZE 26 /* MUST INCREMENT WHEN ADDING PARAMETERS */ |
108 | #define LOGSOLVER_OPTION_PTR (sys->parm_array[0]) |
109 | #define LOGSOLVER_OPTION ((*(char **)LOGSOLVER_OPTION_PTR)) |
110 | #define NONLISOLVER_OPTION_PTR (sys->parm_array[1]) |
111 | #define NONLISOLVER_OPTION ((*(char **)NONLISOLVER_OPTION_PTR)) |
112 | #define OPTSOLVER_OPTION_PTR (sys->parm_array[2]) |
113 | #define OPTSOLVER_OPTION ((*(char **)OPTSOLVER_OPTION_PTR)) |
114 | #define TIME_LIMIT_PTR (sys->parm_array[3]) |
115 | #define TIME_LIMIT ((*(int32 *)TIME_LIMIT_PTR)) |
116 | #define ITER_LIMIT_PTR (sys->parm_array[4]) |
117 | #define ITER_LIMIT ((*(int32 *)ITER_LIMIT_PTR)) |
118 | #define ITER_BIS_LIMIT_PTR (sys->parm_array[5]) |
119 | #define ITER_BIS_LIMIT ((*(int32 *)ITER_BIS_LIMIT_PTR)) |
120 | #define TOO_SMALL_PTR (sys->parm_array[6]) |
121 | #define TOO_SMALL ((*(real64 *)TOO_SMALL_PTR)) |
122 | #define LINEAR_SEARCH_FACTOR_PTR (sys->parm_array[7]) |
123 | #define LINEAR_SEARCH_FACTOR ((*(real64 *)LINEAR_SEARCH_FACTOR_PTR)) |
124 | #define SHOW_MORE_IMPT_PTR (sys->parm_array[8]) |
125 | #define SHOW_MORE_IMPT ((*(int32 *)SHOW_MORE_IMPT_PTR)) |
126 | #define SHOW_LESS_IMPT_PTR (sys->parm_array[9]) |
127 | #define SHOW_LESS_IMPT ((*(int32 *)SHOW_LESS_IMPT_PTR)) |
128 | #define AUTO_RESOLVE_PTR (sys->parm_array[10]) |
129 | #define AUTO_RESOLVE ((*(int32 *)AUTO_RESOLVE_PTR)) |
130 | #define UNDEFINED_PTR (sys->parm_array[11]) |
131 | #define UNDEFINED ((*(real64 *)UNDEFINED_PTR)) |
132 | #define DOMLIM_PTR (sys->parm_array[12]) |
133 | #define DOMLIM ((*(int32 *)DOMLIM_PTR)) |
134 | #define OPT_ITER_LIMIT_PTR (sys->parm_array[13]) |
135 | #define OPT_ITER_LIMIT ((*(int32 *)OPT_ITER_LIMIT_PTR)) |
136 | #define INFINITY_PTR (sys->parm_array[14]) |
137 | #define ASC_INFINITY ((*(real64 *)INFINITY_PTR)) |
138 | #define OBJ_TOL_PTR (sys->parm_array[15]) |
139 | #define OBJ_TOL ((*(real64 *)OBJ_TOL_PTR)) |
140 | #define RTMAXJ_PTR (sys->parm_array[16]) |
141 | #define RTMAXJ ((*(real64 *)RTMAXJ_PTR)) |
142 | #define RHO_PTR (sys->parm_array[17]) |
143 | #define RHO ((*(real64 *)RHO_PTR)) |
144 | |
145 | |
146 | /* |
147 | * Client tokens of the different solvers: Conditional, Optimizer, |
148 | * Nonlinear, Logical. We will switch from one client token to |
149 | * another as the solution process occurs. |
150 | */ |
151 | #define NUMBER_OF_CLIENTS 4 |
152 | SlvClientToken token[NUMBER_OF_CLIENTS]; |
153 | int32 solver_index[NUMBER_OF_CLIENTS]; |
154 | |
155 | /* |
156 | * indeces in arrays token and solver_index |
157 | */ |
158 | #define CONDITIONAL_SOLVER 0 |
159 | #define LOGICAL_SOLVER 1 |
160 | #define NONLINEAR_SOLVER 2 |
161 | #define OPTIMIZATION_SOLVER 3 |
162 | |
163 | /* |
164 | * Do we have an optimization problem ?. Global variable initialized |
165 | * to 0 (not optimizing) |
166 | */ |
167 | static int32 g_optimizing = 0; |
168 | |
169 | #if USE_CONSISTENCY |
170 | /* |
171 | * number of subregion visited during the solution of the conditional |
172 | * model. |
173 | */ |
174 | static int32 g_subregions_visited; |
175 | |
176 | #endif /* USE_CONSISTENCY */ |
177 | |
178 | |
179 | /* auxiliar structures */ |
180 | struct boolean_values { |
181 | int32 *pre_val; /* previous values of dis_discrete */ |
182 | int32 *cur_val; /* current values of dis_discrete */ |
183 | }; |
184 | |
185 | struct matching_cases { |
186 | int32 *case_list; /* list of cases */ |
187 | int32 ncases; /* number of cases */ |
188 | int32 diff_subregion; /* subregion ? */ |
189 | }; |
190 | |
191 | struct real_values { |
192 | real64 *pre_values; /* previous values of var_variables */ |
193 | real64 *cur_values; /* current values of var_variables */ |
194 | }; |
195 | |
196 | struct opt_vector { |
197 | real64 *element; /* elements in colum of matrix */ |
198 | }; |
199 | |
200 | struct opt_matrix { |
201 | struct opt_vector *cols; /* columns in matrix */ |
202 | }; |
203 | |
204 | struct subregionID { |
205 | unsigned long ID_number; |
206 | int32 *bool_values; |
207 | }; |
208 | |
209 | struct ds_subregion_list { |
210 | int32 length,capacity; |
211 | struct subregionID *sub_stack; |
212 | }; |
213 | |
214 | struct ds_subregions_visited { |
215 | int32 length,capacity; |
216 | unsigned long *visited; |
217 | }; |
218 | |
219 | /* |
220 | * This solver's data structure (CMSlv) |
221 | */ |
222 | struct slv9_system_structure { |
223 | |
224 | /* |
225 | * Problem definition |
226 | */ |
227 | slv_system_t slv; /* slv_system_t back-link */ |
228 | |
229 | struct rel_relation *obj; /* Objective function: NULL = none */ |
230 | struct var_variable **vlist; /* Variable list (NULL terminated) */ |
231 | struct rel_relation **rlist; /* Relation list (NULL terminated) */ |
232 | struct dis_discrete **dvlist; /* Dis vars list (NULL terminated) */ |
233 | struct logrel_relation **lrlist; /* Logrels list(NULL terminated)*/ |
234 | struct bnd_boundary **blist; /* Variable list (NULL terminated) */ |
235 | struct var_variable **mvlist; |
236 | struct dis_discrete **mdvlist; /* We will not touch the masters list, |
237 | * but they can provide very useful |
238 | * information to the conditional |
239 | * solver since the master index does |
240 | * not change. |
241 | */ |
242 | |
243 | /* |
244 | * for optimization at boundaries |
245 | */ |
246 | struct opt_matrix *coeff_matrix; /* Matrix for optimization problem */ |
247 | struct opt_vector *opt_var_values; /* Values of vars in opt problem */ |
248 | int32 subregions; /* number of subregions at cur bnd */ |
249 | mtx_matrix_t lin_mtx; /* Matrix to define the linear system |
250 | * for calculation of the lagrange |
251 | * multipliers |
252 | */ |
253 | /* |
254 | * For search consistency analysis |
255 | */ |
256 | struct ds_subregion_list subregion_list; |
257 | /* |
258 | * Information about the subregions |
259 | * visited during the solution of the |
260 | * conditional model |
261 | */ |
262 | struct ds_subregions_visited subregions_visited; |
263 | /* |
264 | * ID number of the subregions |
265 | * visited |
266 | */ |
267 | int32 *bool_mindex; /* master indices of boolean vars in |
268 | * the problem associated with WHENs |
269 | */ |
270 | int32 need_consistency_analysis; /* Is the consistency analysis needed */ |
271 | |
272 | |
273 | /* |
274 | * Solver information |
275 | */ |
276 | int32 integrity; /* Has the system been created ? */ |
277 | int32 presolved; /* Has the system been presolved ? */ |
278 | slv_parameters_t p; /* Parameters */ |
279 | slv_status_t s; /* Status (as of iteration end) */ |
280 | int32 cap; /* Order of matrix/vectors */ |
281 | int32 rank; /* Symbolic rank of problem */ |
282 | int32 vused; /* Free and incident variables */ |
283 | int32 vtot; /* length of varlist */ |
284 | int32 mvtot; /* length of master varlist */ |
285 | int32 rused; /* Included relations */ |
286 | int32 rtot; /* length of rellist */ |
287 | real64 clock; /* CPU time */ |
288 | int32 nliter; /* iterations in nonlinear solver */ |
289 | |
290 | void *parm_array[slv9_PA_SIZE]; /* array of pointers to param values */ |
291 | struct slv_parameter pa[slv9_PA_SIZE]; /* &pa[0] => sys->p.parms */ |
292 | |
293 | #ifdef ASC_WITH_CONOPT |
294 | /* |
295 | * Data for optimizer at boundaries (CONOPT) |
296 | */ |
297 | struct conopt_data con; |
298 | #endif |
299 | }; |
300 | |
301 | |
302 | /* |
303 | * Integrity checks |
304 | * ---------------- |
305 | * check_system(sys) |
306 | */ |
307 | |
308 | #define OK ((int32)813029392) |
309 | #define DESTROYED ((int32)103289182) |
310 | |
311 | /* |
312 | * Checks sys for NULL and for integrity. |
313 | */ |
314 | static int check_system(slv9_system_t sys) |
315 | { |
316 | if( sys == NULL ) { |
317 | FPRINTF(ASCERR,"ERROR: (slv9) check_system\n"); |
318 | FPRINTF(ASCERR," NULL system handle.\n"); |
319 | return 1; |
320 | } |
321 | |
322 | switch( sys->integrity ) { |
323 | case OK: |
324 | return 0; |
325 | case DESTROYED: |
326 | FPRINTF(ASCERR,"ERROR: (slv9) check_system\n"); |
327 | FPRINTF(ASCERR," System was recently destroyed.\n"); |
328 | return 1; |
329 | default: |
330 | FPRINTF(ASCERR,"ERROR: (slv9) check_system\n"); |
331 | FPRINTF(ASCERR," System reused or never allocated.\n"); |
332 | return 1; |
333 | } |
334 | } |
335 | |
336 | |
337 | /* |
338 | * General input/output routines |
339 | * ----------------------------- |
340 | * print_var_name(out,sys,var) |
341 | */ |
342 | #define print_var_name(a,b,c) slv_print_var_name((a),(b)->slv,(c)) |
343 | |
344 | |
345 | /* |
346 | * Array operations |
347 | * ---------------- |
348 | * destroy_array(p) |
349 | * create_array(len,type) |
350 | * create_zero_array(len,type) |
351 | */ |
352 | #define destroy_array(p) \ |
353 | if( (p) != NULL ) ascfree((p)) |
354 | #define create_array(len,type) \ |
355 | ((len) > 0 ? (type *)ascmalloc((len)*sizeof(type)) : NULL) |
356 | #define create_zero_array(len,type) \ |
357 | ((len) > 0 ? (type *)asccalloc((len),sizeof(type)) : NULL) |
358 | |
359 | |
360 | /* |
361 | * Search Consistency Analysis during iterative process |
362 | * --------------------------------------------------------- |
363 | * The caller of this functions is in charge of |
364 | * defining the extension of the analysis by passing an integer |
365 | * which will tell us if 1) the analysis consider only the current |
366 | * and the previous alternatives or 2) the analysis consider all the |
367 | * alternatives visited at current the state of the solution |
368 | * algorithm. |
369 | */ |
370 | |
371 | /* |
372 | * Handling dynamic allocation of the structural information |
373 | */ |
374 | |
375 | #define alloc_array(nelts,type) \ |
376 | ((nelts) > 0 ? (type *)ascmalloc((nelts)*sizeof(type)) : NULL) |
377 | #define copy_nums(from,too,nnums) \ |
378 | asc_memcpy((from),(too),(nnums)*sizeof(int32)) |
379 | #define copy_subregions(from,too,nsubs) \ |
380 | asc_memcpy((from),(too),(nsubs)*sizeof(struct subregionID)) |
381 | |
382 | #if TEST_CONSISTENCY |
383 | /* |
384 | * Appends the subregion_visited into the list |
385 | */ |
386 | static void append_subregion(struct ds_subregion_list *sl, |
387 | struct subregionID sub) |
388 | { |
389 | if( sl->length == sl->capacity ) { |
390 | int32 newcap; |
391 | struct subregionID *newlist; |
392 | |
393 | newcap = sl->capacity + 10; |
394 | newlist = alloc_array(newcap,struct subregionID); |
395 | copy_subregions((char *)sl->sub_stack,(char *)newlist,sl->length); |
396 | if( sl->sub_stack != NULL ) { |
397 | ascfree(sl->sub_stack); |
398 | } |
399 | sl->sub_stack = newlist; |
400 | sl->capacity = newcap; |
401 | } |
402 | |
403 | sl->sub_stack[sl->length++] = sub; |
404 | } |
405 | |
406 | /* |
407 | * Appends the subregion_visited into the list |
408 | */ |
409 | static void append_sub_visited(struct ds_subregions_visited *sv, |
410 | unsigned long sub_visited) |
411 | { |
412 | if( sv->length == sv->capacity ) { |
413 | int32 newcap; |
414 | unsigned long *newlist; |
415 | |
416 | newcap = sv->capacity + 10; |
417 | newlist = alloc_array(newcap,unsigned long); |
418 | copy_nums((char *)sv->visited,(char *)newlist,sv->length); |
419 | if( sv->visited != NULL ) { |
420 | ascfree(sv->visited); |
421 | } |
422 | sv->visited = newlist; |
423 | sv->capacity = newcap; |
424 | } |
425 | |
426 | sv->visited[sv->length++] = sub_visited; |
427 | } |
428 | |
429 | static unsigned long powoftwo (int32 expo) |
430 | { |
431 | unsigned long val; |
432 | int32 c; |
433 | |
434 | val = 1; |
435 | for (c=1; c<= expo; c++) { |
436 | val = val * 2; |
437 | } |
438 | |
439 | return val; |
440 | } |
441 | |
442 | |
443 | /* |
444 | * Storage information (boolean values) about a subregion so that |
445 | * we can visit it later for interactive strucutral analysis |
446 | */ |
447 | static void ID_and_storage_subregion_information(slv_system_t server, |
448 | SlvClientToken asys) |
449 | { |
450 | slv9_system_t sys; |
451 | struct dis_discrete **bvlist; |
452 | struct dis_discrete *cur_dis; |
453 | struct ds_subregion_list *sl; |
454 | struct ds_subregions_visited *sv; |
455 | struct subregionID *sub; |
456 | dis_filter_t dfilter; |
457 | unsigned long val, visited, sID; |
458 | int32 d, numdvs, numdvf, dcount; |
459 | int32 len, s, found; |
460 | |
461 | sys = SLV9(asys); |
462 | check_system(sys); |
463 | |
464 | bvlist = sys->mdvlist; |
465 | if(bvlist == NULL ) { |
466 | FPRINTF(ASCERR,"ERROR: ID_and_storage_subregion_information.\n"); |
467 | FPRINTF(ASCERR," Master discrete var list was never set.\n"); |
468 | return; |
469 | } |
470 | numdvs = slv_get_num_master_dvars(server); |
471 | |
472 | dfilter.matchbits = (DIS_INWHEN | DIS_BOOLEAN); |
473 | dfilter.matchvalue = (DIS_INWHEN | DIS_BOOLEAN); |
474 | numdvf = slv_count_master_dvars(server,&dfilter); |
475 | |
476 | if (numdvf > 0) { |
477 | sub = (struct subregionID *)(ascmalloc(sizeof(struct subregionID))); |
478 | sub->bool_values = (int32 *)(ascmalloc(numdvf*sizeof(int32))); |
479 | } else { |
480 | FPRINTF(ASCERR,"ERROR: ID_and_storage_subregion_information.\n"); |
481 | FPRINTF(ASCERR," No boolean variables in the problem \n"); |
482 | return; |
483 | } |
484 | |
485 | dcount = 0; |
486 | val = 0; |
487 | for (d=0; d<numdvs; d++) { |
488 | cur_dis = bvlist[d]; |
489 | if (dis_apply_filter(cur_dis,&dfilter)) { |
490 | sub->bool_values[dcount] = dis_value(cur_dis); |
491 | dcount++; |
492 | if (sub->bool_values[dcount - 1] == 1) { |
493 | val = val + powoftwo(numdvf - dcount); |
494 | } |
495 | } |
496 | } |
497 | if ( (val == 0 ) && (numdvf > 0) ) { |
498 | val = powoftwo(numdvf); |
499 | } |
500 | sub->ID_number = val; |
501 | #if DEBUG_CONSISTENCY |
502 | FPRINTF(ASCERR,"ID of alternative is %ul \n", val); |
503 | #endif /* DEBUG_CONSISTENCY */ |
504 | visited = val; |
505 | found = 0; |
506 | len = sys->subregions_visited.length; |
507 | if (len > 0) { |
508 | for (s=0; s<len; s++) { |
509 | sID = sys->subregions_visited.visited[s]; |
510 | if (visited == sID) { |
511 | found = 1; |
512 | break; |
513 | } |
514 | } |
515 | } |
516 | |
517 | sv = &(sys->subregions_visited); |
518 | append_sub_visited(sv,visited); |
519 | |
520 | if (found == 0) { |
521 | #if DEBUG_CONSISTENCY |
522 | FPRINTF(ASCERR,"Saving alternative\n"); |
523 | #endif /* DEBUG_CONSISTENCY */ |
524 | sl = &(sys->subregion_list); |
525 | append_subregion(sl,(*sub)); |
526 | } else { |
527 | destroy_array(sub->bool_values); |
528 | ascfree(sub); |
529 | } |
530 | |
531 | return; |
532 | } |
533 | #endif |
534 | |
535 | /* |
536 | * Destroys subregion information |
537 | */ |
538 | static void destroy_subregion_information(SlvClientToken asys) |
539 | { |
540 | slv9_system_t sys; |
541 | struct subregionID *sub; |
542 | int32 lens, s; |
543 | |
544 | sys = SLV9(asys); |
545 | check_system(sys); |
546 | |
547 | if (sys->subregions_visited.visited != NULL) { |
548 | destroy_array(sys->subregions_visited.visited); |
549 | } |
550 | |
551 | lens = sys->subregion_list.length; |
552 | if (lens != 0) { |
553 | for (s=0; s<lens; s++) { |
554 | sub = &(sys->subregion_list.sub_stack[s]); |
555 | if (sub->bool_values != NULL) { |
556 | destroy_array(sub->bool_values); |
557 | } |
558 | } |
559 | } |
560 | |
561 | if (sys->subregion_list.sub_stack != NULL) { |
562 | destroy_array(sys->subregion_list.sub_stack); |
563 | } |
564 | |
565 | if (sys->bool_mindex != NULL) { |
566 | destroy_array(sys->bool_mindex); |
567 | } |
568 | } |
569 | |
570 | |
571 | #if 0 /** unused function eligible_set_for_neighboring_subregions */ |
572 | /* might be used if DEBUG_CONSISTENCY on */ |
573 | |
574 | /* |
575 | * Storing original values of boolean variables |
576 | */ |
577 | static void store_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 | bval->pre_val = create_array(dlen,int32); |
585 | bval->cur_val = create_array(dlen,int32); |
586 | for (d=1; d<=dlen; d++){ |
587 | dvar = (struct dis_discrete *)gl_fetch(bollist,d); |
588 | bval->cur_val[d-1] = dis_value(dvar); |
589 | bval->pre_val[d-1] = dis_previous_value(dvar); |
590 | } |
591 | } |
592 | |
593 | /* |
594 | * Restoring original values of boolean variables |
595 | */ |
596 | static void restore_original_bool_values(struct gl_list_t *bollist, |
597 | struct boolean_values *bval) |
598 | { |
599 | struct dis_discrete *dvar; |
600 | int32 d, dlen; |
601 | |
602 | dlen = gl_length(bollist); |
603 | for (d=1; d<=dlen; d++){ |
604 | dvar = (struct dis_discrete *)gl_fetch(bollist,d); |
605 | dis_set_boolean_value(dvar,bval->cur_val[d-1]); |
606 | dis_set_value(dvar,bval->cur_val[d-1]); |
607 | dis_set_previous_value(dvar,bval->pre_val[d-1]); |
608 | } |
609 | destroy_array(bval->cur_val); |
610 | destroy_array(bval->pre_val); |
611 | } |
612 | |
613 | #endif /* if 0 */ |
614 | |
615 | /* |
616 | * the first element of cur_cases is in position one. The result is |
617 | * the same array, but ordered and starting in position zero |
618 | */ |
619 | static void cases_reorder(int32 *cur_cases, int32 *correct_cases, int32 ncases) |
620 | { |
621 | int32 cur_case,pos=0,tmp_num,c,ind; |
622 | |
623 | for (c=1; c<=ncases; c++) { |
624 | tmp_num = 0; |
625 | for (ind=1; ind<=ncases; ind++) { |
626 | cur_case = cur_cases[ind]; |
627 | if (tmp_num < cur_case) { |
628 | pos = ind; |
629 | tmp_num = cur_case; |
630 | } |
631 | } |
632 | cur_cases[pos] = 0; |
633 | correct_cases[ncases-c] = tmp_num; |
634 | } |
635 | |
636 | return; |
637 | } |
638 | |
639 | #if 0 /** unused function eligible_set_for_neighboring_subregions */ |
640 | /* might appear if debug_consistency is true. */ |
641 | /* |
642 | * Restoring orignal configuration of the system |
643 | */ |
644 | static void restore_configuration(slv_system_t server, |
645 | struct gl_list_t *bollist) |
646 | |
647 | { |
648 | int32 *cur_cases, *correct_cases; |
649 | int32 ncases; |
650 | |
651 | cur_cases = cases_matching(bollist,&ncases); |
652 | correct_cases = create_array(ncases,int32); |
653 | cases_reorder(cur_cases,correct_cases,ncases); |
654 | set_active_rels_in_subregion(server,correct_cases,ncases,bollist); |
655 | set_active_vars_in_subregion(server); |
656 | destroy_array(cur_cases); |
657 | destroy_array(correct_cases); |
658 | } |
659 | |
660 | |
661 | /* |
662 | * Get the list of boolean variables in the problem which are |
663 | * associated with a WHEN |
664 | */ |
665 | static struct gl_list_t *get_list_of_booleans(slv_system_t server, |
666 | SlvClientToken asys) |
667 | { |
668 | slv9_system_t sys; |
669 | struct dis_discrete **bvlist; |
670 | struct dis_discrete *cur_dis; |
671 | struct gl_list_t *boolvars; |
672 | dis_filter_t dfilter; |
673 | int32 numdvf, numdvs, d, dcount; |
674 | |
675 | sys = SLV9(asys); |
676 | check_system(sys); |
677 | |
678 | bvlist = sys->mdvlist; |
679 | if(bvlist == NULL ) { |
680 | FPRINTF(ASCERR,"ERROR: (slv9) get_list_of_booleans.\n"); |
681 | FPRINTF(ASCERR," Master discrete var list was never set.\n"); |
682 | return NULL; |
683 | } |
684 | numdvs = slv_get_num_master_dvars(server); |
685 | |
686 | dfilter.matchbits = (DIS_INWHEN | DIS_BOOLEAN); |
687 | dfilter.matchvalue = (DIS_INWHEN | DIS_BOOLEAN); |
688 | numdvf = slv_count_master_dvars(server,&dfilter); |
689 | |
690 | if (numdvf == 0) { |
691 | FPRINTF(ASCERR,"ERROR: (slv9) get_list_of_booleans.\n"); |
692 | FPRINTF(ASCERR," No boolean variables in the problem \n"); |
693 | return NULL; |
694 | } |
695 | |
696 | sys->bool_mindex = (int32 *)(ascmalloc(numdvf*sizeof(int32))); |
697 | boolvars = gl_create(numdvf); |
698 | |
699 | dcount = 0; |
700 | for (d=0; d<numdvs; d++) { |
701 | cur_dis = bvlist[d]; |
702 | if (dis_apply_filter(cur_dis,&(dfilter))) { |
703 | gl_append_ptr(boolvars,cur_dis); |
704 | sys->bool_mindex[dcount] = d; |
705 | dcount++; |
706 | } |
707 | } |
708 | |
709 | return boolvars; |
710 | } |
711 | |
712 | #endif /* 0*/ |
713 | |
714 | /* |
715 | * Get the eligible var list for each alternative |
716 | * Return: |
717 | * 1 means everything went right |
718 | * 0 means the analysis has failed with the current parititioning |
719 | * -1 means a memory problem has occurred |
720 | */ |
721 | static int32 get_eligible_set(slv_system_t server,struct gl_list_t *disvars, |
722 | int32 *terminate) |
723 | { |
724 | struct var_variable **vslist; |
725 | struct var_variable **vmlist; |
726 | struct var_variable *mvar, *svar; |
727 | var_filter_t vfilter; |
728 | int32 *cur_cases; |
729 | int32 *correct_cases; |
730 | int32 *vars; |
731 | int32 v, count=0, ind; |
732 | int32 ncases; |
733 | int32 mnum; |
734 | int32 status,dof; |
735 | |
736 | vslist = slv_get_solvers_var_list(server); |
737 | vmlist = slv_get_master_var_list(server); |
738 | mnum = slv_get_num_master_vars(server); |
739 | for (v=0; v<mnum; v++) { |
740 | mvar = vmlist[v]; |
741 | var_set_eligible_in_subregion(mvar,FALSE); |
742 | } |
743 | |
744 | cur_cases = cases_matching(disvars,&ncases); |
745 | correct_cases = create_array(ncases,int32); |
746 | cases_reorder(cur_cases,correct_cases,ncases); |
747 | set_active_rels_in_subregion(server,correct_cases,ncases,disvars); |
748 | set_active_vars_in_subregion(server); |
749 | destroy_array(cur_cases); |
750 | destroy_array(correct_cases); |
751 | |
752 | #if DEBUG_CONSISTENCY |
753 | FPRINTF(ASCERR,"Analyzing alternative:\n"); |
754 | #endif /* DEBUG_CONSISTENCY */ |
755 | |
756 | if (!slvDOF_status(server,(&status),(&dof))) { |
757 | FPRINTF(ASCERR,"ERROR in combinatorial search\n"); |
758 | FPRINTF(ASCERR,"Combinatorial search aborted\n"); |
759 | return -1; |
760 | } else { |
761 | if (status == 3) { |
762 | #if DEBUG_CONSISTENCY |
763 | FPRINTF(ASCERR,"Alternative is structurally singular\n"); |
764 | #endif /* DEBUG_CONSISTENCY */ |
765 | (*terminate) = 0; |
766 | return 0; |
767 | } else { |
768 | if (status == 4) { |
769 | #if DEBUG_CONSISTENCY |
770 | FPRINTF(ASCERR,"Alternative is overspecified\n"); |
771 | #endif /* DEBUG_CONSISTENCY */ |
772 | (*terminate) = 0; |
773 | return 0; |
774 | } |
775 | } |
776 | } |
777 | |
778 | if (status == 1) { |
779 | (*terminate) = 0; |
780 | #if DEBUG_CONSISTENCY |
781 | FPRINTF(ASCERR,"Alternative has % d degrees of freedom.\n", dof); |
782 | |
783 | #endif /* DEBUG_CONSISTENCY */ |
784 | if (slvDOF_eligible(server,&(vars))) { |
785 | count = 0; |
786 | while (vars[count] != -1) { |
787 | ind = vars[count]; |
788 | svar = vslist[ind]; |
789 | v = var_mindex(svar); |
790 | mvar = vmlist[v]; |
791 | var_set_eligible_in_subregion(mvar,TRUE); |
792 | count++; |
793 | } |
794 | destroy_array(vars); |
795 | } |
796 | if (dof > count) { |
797 | #if DEBUG_CONSISTENCY |
798 | FPRINTF(ASCERR, |
799 | "Alternative does not have enough number of eligible vars\n"); |
800 | #endif /* DEBUG_CONSISTENCY */ |
801 | return 0; |
802 | } |
803 | } |
804 | |
805 | if (status == 2) { |
806 | #if DEBUG_CONSISTENCY |
807 | FPRINTF(ASCERR,"Alternative is square.\n"); |
808 | #endif /* DEBUG_CONSISTENCY */ |
809 | } |
810 | |
811 | vfilter.matchbits = (VAR_ACTIVE | VAR_INCIDENT | VAR_SVAR |
812 | | VAR_ELIGIBLE_IN_SUBREGION); |
813 | vfilter.matchvalue = (VAR_ACTIVE | VAR_INCIDENT | VAR_SVAR); |
814 | |
815 | for (v=0; v<mnum; v++) { |
816 | mvar = vmlist[v]; |
817 | if(var_apply_filter(mvar,&vfilter)) { |
818 | var_set_eligible(mvar,FALSE); |
819 | } |
820 | var_set_eligible_in_subregion(mvar,FALSE); |
821 | } |
822 | |
823 | return 1; |
824 | } |
825 | |
826 | /* |
827 | * Get the eligible set of variables for each of the alternatives generated |
828 | * by modifying the values of the boolean variables with the values stored |
829 | * during the solution process |
830 | * Return: |
831 | * 1 means everything went right |
832 | * 0 means the analysis has failed with the current partitioning |
833 | * -1 means a memory problem or wierdness has occurred |
834 | */ |
835 | static int32 do_search_alternatives(slv_system_t server, SlvClientToken asys, |
836 | struct gl_list_t *disvars, |
837 | int32 *terminate, int32 all_sub) |
838 | { |
839 | slv9_system_t sys; |
840 | struct dis_discrete *cur_dis; |
841 | struct subregionID *sub; |
842 | int32 *values = NULL; |
843 | int32 dlen, test; |
844 | int32 lens, lenv, v, s, d; |
845 | int32 result; |
846 | unsigned long visited, vID; |
847 | |
848 | |
849 | sys = SLV9(asys); |
850 | |
851 | dlen = gl_length(disvars); |
852 | lenv = sys->subregions_visited.length; |
853 | lens = sys->subregion_list.length; |
854 | |
855 | if (all_sub == 0) { /* current and previous subregion */ |
856 | for (v=lenv-2; v<lenv; v++) { |
857 | test = 0; |
858 | vID = sys->subregions_visited.visited[v]; |
859 | for (s=lens-1; s>=0; s--) { |
860 | sub = &(sys->subregion_list.sub_stack[s]); |
861 | visited = sub->ID_number; |
862 | if (vID == visited) { |
863 | values = sub->bool_values; |
864 | test = 1; |
865 | FPRINTF(ASCERR,"s = %d \n",s); |
866 | break; |
867 | } |
868 | } |
869 | |
870 | if (test == 0) { |
871 | FPRINTF(ASCERR,"ERROR: (slv9) do_search_alternatives \n"); |
872 | FPRINTF(ASCERR," subregion not found \n"); |
873 | return -1; |
874 | } |
875 | #if DEBUG_CONSISTENCY |
876 | FPRINTF(ASCERR,"Alternative = %ul \n", vID); |
877 | #endif /* DEBUG_CONSISTENCY */ |
878 | for (d=0; d<dlen; d++) { |
879 | assert(values != NULL); /* if null, test was 0 above and we returned, in theory */ |
880 | cur_dis = (struct dis_discrete *)(gl_fetch(disvars,d+1)); |
881 | if (values[d] == 1) { |
882 | dis_set_boolean_value(cur_dis,TRUE); |
883 | } else { |
884 | dis_set_boolean_value(cur_dis,FALSE); |
885 | } |
886 | } |
887 | result = get_eligible_set(server,disvars,terminate); |
888 | if (result != 1) { |
889 | return result; |
890 | } |
891 | } |
892 | |
893 | } else { /* all visited subregions */ |
894 | |
895 | for (s=lens-1; s>=0; s--) { |
896 | sub = &(sys->subregion_list.sub_stack[s]); |
897 | values = sub->bool_values; |
898 | vID = sub->ID_number; |
899 | #if DEBUG_CONSISTENCY |
900 | FPRINTF(ASCERR,"Alternative = %ul \n", vID); |
901 | #endif /* DEBUG_CONSISTENCY */ |
902 | for (d=0; d<dlen; d++) { |
903 | cur_dis = (struct dis_discrete *)(gl_fetch(disvars,d+1)); |
904 | if (values[d] == 1) { |
905 | dis_set_boolean_value(cur_dis,TRUE); |
906 | } else { |
907 | dis_set_boolean_value(cur_dis,FALSE); |
908 | } |
909 | } |
910 | result = get_eligible_set(server,disvars,terminate); |
911 | if (result != 1) { |
912 | return result; |
913 | } |
914 | } |
915 | } |
916 | |
917 | return 1; |
918 | } |
919 | |
920 | |
921 | /* |
922 | * Perform consistency analysis for the visited/current-previous subregions. |
923 | * If all_subs is 1, the analysis takes in account all of the subregions |
924 | * visited by the solution algorithm at the current point if the solution |
925 | * procedure. If all_subs is 0, the analysis is only for the current |
926 | * and previous subregion. |
927 | */ |
928 | static int32 consistency(slv_system_t server, SlvClientToken asys, |
929 | struct gl_list_t *bollist, |
930 | int32 all_subs, int32 *terminate) |
931 | { |
932 | slv9_system_t sys; |
933 | struct var_variable **vmlist; |
934 | struct var_variable *mvar; |
935 | var_filter_t vfilter; |
936 | int32 *globeli = NULL; |
937 | int32 dlen; |
938 | int32 mnum, v, elnum; |
939 | int32 result; |
940 | int32 iter; |
941 | |
942 | sys = SLV9(asys); |
943 | check_system(sys); |
944 | |
945 | /* |
946 | * Initializing eligible bit for variables |
947 | */ |
948 | vmlist = slv_get_master_var_list(server); |
949 | mnum = slv_get_num_master_vars(server); |
950 | for (v=0; v<mnum; v++) { |
951 | mvar = vmlist[v]; |
952 | var_set_eligible(mvar,TRUE); |
953 | } |
954 | |
955 | dlen = gl_length(bollist); |
956 | |
957 | #if DEBUG_CONSISTENCY |
958 | FPRINTF(ASCERR,"S e a r c h i n g \n"); |
959 | #endif /* DEBUG_CONSISTENCY */ |
960 | result = do_search_alternatives(server,asys,bollist,terminate,all_subs); |
961 | |
962 | if (result != 1) { |
963 | #if DEBUG_CONSISTENCY |
964 | FPRINTF(ASCERR,"returning failed search after S e a r c h \n"); |
965 | #endif /* DEBUG_CONSISTENCY */ |
966 | return result; |
967 | } |
968 | |
969 | /* |
970 | * Getting the "globally" eligible variables |
971 | */ |
972 | vfilter.matchbits = (VAR_INCIDENT | VAR_SVAR | VAR_ELIGIBLE | VAR_FIXED); |
973 | vfilter.matchvalue = (VAR_INCIDENT | VAR_SVAR | VAR_ELIGIBLE); |
974 | elnum = slv_count_master_vars(server,&vfilter); |
975 | |
976 | if (elnum > 0) { |
977 | globeli = ASC_NEW_ARRAY(int32,elnum); |
978 | elnum = 0; |
979 | for (v=0; v<mnum; v++) { |
980 | mvar = vmlist[v]; |
981 | if(var_apply_filter(mvar,&vfilter)) { |
982 | #if DEBUG_CONSISTENCY |
983 | FPRINTF(ASCERR,"Eligible index = %d \n",v); |
984 | #endif /* DEBUG_CONSISTENCY */ |
985 | globeli[elnum] = v; |
986 | elnum++; |
987 | } |
988 | } |
989 | } |
990 | |
991 | /* |
992 | * Recursively analysis |
993 | */ |
994 | |
995 | if ((*terminate) == 1) { |
996 | if (elnum != 0) { |
997 | #if DEBUG_CONSISTENCY |
998 | FPRINTF(ASCERR,"All alternatives are square but the \n"); |
999 | FPRINTF(ASCERR,"Eligible set is not null\n"); |
1000 | #endif /* DEBUG_CONSISTENCY */ |
1001 | destroy_array(globeli); |
1002 | } |
1003 | return 1; |
1004 | } else { |
1005 | if (elnum == 0) { |
1006 | #if DEBUG_CONSISTENCY |
1007 | FPRINTF(ASCERR,"No globally eligible variables to be fixed.\n"); |
1008 | #endif /* DEBUG_CONSISTENCY */ |
1009 | return 0; |
1010 | } |
1011 | |
1012 | for (v=0; v<elnum; v++) { |
1013 | iter = 1; |
1014 | mvar = vmlist[globeli[v]]; |
1015 | var_set_fixed(mvar,TRUE); |
1016 | var_set_potentially_fixed(mvar,TRUE); |
1017 | #if DEBUG_CONSISTENCY |
1018 | FPRINTF(ASCERR,"Fixing index = %d \n",globeli[v]); |
1019 | FPRINTF(ASCERR,"N e s t e d S e a r c h \n"); |
1020 | #endif /* DEBUG_CONSISTENCY */ |
1021 | result = consistency(server,asys,bollist,all_subs,&iter); |
1022 | |
1023 | if (result != 1) { |
1024 | #if DEBUG_CONSISTENCY |
1025 | FPRINTF(ASCERR,"%d eliminated\n",globeli[v]); |
1026 | #endif /* DEBUG_CONSISTENCY */ |
1027 | var_set_fixed(mvar,FALSE); |
1028 | var_set_potentially_fixed(mvar,FALSE); |
1029 | continue; |
1030 | } else { |
1031 | if (iter == 1) { |
1032 | (*terminate) = 1; |
1033 | #if DEBUG_CONSISTENCY |
1034 | FPRINTF(ASCERR,"%d Acepted \n",globeli[v]); |
1035 | #endif /* DEBUG_CONSISTENCY */ |
1036 | destroy_array(globeli); |
1037 | return 1; |
1038 | } else { |
1039 | var_set_fixed(mvar,FALSE); |
1040 | var_set_potentially_fixed(mvar,FALSE); |
1041 | continue; |
1042 | } |
1043 | } |
1044 | } |
1045 | destroy_array(globeli); |
1046 | #if DEBUG_CONSISTENCY |
1047 | FPRINTF(ASCERR,"returning 0 after nested search\n"); |
1048 | #endif /* DEBUG_CONSISTENCY */ |
1049 | return 0; |
1050 | } |
1051 | } |
1052 | |
1053 | #if 0 /** unused function eligible_set_for_neighboring_subregions */ |
1054 | /* might appear if debug_consistency is true. */ |
1055 | |
1056 | /* |
1057 | * Get a set of globally eligible variables. Eligible for all the subregions |
1058 | * visited, or for the previous and current subregions. |
1059 | */ |
1060 | static int32 get_globally_eligible(slv_system_t server, SlvClientToken asys, |
1061 | struct gl_list_t *bollist, |
1062 | int32 all_subs, int32 **eliset) |
1063 | { |
1064 | slv9_system_t sys; |
1065 | struct var_variable **vmlist; |
1066 | struct var_variable *mvar; |
1067 | var_filter_t vfilter; |
1068 | int32 dlen; |
1069 | int32 mnum, v, elnum; |
1070 | int32 terminate; |
1071 | int32 result; |
1072 | |
1073 | sys = SLV9(asys); |
1074 | check_system(sys); |
1075 | /* |
1076 | * Initializing eligible bit for variables |
1077 | */ |
1078 | vmlist = slv_get_master_var_list(server); |
1079 | mnum = slv_get_num_master_vars(server); |
1080 | for (v=0; v<mnum; v++) { |
1081 | mvar = vmlist[v]; |
1082 | var_set_eligible(mvar,TRUE); |
1083 | } |
1084 | |
1085 | dlen = gl_length(bollist); |
1086 | |
1087 | /* |
1088 | * initializing |
1089 | */ |
1090 | *eliset = NULL; |
1091 | terminate = 1; |
1092 | |
1093 | #if DEBUG_CONSISTENCY |
1094 | FPRINTF(ASCERR,"S e a r c h i n g \n"); |
1095 | #endif /* DEBUG_CONSISTENCY */ |
1096 | result = do_search_alternatives(server,asys,bollist,&terminate,all_subs); |
1097 | |
1098 | if (result != 1) { |
1099 | if (terminate == 0) { |
1100 | #if DEBUG_CONSISTENCY |
1101 | FPRINTF(ASCERR,"ERROR: some alternatives are either singular or\n"); |
1102 | FPRINTF(ASCERR,"overspecified. All the alternatives have to be\n"); |
1103 | FPRINTF(ASCERR, |
1104 | "either square or underspecified to complete the analysis\n"); |
1105 | #endif /* DEBUG_CONSISTENCY */ |
1106 | } |
1107 | return 0; |
1108 | } |
1109 | |
1110 | /* |
1111 | * Getting the "globally" eligible variables |
1112 | */ |
1113 | vfilter.matchbits = (VAR_INCIDENT | VAR_SVAR | VAR_ELIGIBLE | VAR_FIXED); |
1114 | vfilter.matchvalue = (VAR_INCIDENT | VAR_SVAR | VAR_ELIGIBLE); |
1115 | elnum = slv_count_master_vars(server,&vfilter); |
1116 | |
1117 | *eliset = (int32 *)ascmalloc((elnum+1)*sizeof(int32)); |
1118 | elnum = 0; |
1119 | for (v=0; v<mnum; v++) { |
1120 | mvar = vmlist[v]; |
1121 | if(var_apply_filter(mvar,&vfilter)) { |
1122 | #if DEBUG_CONSISTENCY |
1123 | FPRINTF(ASCERR,"Eligible index = %d \n",v); |
1124 | FPRINTF(ASCERR,"Variable : \n"); |
1125 | print_var_name(ASCERR,sys,mvar); |
1126 | #endif /* DEBUG_CONSISTENCY */ |
1127 | (*eliset)[elnum] = v; |
1128 | elnum++; |
1129 | } |
1130 | } |
1131 | (*eliset)[elnum] = -1; |
1132 | |
1133 | if (elnum == 0) { |
1134 | if (terminate == 0) { |
1135 | #if DEBUG_CONSISTENCY |
1136 | FPRINTF(ASCERR, |
1137 | "Some alternatives are underspecified, but there does\n"); |
1138 | FPRINTF(ASCERR,"not exist a set of eligible variables consistent \n"); |
1139 | FPRINTF(ASCERR,"with all the alternatives\n"); |
1140 | #endif /* DEBUG_CONSISTENCY */ |
1141 | } else { |
1142 | #if DEBUG_CONSISTENCY |
1143 | FPRINTF(ASCERR,"All alternatives are already square\n"); |
1144 | #endif /* DEBUG_CONSISTENCY */ |
1145 | } |
1146 | return 0; |
1147 | } else { |
1148 | if (terminate == 1) { |
1149 | #if DEBUG_CONSISTENCY |
1150 | FPRINTF(ASCERR,"All alternatives are square but the \n"); |
1151 | FPRINTF(ASCERR,"Eligible set is not null\n"); |
1152 | #endif /* DEBUG_CONSISTENCY */ |
1153 | } |
1154 | } |
1155 | return 1; |
1156 | } |
1157 | |
1158 | |
1159 | |
1160 | /* |
1161 | * Store and restore values of the boolean variables of the problem |
1162 | * and calls for the the set of globally eligible variables.If all_subs |
1163 | * is 1, the analysis takes in account all of the subregions visited |
1164 | * by the solution algorithm at the current point if the solution |
1165 | * procedure. If all_subs is 0, the analysis is only for the current |
1166 | * and previous subregion. |
1167 | */ |
1168 | static int32 consistent_eligible_set_for_subregions(slv_system_t server, |
1169 | SlvClientToken asys, |
1170 | int32 **vlist, |
1171 | int32 all_subs) |
1172 | { |
1173 | struct gl_list_t *blist; |
1174 | struct boolean_values bval; |
1175 | int32 result; |
1176 | |
1177 | if (server==NULL || vlist == NULL) { |
1178 | FPRINTF(ASCERR, |
1179 | "consistent_eligible_set_for_subregions called with NULL.\n"); |
1180 | return 0; |
1181 | } |
1182 | |
1183 | blist = get_list_of_booleans(server,asys); |
1184 | |
1185 | if ( (blist == NULL) || (gl_length(blist) == 0) ) { |
1186 | FPRINTF(ASCERR,"ERROR: (slv9) consistent_eligible_set_for_subregions \n"); |
1187 | FPRINTF(ASCERR," List of boolean vars could not be found\n"); |
1188 | return 0; |
1189 | } |
1190 | |
1191 | store_original_bool_values(blist,&(bval)); |
1192 | result = get_globally_eligible(server,asys,blist,all_subs,vlist); |
1193 | |
1194 | restore_original_bool_values(blist,&(bval)); |
1195 | restore_configuration(server,blist); |
1196 | gl_destroy(blist); |
1197 | |
1198 | if (result == 1) { |
1199 | return 1; |
1200 | } else { |
1201 | return 0; |
1202 | } |
1203 | |
1204 | } |
1205 | |
1206 | /* |
1207 | * Store and restore values of the boolean variables of the problem |
1208 | * and calls for the consistency analysis of the subregions.If all_subs |
1209 | * is 1, the analysis takes in account all of the subregions visited |
1210 | * by the solution algorithm at the current point if the solution |
1211 | * procedure. If all_subs is 0, the analysis is only for the current |
1212 | * and previous subregion. |
1213 | */ |
1214 | static int32 analyze_subregions(slv_system_t server,SlvClientToken asys, |
1215 | int32 **vlist, int32 all_subs) |
1216 | { |
1217 | slv9_system_t sys; |
1218 | struct var_variable ** vmlist; |
1219 | struct var_variable *mvar; |
1220 | struct gl_list_t *blist; |
1221 | struct boolean_values bval; |
1222 | var_filter_t vfilter; |
1223 | int32 mnum, elnum, v; |
1224 | int32 result; |
1225 | int32 terminate; |
1226 | |
1227 | sys = SLV9(asys); |
1228 | check_system(sys); |
1229 | |
1230 | if (server==NULL || vlist == NULL) { |
1231 | FPRINTF(ASCERR,"(slv9) analyze_subregions called with NULL.\n"); |
1232 | return 0; |
1233 | } |
1234 | |
1235 | blist = get_list_of_booleans(server,asys); |
1236 | if ( (blist == NULL) || (gl_length(blist) == 0) ) { |
1237 | FPRINTF(ASCERR,"ERROR: (slv9) analyze_subregions \n"); |
1238 | FPRINTF(ASCERR," List of boolean vars could not be found\n"); |
1239 | return 0; |
1240 | } |
1241 | |
1242 | store_original_bool_values(blist,&(bval)); |
1243 | /* |
1244 | * initializing |
1245 | */ |
1246 | terminate = 1; |
1247 | (*vlist) = NULL; |
1248 | |
1249 | vmlist = slv_get_master_var_list(server); |
1250 | mnum = slv_get_num_master_vars(server); |
1251 | |
1252 | vfilter.matchbits = (VAR_POTENTIALLY_FIXED); |
1253 | vfilter.matchvalue = (VAR_POTENTIALLY_FIXED); |
1254 | |
1255 | result = consistency(server,asys,blist,all_subs,&terminate); |
1256 | |
1257 | if (result == 1) { |
1258 | /* |
1259 | * Getting the set of eligible variables |
1260 | */ |
1261 | elnum = slv_count_master_vars(server,&vfilter); |
1262 | *vlist = (int32 *)ascmalloc((elnum+1)*sizeof(int32)); |
1263 | elnum = 0; |
1264 | for (v=0; v<mnum; v++) { |
1265 | mvar = vmlist[v]; |
1266 | if(var_apply_filter(mvar,&vfilter)) { |
1267 | var_set_fixed(mvar,FALSE); |
1268 | var_set_potentially_fixed(mvar,FALSE); |
1269 | #if DEBUG_CONSISTENCY |
1270 | FPRINTF(ASCERR,"Variable in consistent set: \n"); |
1271 | print_var_name(ASCERR,sys,mvar); |
1272 | #endif /* DEBUG_CONSISTENCY */ |
1273 | (*vlist)[elnum] = v; |
1274 | elnum++; |
1275 | } |
1276 | } |
1277 | (*vlist)[elnum] = -1; |
1278 | |
1279 | restore_original_bool_values(blist,&(bval)); |
1280 | restore_configuration(server,blist); |
1281 | gl_destroy(blist); |
1282 | return 1; |
1283 | } else { |
1284 | for (v=0; v<mnum; v++) { |
1285 | mvar = vmlist[v]; |
1286 | if(var_apply_filter(mvar,&vfilter)) { |
1287 | var_set_fixed(mvar,FALSE); |
1288 | var_set_potentially_fixed(mvar,FALSE); |
1289 | } |
1290 | } |
1291 | restore_original_bool_values(blist,&(bval)); |
1292 | restore_configuration(server,blist); |
1293 | gl_destroy(blist); |
1294 | return 0; |
1295 | } |
1296 | } |
1297 | |
1298 | |
1299 | /* |
1300 | * Finds the globally eligible set of variables only for the current and |
1301 | * previous subregions |
1302 | */ |
1303 | static int32 eligible_set_for_neighboring_subregions(slv_system_t server, |
1304 | SlvClientToken asys, |
1305 | int32 **vlist) |
1306 | { |
1307 | slv9_system_t sys; |
1308 | |
1309 | sys = SLV9(asys); |
1310 | check_system(sys); |
1311 | |
1312 | if( sys->mdvlist == NULL ) { |
1313 | FPRINTF(ASCERR,"ERROR: (slv9) eligible_set_for_neighboring_subregions\n"); |
1314 | FPRINTF(ASCERR," Discrete Variable list was never set.\n"); |
1315 | return 0; |
1316 | } |
1317 | |
1318 | if (!(sys->need_consistency_analysis)) { |
1319 | FPRINTF(ASCERR,"Globally eligible set not necessary\n"); |
1320 | FPRINTF(ASCERR,"All the subregions have the same structure \n"); |
1321 | return 0; |
1322 | } |
1323 | |
1324 | if (consistent_eligible_set_for_subregions(server,asys,vlist,0)) { |
1325 | return 1; |
1326 | } |
1327 | |
1328 | return 0; |
1329 | } |
1330 | |
1331 | |
1332 | /* |
1333 | * Perform the consistency analysis algorithm only for the current and |
1334 | * previous subregions |
1335 | */ |
1336 | static int32 consistency_for_neighboring_subregions(slv_system_t server, |
1337 | SlvClientToken asys, |
1338 | int32 **vlist) |
1339 | { |
1340 | slv9_system_t sys; |
1341 | |
1342 | sys = SLV9(asys); |
1343 | check_system(sys); |
1344 | |
1345 | if( sys->mdvlist == NULL ) { |
1346 | FPRINTF(ASCERR,"ERROR: (slv9) consistency_for_neighboring_subregions\n"); |
1347 | FPRINTF(ASCERR," Discrete Variable list was never set.\n"); |
1348 | return 0; |
1349 | } |
1350 | |
1351 | if (!(sys->need_consistency_analysis)) { |
1352 | FPRINTF(ASCERR,"consistency_analysis is not required\n"); |
1353 | FPRINTF(ASCERR,"All the subregions have the same structure \n"); |
1354 | return 0; |
1355 | } |
1356 | |
1357 | if (analyze_subregions(server,asys,vlist,0)) { |
1358 | return 1; |
1359 | } |
1360 | |
1361 | return 0; |
1362 | } |
1363 | |
1364 | |
1365 | |
1366 | /* |
1367 | * Consistency analysis for visisted subregions. This function |
1368 | * gets the subregions that the solution algorithm has visited and |
1369 | * analyzes them. |
1370 | */ |
1371 | static int32 eligible_set_for_subregions(slv_system_t server, |
1372 | SlvClientToken asys, |
1373 | int32 **vlist) |
1374 | { |
1375 | slv9_system_t sys; |
1376 | |
1377 | sys = SLV9(asys); |
1378 | check_system(sys); |
1379 | |
1380 | if( sys->mdvlist == NULL ) { |
1381 | FPRINTF(ASCERR,"ERROR: (slv9) eligible_set_for_subregions \n"); |
1382 | FPRINTF(ASCERR," Discrete Variable list was never set.\n"); |
1383 | return 0; |
1384 | } |
1385 | |
1386 | if (!(sys->need_consistency_analysis)) { |
1387 | FPRINTF(ASCERR,"Globally eligible set not necessary \n"); |
1388 | FPRINTF(ASCERR,"All the subregions have the same structure \n"); |
1389 | return 0; |
1390 | } |
1391 | |
1392 | if (consistent_eligible_set_for_subregions(server,asys,vlist,1)) { |
1393 | return 1; |
1394 | } |
1395 | |
1396 | return 0; |
1397 | } |
1398 | |
1399 | |
1400 | /* |
1401 | * Consistency analysis for visisted subregions. This function |
1402 | * gets the subregions that the solution algorithm has visited and |
1403 | * analyzes them. |
1404 | */ |
1405 | static int32 consistency_analysis_for_subregions(slv_system_t server, |
1406 | SlvClientToken asys, |
1407 | int32 **vlist) |
1408 | { |
1409 | slv9_system_t sys; |
1410 | |
1411 | sys = SLV9(asys); |
1412 | check_system(sys); |
1413 | |
1414 | if( sys->mdvlist == NULL ) { |
1415 | FPRINTF(ASCERR,"ERROR: (slv9) consistency_analysis_for_subregions\n"); |
1416 | FPRINTF(ASCERR," Discrete Variable list was never set.\n"); |
1417 | return 0; |
1418 | } |
1419 | |
1420 | if (!(sys->need_consistency_analysis)) { |
1421 | FPRINTF(ASCERR,"consistency_analysis is not required\n"); |
1422 | FPRINTF(ASCERR,"All the subregions have the same structure \n"); |
1423 | return 0; |
1424 | } |
1425 | |
1426 | if (analyze_subregions(server,asys,vlist,1)) { |
1427 | return 1; |
1428 | } |
1429 | |
1430 | return 0; |
1431 | } |
1432 | |
1433 | #endif /*#if 0 unused functions */ |
1434 | |
1435 | |
1436 | /* |
1437 | * Handling of solution of the Logical Equations |
1438 | * --------------------------------------------------------- |
1439 | * This is made this way because it is a process which will be |
1440 | * required very often. |
1441 | */ |
1442 | |
1443 | /* |
1444 | * Solution of the logical relations encountered in the system based on |
1445 | * the current values of the discrete variables. |
1446 | */ |
1447 | static void solve_logical_relations(slv_system_t server) |
1448 | { |
1449 | slv_set_client_token(server,token[LOGICAL_SOLVER]); |
1450 | slv_set_solver_index(server,solver_index[LOGICAL_SOLVER]); |
1451 | slv_presolve(server); |
1452 | #if SHOW_LOGICAL_DETAILS |
1453 | FPRINTF(ASCERR,"Solving Logical Relations\n"); |
1454 | #endif /* SHOW_LOGICAL_DETAILS */ |
1455 | slv_solve(server); |
1456 | } |
1457 | |
1458 | |
1459 | |
1460 | /* |
1461 | * Handling the modification of parameters in external solvers |
1462 | * --------------------------------------------------------- |
1463 | */ |
1464 | |
1465 | /* |
1466 | * different types of parameter values |
1467 | */ |
1468 | union param_value { |
1469 | int32 i; |
1470 | real64 r; |
1471 | int32 b; |
1472 | char *c; |
1473 | }; |
1474 | |
1475 | |
1476 | /* |
1477 | * Setting the value of a parameter in a subsidiary solver |
1478 | */ |
1479 | static void set_param_in_solver(slv_system_t server, int32 solver, |
1480 | enum parm_type types, char *param, |
1481 | union param_value *value) |
1482 | { |
1483 | slv_parameters_t p; |
1484 | int32 len,length; |
1485 | |
1486 | slv_set_client_token(server,token[solver]); |
1487 | slv_set_solver_index(server,solver_index[solver]); |
1488 | slv_get_parameters(server,&p); |
1489 | length = p.num_parms; |
1490 | for (len = 0; len < length; len++) { |
1491 | if (p.parms[len].type == types) { |
1492 | switch (p.parms[len].type) { |
1493 | case bool_parm: |
1494 | if (strcmp(param,p.parms[len].name) == 0) { |
1495 | p.parms[len].info.b.value = value->b; |
1496 | } |
1497 | break; |
1498 | case real_parm: |
1499 | if (strcmp(param,p.parms[len].name) == 0) { |
1500 | p.parms[len].info.r.value = value->r; |
1501 | } |
1502 | break; |
1503 | case char_parm: |
1504 | if (strcmp(param,p.parms[len].name) == 0) { |
1505 | p.parms[len].info.c.value = value->c; |
1506 | } |
1507 | break; |
1508 | case int_parm: |
1509 | if (strcmp(param,p.parms[len].name) == 0) { |
1510 | p.parms[len].info.i.value = value->i; |
1511 | } |
1512 | break; |
1513 | default: |
1514 | break; |
1515 | } |
1516 | } |
1517 | } |
1518 | return; |
1519 | } |
1520 | |
1521 | |
1522 | /* |
1523 | * Analysis of Discrete Variables |
1524 | * ------------------------------- |
1525 | */ |
1526 | |
1527 | /* |
1528 | * Compare current values of the discrete variables with their previous values |
1529 | * in order to know if some of them have changed. |
1530 | */ |
1531 | static int32 some_dis_vars_changed(slv_system_t server, SlvClientToken asys) |
1532 | { |
1533 | struct dis_discrete **dv, *cur_dis; |
1534 | int32 numdvs, ind; |
1535 | slv9_system_t sys; |
1536 | |
1537 | sys = SLV9(asys); |
1538 | check_system(sys); |
1539 | |
1540 | if( sys->dvlist == NULL ) { |
1541 | FPRINTF(ASCERR,"ERROR: (slv9) some_dis_vars_changed\n"); |
1542 | FPRINTF(ASCERR," Discrete variable list was never set.\n"); |
1543 | return 0; |
1544 | } |
1545 | |
1546 | dv = sys->dvlist; |
1547 | numdvs = slv_get_num_solvers_dvars(server); |
1548 | for( ind = 0; ind < numdvs; ind++ ) { |
1549 | cur_dis = dv[ind]; |
1550 | #if SHOW_LOGICAL_DETAILS |
1551 | FPRINTF(ASCERR,"Boundary index = %d \n",ind); |
1552 | FPRINTF(ASCERR,"Current Value = %d\n",dis_value(cur_dis)); |
1553 | FPRINTF(ASCERR,"Previous Value = %d\n",dis_previous_value(cur_dis)); |
1554 | #endif /* SHOW_LOGICAL_DETAILS */ |
1555 | if ((dis_kind(cur_dis)==e_dis_boolean_t ) && dis_inwhen(cur_dis) ) { |
1556 | if (dis_value(cur_dis) != dis_previous_value(cur_dis)) { |
1557 | return 1; |
1558 | } |
1559 | } |
1560 | } |
1561 | return 0; |
1562 | } |
1563 | |
1564 | /* |
1565 | * Compare the original value of a discrete boolean variable (before |
1566 | * perturbation of boundaries) with its values after a solution |
1567 | * of the logical relations with some perturbed values for boundaries. |
1568 | * If those values are different, the bit VAL_MODIFIED is set to |
1569 | * TRUE. This will give us the boolean variable which will change as a |
1570 | * consequence of a boundary crossing. |
1571 | */ |
1572 | static void search_for_modified_dvars(struct dis_discrete **dv, |
1573 | int32 numdvs, |
1574 | struct boolean_values *bval) |
1575 | { |
1576 | struct dis_discrete *cur_dis; |
1577 | int32 d; |
1578 | int32 orig_value; |
1579 | |
1580 | for (d=0; d<numdvs; d++) { |
1581 | cur_dis = dv[d]; |
1582 | if(dis_inwhen(cur_dis) && dis_boolean(cur_dis)) { |
1583 | orig_value = bval->cur_val[d]; |
1584 | if (orig_value != dis_value(cur_dis)) { |
1585 | dis_set_val_modified(cur_dis,TRUE); |
1586 | } |
1587 | } |
1588 | } |
1589 | } |
1590 | |
1591 | |
1592 | /* |
1593 | * Analysis of Boundaries |
1594 | * ---------------------------- |
1595 | */ |
1596 | |
1597 | /* |
1598 | * Evaluates the current status (satisfied? , at zero?) of a boundary |
1599 | * and sets its flags accordingly. At the same time, it updates the |
1600 | * residual of the relation included in the boundary (see |
1601 | * bndman_calc_satisfied). |
1602 | */ |
1603 | |
1604 | static void update_boundaries(slv_system_t server, SlvClientToken asys) |
1605 | { |
1606 | struct bnd_boundary **bp; |
1607 | int32 numbnds, ind, value; |
1608 | slv9_system_t sys; |
1609 | |
1610 | sys = SLV9(asys); |
1611 | check_system(sys); |
1612 | |
1613 | if( sys->blist == NULL ) { |
1614 | FPRINTF(ASCERR,"ERROR: (slv9) update_boundaries.\n"); |
1615 | FPRINTF(ASCERR," Boundary list was never set.\n"); |
1616 | return; |
1617 | } |
1618 | |
1619 | bp = sys->blist; |
1620 | numbnds = slv_get_num_solvers_bnds(server); |
1621 | |
1622 | for( ind = 0; ind < numbnds; ++ind ) { |
1623 | value = bnd_status_cur(bp[ind]); |
1624 | bnd_set_pre_status(bp[ind],value); |
1625 | value = bndman_calc_satisfied(bp[ind]); |
1626 | bnd_set_cur_status(bp[ind],value); |
1627 | if ( (bnd_status_cur(bp[ind]) != bnd_status_pre(bp[ind])) && |
1628 | bnd_kind(bp[ind]) == e_bnd_rel && !bnd_at_zero(bp[ind])) { |
1629 | bnd_set_crossed(bp[ind],TRUE); |
1630 | } else { |
1631 | bnd_set_crossed(bp[ind],FALSE); |
1632 | } |
1633 | if (bnd_kind(bp[ind]) == e_bnd_rel) { |
1634 | value = bndman_calc_at_zero(bp[ind]); |
1635 | bnd_set_at_zero(bp[ind],value); |
1636 | } else { |
1637 | bnd_set_at_zero(bp[ind],FALSE); |
1638 | } |
1639 | } |
1640 | } |
1641 | |
1642 | |
1643 | /* |
1644 | * Look for some boundary with the CROSSED bit active. If this boundary |
1645 | * is used in some logical relation, the function returns 1, else returns 0 |
1646 | */ |
1647 | static int32 some_boundaries_crossed(slv_system_t server, SlvClientToken asys) |
1648 | { |
1649 | struct bnd_boundary **bp, *cur_bnd; |
1650 | int32 numbnds, ind; |
1651 | slv9_system_t sys; |
1652 | |
1653 | sys = SLV9(asys); |
1654 | check_system(sys); |
1655 | |
1656 | if( sys->blist == NULL ) { |
1657 | FPRINTF(ASCERR,"ERROR: (slv9) some_boundaries_crossed\n"); |
1658 | FPRINTF(ASCERR," Boundary list was never set.\n"); |
1659 | return 0; |
1660 | } |
1661 | |
1662 | bp = sys->blist; |
1663 | numbnds = slv_get_num_solvers_bnds(server); |
1664 | for( ind = 0; ind < numbnds; ++ind ) { |
1665 | cur_bnd = bp[ind]; |
1666 | if (bnd_crossed(cur_bnd) && bnd_in_logrel(cur_bnd)) { |
1667 | return 1; |
1668 | } |
1669 | } |
1670 | return 0; |
1671 | } |
1672 | |
1673 | /* |
1674 | * Look for some boundary with the AT_ZERO bit active.If this boundary |
1675 | * is used in some logical relation, the function returns 1, else returns 0 |
1676 | */ |
1677 | static int32 some_boundaries_at_zero(slv_system_t server, SlvClientToken asys) |
1678 | { |
1679 | struct bnd_boundary **bp, *cur_bnd; |
1680 | int32 numbnds, ind; |
1681 | slv9_system_t sys; |
1682 | |
1683 | sys = SLV9(asys); |
1684 | check_system(sys); |
1685 | |
1686 | if( sys->blist == NULL ) { |
1687 | FPRINTF(ASCERR,"ERROR: (slv9) some_boundaries_at_zero\n"); |
1688 | FPRINTF(ASCERR," Boundary list was never set.\n"); |
1689 | return 0; |
1690 | } |
1691 | |
1692 | bp = sys->blist; |
1693 | numbnds = slv_get_num_solvers_bnds(server); |
1694 | for( ind = 0; ind < numbnds; ++ind ) { |
1695 | cur_bnd = bp[ind]; |
1696 | if (bnd_at_zero(cur_bnd) && bnd_in_logrel(cur_bnd)) { |
1697 | return 1; |
1698 | } |
1699 | } |
1700 | return 0; |
1701 | } |
1702 | |
1703 | /* |
1704 | * Perform the combinatorial perturbation of the boundaries which are |
1705 | * at their zero. That means: We are going to perform a combinatorial |
1706 | * search, changing the truth value of a SATISFIED term (for the |
1707 | * specified boundaries) ON and OFF, and finding the boolean variables |
1708 | * affected for those changes in value of the SATISFIED terms. |
1709 | */ |
1710 | static void do_perturbation_combinations(slv_system_t server, |
1711 | struct boolean_values *bval, |
1712 | struct bnd_boundary **bp, |
1713 | struct dis_discrete **dv, |
1714 | int32 numdvs,int32 *bndatzero, |
1715 | int32 ind, int32 numbndf) |
1716 | { |
1717 | slv_status_t status; |
1718 | int32 indpo; |
1719 | |
1720 | if(ind<(numbndf-1)) { |
1721 | indpo = ind + 1; |
1722 | bnd_set_perturb(bp[bndatzero[ind]],TRUE); |
1723 | do_perturbation_combinations(server,bval,bp,dv,numdvs, |
1724 | bndatzero,indpo,numbndf); |
1725 | bnd_set_perturb(bp[bndatzero[ind]],FALSE); |
1726 | do_perturbation_combinations(server,bval,bp,dv,numdvs, |
1727 | bndatzero,indpo,numbndf); |
1728 | } else { |
1729 | if (ind < numbndf) { |
1730 | bnd_set_perturb(bp[bndatzero[ind]],TRUE); |
1731 | solve_logical_relations(server); |
1732 | slv_get_status(server,&status); |
1733 | if(!status.converged) { |
1734 | FPRINTF(ASCERR,"WARNING: \n"); |
1735 | FPRINTF(ASCERR,"(slv9) do_perturbation_combinations\n"); |
1736 | FPRINTF(ASCERR," Not convergence in logical solver \n"); |
1737 | } else { |
1738 | search_for_modified_dvars(dv,numdvs,bval); |
1739 | } |
1740 | bnd_set_perturb(bp[bndatzero[ind]],FALSE); |
1741 | solve_logical_relations(server); |
1742 | slv_get_status(server,&status); |
1743 | if(!status.converged) { |
1744 | FPRINTF(ASCERR,"WARNING: \n"); |
1745 | FPRINTF(ASCERR,"(slv9) do_perturbation_combinations\n"); |
1746 | FPRINTF(ASCERR," Not convergence in logical solver \n"); |
1747 | } else { |
1748 | search_for_modified_dvars(dv,numdvs,bval); |
1749 | } |
1750 | } else { |
1751 | FPRINTF(ASCERR,"ERROR: (slv9) do_perturbation_combinations\n"); |
1752 | FPRINTF(ASCERR," Wrong boundary index as argument\n"); |
1753 | } |
1754 | } |
1755 | return; |
1756 | } |
1757 | |
1758 | |
1759 | /* |
1760 | * Perform the combinatorial search of the subregions. That means: |
1761 | * We perform a combinatorial search, changing the value of the |
1762 | * discrete variables (given in disvars) TRUE and FALSE, and |
1763 | * finding which cases (in the WHENs) applies for each of the |
1764 | * combinations. |
1765 | */ |
1766 | static 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 void order_case(int32 *case_list, int32 *newcaselist, int ncases) |
1811 | { |
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 void order_cases(struct matching_cases *cases,int pos_cases) |
1835 | { |
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 int32 compare_case(int32 *cur_set, int32 *comp_set, int cur_ncases) |
1867 | { |
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 void compare_cases(struct matching_cases *cases,int pos_cases) |
1886 | { |
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 int32 at_a_boundary(slv_system_t server, SlvClientToken asys, |
1925 | int32 *n_subregions, |
1926 | struct matching_cases **subregions, |
1927 | int32 *cur_subregion, |
1928 | struct gl_list_t *disvars) |
1929 | { |
1930 | slv9_system_t sys; |
1931 | struct bnd_boundary **bp, *cur_bnd; |
1932 | struct dis_discrete **dv, *cur_dis; |
1933 | struct boolean_values bval; |
1934 | dis_filter_t dfilter; |
1935 | bnd_filter_t bfilter; |
1936 | struct matching_cases *cases; |
1937 | int32 *bndatzero; |
1938 | int32 *dvarmodified; |
1939 | int32 *cur_cases; |
1940 | int32 *caselist, *newcaselist; |
1941 | int32 numbnds, numbndf, b, ind; |
1942 | int32 numdvs, numdvf, d; |
1943 | int32 cur_ncases, assign_cur_sub; |
1944 | int32 pos_cases, comb; |
1945 | char *param; |
1946 | union param_value u; |
1947 | |
1948 | sys = SLV9(asys); |
1949 | check_system(sys); |
1950 | |
1951 | if( sys->blist == NULL ) { |
1952 | FPRINTF(ASCERR,"ERROR: (slv9) at_a_boundary\n"); |
1953 | FPRINTF(ASCERR," Boundary list was never set.\n"); |
1954 | return 0; |
1955 | } |
1956 | |
1957 | if( sys->dvlist == NULL ) { |
1958 | FPRINTF(ASCERR,"ERROR: (slv9) at_a_boundary\n"); |
1959 | FPRINTF(ASCERR," Discrete Variable list was never set.\n"); |
1960 | return 0; |
1961 | } |
1962 | |
1963 | if (!some_boundaries_at_zero(server,asys)) { |
1964 | return 0; |
1965 | } |
1966 | |
1967 | bp = sys->blist; |
1968 | numbnds = slv_get_num_solvers_bnds(server); |
1969 | bfilter.matchbits = (BND_AT_ZERO); |
1970 | bfilter.matchvalue = (BND_AT_ZERO); |
1971 | numbndf = slv_count_solvers_bnds(server,&bfilter); |
1972 | bndatzero = create_array(numbndf,int32); |
1973 | ind = 0; |
1974 | for (b=0; b<numbnds; b++) { |
1975 | cur_bnd = bp[b]; |
1976 | bnd_set_perturb(cur_bnd,FALSE); |
1977 | if (bnd_at_zero(cur_bnd)) { |
1978 | #if SHOW_BOUNDARY_ANALYSIS_DETAILS |
1979 | FPRINTF(ASCERR,"boundary at zero = %d\n",b); |
1980 | #endif /* SHOW_BOUNDARY_ANALYSIS_DETAILS */ |
1981 | bndatzero[ind] = b; |
1982 | ind++; |
1983 | } |
1984 | } |
1985 | |
1986 | dv = sys->dvlist; |
1987 | numdvs = slv_get_num_solvers_dvars(server); |
1988 | bval.cur_val = create_array(numdvs,int32); |
1989 | bval.pre_val = create_array(numdvs,int32); |
1990 | |
1991 | for (d=0; d<numdvs; d++) { |
1992 | cur_dis = dv[d]; |
1993 | dis_set_val_modified(cur_dis,FALSE); |
1994 | bval.cur_val[d] = dis_value(cur_dis); |
1995 | bval.pre_val[d] = dis_previous_value(cur_dis); |
1996 | } |
1997 | |
1998 | #if SHOW_BOUNDARY_ANALYSIS_DETAILS |
1999 | FPRINTF(ASCERR,"Executing combinatorial perturbation of boundaries\n"); |
2000 | #endif /* SHOW_BOUNDARY_ANALYSIS_DETAILS */ |
2001 | |
2002 | /* |
2003 | * Setting the value of the perturbation mode flag in the logical solver |
2004 | * to 1. |
2005 | * PERTURB_BOUNDARY is a boolean parameter of the logical solver |
2006 | * LRSlv. This parameter tells the solver whether it should change |
2007 | * the truth value of the SATISFIED terms or not (only for the |
2008 | * boundaries specified). This trick is important while finding |
2009 | * the number of subregions around a/several boundary(ies). |
2010 | */ |
2011 | param = "perturbboundaries"; |
2012 | u.b = 1; |
2013 | set_param_in_solver(server,LOGICAL_SOLVER,bool_parm,param,&u); |
2014 | |
2015 | ind = 0; |
2016 | do_perturbation_combinations(server,&(bval),bp,dv,numdvs, |
2017 | bndatzero,ind,numbndf); |
2018 | /* |
2019 | * Setting the value of the perturbation mode flag in the logical solver |
2020 | * to 0. |
2021 | */ |
2022 | u.b = 0; |
2023 | set_param_in_solver(server,LOGICAL_SOLVER,bool_parm,param,&u); |
2024 | |
2025 | destroy_array(bndatzero); |
2026 | |
2027 | dfilter.matchbits = (DIS_VAL_MODIFIED); |
2028 | dfilter.matchvalue = (DIS_VAL_MODIFIED); |
2029 | numdvf = slv_count_solvers_dvars(server,&dfilter); |
2030 | |
2031 | if (numdvf == 0) { |
2032 | FPRINTF(ASCERR,"Not really at a boundary\n"); |
2033 | for (d=0; d<numdvs; d++) { |
2034 | cur_dis = dv[d]; |
2035 | dis_set_boolean_value(cur_dis,bval.cur_val[d]); |
2036 | dis_set_value(cur_dis,bval.cur_val[d]); |
2037 | dis_set_previous_value(cur_dis,bval.pre_val[d]); |
2038 | } |
2039 | destroy_array(bval.cur_val); |
2040 | destroy_array(bval.pre_val); |
2041 | return 0; |
2042 | } |
2043 | |
2044 | dvarmodified = create_array(numdvf,int32); |
2045 | ind = 0; |
2046 | for (d=0; d<numdvs; d++) { |
2047 | cur_dis = dv[d]; |
2048 | if(dis_val_modified(cur_dis)) { |
2049 | dvarmodified[ind] = d; |
2050 | gl_append_ptr(disvars,cur_dis); |
2051 | dis_set_val_modified(cur_dis,FALSE); |
2052 | ind++; |
2053 | } |
2054 | } |
2055 | |
2056 | for (d=0; d<numdvs; d++) { |
2057 | cur_dis = dv[d]; |
2058 | dis_set_boolean_value(cur_dis,bval.cur_val[d]); |
2059 | dis_set_value(cur_dis,bval.cur_val[d]); |
2060 | dis_set_previous_value(cur_dis,bval.pre_val[d]); |
2061 | } |
2062 | |
2063 | pos_cases = 1; |
2064 | for (d = 1; d<=numdvf; d++) { |
2065 | pos_cases = pos_cases * 2; |
2066 | } |
2067 | |
2068 | cases = (struct matching_cases *) |
2069 | (ascmalloc((pos_cases)*sizeof(struct matching_cases))); |
2070 | |
2071 | #if SHOW_BOUNDARY_ANALYSIS_DETAILS |
2072 | FPRINTF(ASCERR,"Executing combinatorial search for subregions \n"); |
2073 | #endif /* SHOW_BOUNDARY_ANALYSIS_DETAILS */ |
2074 | |
2075 | d = 1; |
2076 | comb = 0; |
2077 | do_dvar_values_combinations(disvars,cases,numdvf,d,&(comb)); |
2078 | |
2079 | order_cases(cases,pos_cases); |
2080 | compare_cases(cases,pos_cases); |
2081 | |
2082 | (*n_subregions) = 0; |
2083 | for(comb=0; comb<pos_cases;comb++) { |
2084 | if(cases[comb].diff_subregion) { |
2085 | (*n_subregions)++; |
2086 | } |
2087 | } |
2088 | |
2089 | if ((*n_subregions)==0) { |
2090 | FPRINTF(ASCERR,"ERROR: at least one subregion must be found\n"); |
2091 | for (d=0; d<numdvs; d++) { |
2092 | cur_dis = dv[d]; |
2093 | dis_set_boolean_value(cur_dis,bval.cur_val[d]); |
2094 | dis_set_value(cur_dis,bval.cur_val[d]); |
2095 | dis_set_previous_value(cur_dis,bval.pre_val[d]); |
2096 | } |
2097 | destroy_array(bval.cur_val); |
2098 | destroy_array(bval.pre_val); |
2099 | for(comb=0; comb<pos_cases;comb++) { |
2100 | destroy_array(cases[comb].case_list); |
2101 | } |
2102 | destroy_array(cases); |
2103 | return 0; |
2104 | } |
2105 | |
2106 | if ((*n_subregions)==1) { |
2107 | FPRINTF(ASCERR,"Not really at a boundary\n"); |
2108 | for (d=0; d<numdvs; d++) { |
2109 | cur_dis = dv[d]; |
2110 | dis_set_boolean_value(cur_dis,bval.cur_val[d]); |
2111 | dis_set_value(cur_dis,bval.cur_val[d]); |
2112 | dis_set_previous_value(cur_dis,bval.pre_val[d]); |
2113 | } |
2114 | destroy_array(bval.cur_val); |
2115 | destroy_array(bval.pre_val); |
2116 | for(comb=0; comb<pos_cases;comb++) { |
2117 | destroy_array(cases[comb].case_list); |
2118 | } |
2119 | destroy_array(cases); |
2120 | return 0; |
2121 | } |
2122 | |
2123 | if ((*n_subregions) > 0) { |
2124 | (*subregions) = (struct matching_cases *) |
2125 | (ascmalloc(((*n_subregions))*sizeof(struct matching_cases))); |
2126 | (*n_subregions) = 0; |
2127 | for(comb=0; comb<pos_cases;comb++) { |
2128 | if(cases[comb].diff_subregion) { |
2129 | (*subregions)[(*n_subregions)].case_list = cases[comb].case_list; |
2130 | cases[comb].case_list = NULL; |
2131 | (*subregions)[(*n_subregions)].ncases = cases[comb].ncases; |
2132 | cases[comb].ncases = 0; |
2133 | (*subregions)[(*n_subregions)].diff_subregion = 1; |
2134 | (*n_subregions)++; |
2135 | } |
2136 | } |
2137 | } |
2138 | |
2139 | for(comb=0; comb<pos_cases;comb++) { |
2140 | destroy_array(cases[comb].case_list); |
2141 | } |
2142 | destroy_array(cases); |
2143 | |
2144 | |
2145 | assign_cur_sub = 0; |
2146 | /* |
2147 | * Finding the subregion corresponding to the "original" configuration |
2148 | */ |
2149 | for (d=0; d<numdvs; d++) { |
2150 | cur_dis = dv[d]; |
2151 | dis_set_boolean_value(cur_dis,bval.cur_val[d]); |
2152 | dis_set_value(cur_dis,bval.cur_val[d]); |
2153 | dis_set_previous_value(cur_dis,bval.pre_val[d]); |
2154 | } |
2155 | cur_cases = cases_matching(disvars,&cur_ncases); |
2156 | caselist = cur_cases; |
2157 | if (cur_ncases > 1) { |
2158 | newcaselist = create_array(cur_ncases,int32); |
2159 | order_case(caselist,newcaselist,cur_ncases); |
2160 | cur_cases = newcaselist; |
2161 | destroy_array(caselist); |
2162 | } else { |
2163 | if (cur_ncases == 1) { |
2164 | newcaselist = create_array(1,int32); |
2165 | newcaselist[0] = caselist[1]; |
2166 | cur_cases = newcaselist; |
2167 | destroy_array(caselist); |
2168 | } |
2169 | } |
2170 | for(comb=0; comb<(*n_subregions);comb++) { |
2171 | if ((*subregions)[comb].ncases == cur_ncases) { |
2172 | if(compare_case((*subregions)[comb].case_list,cur_cases,cur_ncases)) { |
2173 | (*cur_subregion) = comb; |
2174 | assign_cur_sub = 1; |
2175 | break; |
2176 | } |
2177 | } |
2178 | } |
2179 | |
2180 | if (!assign_cur_sub) { |
2181 | FPRINTF(ASCERR,"PANIC: original configuration not found\n"); |
2182 | } |
2183 | |
2184 | destroy_array(cur_cases); |
2185 | destroy_array(dvarmodified); |
2186 | destroy_array(bval.cur_val); |
2187 | destroy_array(bval.pre_val); |
2188 | return 1; |
2189 | } |
2190 | |
2191 | |
2192 | /* |
2193 | * If some boundary(ies) has been crossed in the iterative scheme, |
2194 | * this function finds the boundary crossed (the first one, if many). |
2195 | * It returns the factor (less than 1) by which the step length has |
2196 | * to be multiplied son that the new point will lie precisely |
2197 | * at that boundary. This factor is found by using the method of |
2198 | * bisection |
2199 | */ |
2200 | static real64 return_to_first_boundary(slv_system_t server, |
2201 | SlvClientToken asys, |
2202 | struct real_values *rvalues, |
2203 | var_filter_t *vfilter) |
2204 | { |
2205 | slv9_system_t sys; |
2206 | struct bnd_boundary **bp, *cur_bnd; |
2207 | struct var_variable **incidences, **bnd_incidences; |
2208 | struct var_variable *cur_var; |
2209 | bnd_filter_t bfilter; |
2210 | struct boolean_values bval; |
2211 | real64 factor=0.0,fup,flo,newvalue; |
2212 | int32 *bndcrossed; |
2213 | int32 *inc_vars; |
2214 | int32 count,n_incidences,inc,conv_flag,still_crossed; |
2215 | int32 numbnds,numbndf,b,ind; |
2216 | int32 iter,n_iterations; |
2217 | FILE *lif; |
2218 | |
2219 | sys = SLV9(asys); |
2220 | check_system(sys); |
2221 | lif = LIF(sys); |
2222 | |
2223 | if( sys->blist == NULL ) { |
2224 | FPRINTF(ASCERR,"ERROR: (slv9) return_to_first_boundary\n"); |
2225 | FPRINTF(ASCERR," Boundary list was never set.\n"); |
2226 | return 1.0; |
2227 | } |
2228 | |
2229 | if (!some_boundaries_crossed(server,asys)) { |
2230 | return 1.0; |
2231 | } |
2232 | |
2233 | bp = sys->blist; |
2234 | numbnds = slv_get_num_solvers_bnds(server); |
2235 | bfilter.matchbits = (BND_CROSSED); |
2236 | bfilter.matchvalue = (BND_CROSSED); |
2237 | numbndf = slv_count_solvers_bnds(server,&bfilter); |
2238 | bndcrossed = create_array(numbndf,int32); |
2239 | bval.cur_val = create_array(numbndf,int32); |
2240 | bval.pre_val = create_array(numbndf,int32); |
2241 | ind = 0; |
2242 | for (b=0; b<numbnds; b++) { |
2243 | cur_bnd = bp[b]; |
2244 | if (bnd_crossed(cur_bnd)) { |
2245 | bndcrossed[ind] = b; |
2246 | bval.cur_val[ind] = bnd_status_cur(cur_bnd); |
2247 | bval.pre_val[ind] = bnd_status_pre(cur_bnd); |
2248 | ind++; |
2249 | } |
2250 | } |
2251 | |
2252 | count = 0; |
2253 | for (b=0; b<numbndf; b++) { |
2254 | cur_bnd = bp[bndcrossed[b]]; |
2255 | n_incidences = bnd_n_real_incidences(cur_bnd); |
2256 | count = count + n_incidences; |
2257 | } |
2258 | |
2259 | incidences = (struct var_variable **) |
2260 | ( ascmalloc((count)*sizeof(struct var_variable *))); |
2261 | inc_vars = create_array(count,int32); |
2262 | count = 0; |
2263 | for (b=0; b<numbndf; b++) { |
2264 | cur_bnd = bp[bndcrossed[b]]; |
2265 | bnd_incidences = bnd_real_incidence(cur_bnd); |
2266 | n_incidences = bnd_n_real_incidences(cur_bnd); |
2267 | #if SHOW_BOUNDARY_ANALYSIS_DETAILS |
2268 | FPRINTF(lif,"boundary crossed = %d\n",bndcrossed[b]); |
2269 | FPRINTF(lif,"previous boundary status = %d\n",bval.pre_val[b]); |
2270 | FPRINTF(lif,"current boundary status = %d\n",bval.cur_val[b]); |
2271 | #endif /* SHOW_BOUNDARY_ANALYSIS_DETAILS */ |
2272 | for (inc=0; inc<n_incidences; inc++) { |
2273 | incidences[count] = bnd_incidences[inc]; |
2274 | inc_vars[count] = var_mindex(incidences[count]); |
2275 | count++; |
2276 | } |
2277 | } |
2278 | |
2279 | /* bisection to find first boundary crossed */ |
2280 | fup = 1.0; |
2281 | flo = 0.0; |
2282 | conv_flag = 0; |
2283 | iter = 0; |
2284 | |
2285 | /* |
2286 | * Maximum number of bisection iterations. This must be modified |
2287 | * so that it becomes a parameter to be defined by the user |
2288 | */ |
2289 | n_iterations = ITER_BIS_LIMIT; |
2290 | |
2291 | #if SHOW_BOUNDARY_ANALYSIS_DETAILS |
2292 | for (inc=0; inc<count; inc++) { |
2293 | cur_var = incidences[inc]; |
2294 | if(var_apply_filter(cur_var,vfilter)) { |
2295 | FPRINTF(lif,"Variable "); |
2296 | print_var_name(lif,sys,cur_var); PUTC('\n',lif); |
2297 | FPRINTF(lif, |
2298 | "previous value = %f\n",rvalues->pre_values[inc_vars[inc]]); |
2299 | FPRINTF(lif,"current value = %f\n",rvalues->cur_values[inc_vars[inc]]); |
2300 | } |
2301 | } |
2302 | #endif /* SHOW_BOUNDARY_ANALYSIS_DETAILS */ |
2303 | |
2304 | while (conv_flag == 0) { |
2305 | iter++; |
2306 | if (iter>n_iterations) { |
2307 | FPRINTF(ASCERR,"ERROR: (slv9) return_to_first_boundary\n"); |
2308 | FPRINTF(ASCERR,"Could not find the first boundary crossed \n"); |
2309 | FPRINTF(ASCERR,"Returning the last factor calculated\n"); |
2310 | break; |
2311 | } |
2312 | still_crossed = 0; |
2313 | factor = ( fup + flo ) / 2.0; |
2314 | #if SHOW_BISECTION_DETAILS |
2315 | FPRINTF(lif,"fup = %f\n",fup); |
2316 | FPRINTF(lif,"flo = %f\n",flo); |
2317 | FPRINTF(lif,"factor = %f\n",factor); |
2318 | #endif /* SHOW_BISECTION_DETAILS */ |
2319 | for (inc=0; inc<count; inc++) { |
2320 | cur_var = incidences[inc]; |
2321 | if(var_apply_filter(cur_var,vfilter)) { |
2322 | newvalue = rvalues->pre_values[inc_vars[inc]] + factor * |
2323 | ( rvalues->cur_values[inc_vars[inc]] - |
2324 | rvalues->pre_values[inc_vars[inc]] ); |
2325 | var_set_value(cur_var,newvalue); |
2326 | #if SHOW_BISECTION_DETAILS |
2327 | FPRINTF(lif,"Variable "); |
2328 | print_var_name(lif,sys,cur_var); PUTC('\n',lif); |
2329 | FPRINTF(lif,"value after factor = %f\n",newvalue); |
2330 | #endif /* SHOW_BISECTION_DETAILS */ |
2331 | } |
2332 | } |
2333 | |
2334 | update_boundaries(server,asys); |
2335 | for (b=0; b<numbndf; b++) { |
2336 | cur_bnd = bp[bndcrossed[b]]; |
2337 | #if SHOW_BISECTION_DETAILS |
2338 | FPRINTF(lif,"previous status = %d\n", bval.pre_val[b]); |
2339 | FPRINTF(lif,"status aftert factor = %d\n",bnd_status_cur(cur_bnd)); |
2340 | #endif /* SHOW_BISECTION_DETAILS */ |
2341 | if ( bnd_status_cur(cur_bnd) != bval.pre_val[b] ) { |
2342 | still_crossed = 1; |
2343 | } |
2344 | } |
2345 | #if SHOW_BISECTION_DETAILS |
2346 | FPRINTF(lif,"still_crossed = %d\n",still_crossed); |
2347 | #endif /* SHOW_BISECTION_DETAILS */ |
2348 | if (still_crossed) { |
2349 | fup = factor; |
2350 | } else { |
2351 | flo = factor; |
2352 | for (b=0; b<numbndf; b++) { |
2353 | cur_bnd = bp[bndcrossed[b]]; |
2354 | bnd_set_pre_status(cur_bnd,bval.pre_val[b]); |
2355 | bnd_set_cur_status(cur_bnd,bval.pre_val[b]); |
2356 | if (bnd_at_zero(cur_bnd)) { |
2357 | #if SHOW_BOUNDARY_ANALYSIS_DETAILS |
2358 | FPRINTF(ASCERR,"boundary at zero = %d\n",bndcrossed[b]); |
2359 | FPRINTF(lif,"factor = %f\n",factor); |
2360 | for (inc=0; inc<count; inc++) { |
2361 | cur_var = incidences[inc]; |
2362 | if(var_apply_filter(cur_var,vfilter)) { |
2363 | FPRINTF(lif,"Variable "); |
2364 | print_var_name(lif,sys,cur_var); PUTC('\n',lif); |
2365 | FPRINTF(lif,"value after factor = %f\n",var_value(cur_var)); |
2366 | } |
2367 | } |
2368 | #endif /* SHOW_BOUNDARY_ANALYSIS_DETAILS */ |
2369 | conv_flag = 1; |
2370 | } |
2371 | } |
2372 | } |
2373 | } |
2374 | destroy_array(bndcrossed); |
2375 | destroy_array(inc_vars); |
2376 | destroy_array(bval.cur_val); |
2377 | destroy_array(bval.pre_val); |
2378 | destroy_array(incidences); |
2379 | |
2380 | return factor; |
2381 | } |
2382 | |
2383 | |
2384 | /* |
2385 | * Storing values of real variables. |
2386 | * --------------------------------- |
2387 | * |
2388 | * We use the master list of variables since its order does not change |
2389 | * and it is given by the master index. We do not touch the master list, |
2390 | * we only use its order. |
2391 | */ |
2392 | |
2393 | /* |
2394 | * Store the values of the var_variables before a newton-like iteration |
2395 | */ |
2396 | static void store_real_pre_values(slv_system_t server, |
2397 | struct real_values *rvalues) |
2398 | { |
2399 | struct var_variable **master; |
2400 | struct var_variable *var; |
2401 | int v, vlen; |
2402 | |
2403 | master = slv_get_master_var_list(server); |
2404 | vlen = slv_get_num_master_vars(server); |
2405 | |
2406 | rvalues->pre_values = create_array(vlen,real64); |
2407 | |
2408 | for (v=0; v<vlen; v++) { |
2409 | var = master[v]; |
2410 | rvalues->pre_values[v] = var_value(var); |
2411 | } |
2412 | } |
2413 | |
2414 | /* |
2415 | * Store the values of the var_variables after a newton-like iteration |
2416 | */ |
2417 | static void store_real_cur_values(slv_system_t server, |
2418 | struct real_values *rvalues) |
2419 | { |
2420 | struct var_variable **master; |
2421 | struct var_variable *var; |
2422 | int v, vlen; |
2423 | |
2424 | master = slv_get_master_var_list(server); |
2425 | vlen = slv_get_num_master_vars(server); |
2426 | |
2427 | rvalues->cur_values = create_array(vlen,real64); |
2428 | |
2429 | for (v=0; v<vlen; v++) { |
2430 | var = master[v]; |
2431 | rvalues->cur_values[v] = var_value(var); |
2432 | } |
2433 | } |
2434 | |
2435 | /* |
2436 | * After the length of the step has been modified so that the current point |
2437 | * lies at a boundary, the values of all the variables is updated so that |
2438 | * they all reduce the length of their step by the same factor. |
2439 | */ |
2440 | static void update_real_var_values(slv_system_t server, |
2441 | struct real_values *rvalues, |
2442 | var_filter_t *vfilter, real64 factor) |
2443 | { |
2444 | struct var_variable **master; |
2445 | struct var_variable *var; |
2446 | real64 newvalue; |
2447 | int v, vlen; |
2448 | |
2449 | master = slv_get_master_var_list(server); |
2450 | vlen = slv_get_num_master_vars(server); |
2451 | |
2452 | for (v=0; v<vlen; v++) { |
2453 | var = master[v]; |
2454 | if(var_apply_filter(var,vfilter)) { |
2455 | newvalue = rvalues->pre_values[v] + |
2456 | factor * (rvalues->cur_values[v] - rvalues->pre_values[v]); |
2457 | var_set_value(var,newvalue); |
2458 | } |
2459 | } |
2460 | destroy_array(rvalues->cur_values); |
2461 | destroy_array(rvalues->pre_values); |
2462 | } |
2463 | |
2464 | |
2465 | /* |
2466 | * Set the flagbit NONBASIC for all the variables in the list |
2467 | * to the value passed as argument |
2468 | */ |
2469 | static void set_nonbasic_status_in_var_list(slv_system_t server, |
2470 | uint32 value) |
2471 | { |
2472 | struct var_variable **master; |
2473 | struct var_variable *var; |
2474 | int v, vlen; |
2475 | |
2476 | master = slv_get_master_var_list(server); |
2477 | vlen = slv_get_num_master_vars(server); |
2478 | |
2479 | for (v=0; v<vlen; v++) { |
2480 | var = master[v]; |
2481 | var_set_nonbasic(var,value); |
2482 | } |
2483 | } |
2484 | |
2485 | |
2486 | /* |
2487 | * After the length of the step has been modified so that the current point |
2488 | * lies at a boundary, the residuals of the equations are updated. |
2489 | */ |
2490 | static void update_relations_residuals(slv_system_t server) |
2491 | { |
2492 | struct rel_relation **master; |
2493 | struct rel_relation *rel; |
2494 | rel_filter_t rfilter; |
2495 | real64 resid; |
2496 | int32 r, rlen, status; |
2497 | |
2498 | master = slv_get_master_rel_list(server); |
2499 | rlen = slv_get_num_master_rels(server); |
2500 | |
2501 | rfilter.matchbits = (REL_INCLUDED | REL_EQUALITY); |
2502 | rfilter.matchvalue = (REL_INCLUDED | REL_EQUALITY); |
2503 | |
2504 | Asc_SignalHandlerPush(SIGFPE,SIG_IGN); |
2505 | for (r=0; r<rlen; r++) { |
2506 | rel = master[r]; |
2507 | if(rel_apply_filter(rel,&rfilter)) { |
2508 | resid = relman_eval(rel,&status,1); |
2509 | } |
2510 | } |
2511 | Asc_SignalHandlerPop(SIGFPE,SIG_IGN); |
2512 | } |
2513 | |
2514 | |
2515 | #ifdef ASC_WITH_CONOPT |
2516 | /*------------------------------------------------------------------------------ |
2517 | CALLBACK ROUTINES FOR CONOPT |
2518 | */ |
2519 | |
2520 | /* |
2521 | * COIRMS Based on the information provided in Coispz, CONOPT will |
2522 | * allocate the number of vectors into which the user can define |
2523 | * the details of the model. The details of the model are defined |
2524 | * here. |
2525 | * |
2526 | * COIRMS(lower, curr, upper, vsta, type,rhs, fv, esta, colsta, |
2527 | * rowno, value, nlflag, n, m, nz, usrmem) |
2528 | * |
2529 | * lower - lower bounds on the variables |
2530 | * curr - intial values of the variables |
2531 | * upper - upper bounds on the variables |
2532 | * vsta - initial status of the variable(o nonbasic, 1 basic) |
2533 | * type - types of equations (0 equality,1 greater,2 less) |
2534 | * rhs - values of the right hand sides |
2535 | * fv - sum of the nonlinear terms in the initial point |
2536 | * esta - initial status of the slack in the constraint (nonbasic,basic) |
2537 | * colsta- start of column pointers |
2538 | * rowno - row or equation numbers of the nonzeros |
2539 | * value - values of the jacobian elements |
2540 | * nlflag- nonlinearity flags(0 nonzero constant,1 varying) |
2541 | * n - number of variables |
2542 | * m - number of constraints |
2543 | * nz - number of jacobian elements |
2544 | * usrmem- user memory defined by conopt |
2545 | */ |
2546 | static int COI_CALL slv9_conopt_readmatrix( |
2547 | double *lower, double *curr, double *upper |
2548 | , int *vsta, int *type, double *rhs |
2549 | , int *esta, int *colsta, int *rowno |
2550 | , double *value, int *nlflag, int *n, int *m, int *nz |
2551 | , double *usrmem |
2552 | ){ |
2553 | slv9_system_t sys; |
2554 | struct var_variable *var; |
2555 | struct var_variable **varlist; |
2556 | struct opt_matrix *coeff_matrix; |
2557 | static var_filter_t vfilter; |
2558 | real64 /*obj_val,*/ deriv; |
2559 | real64 nominal, up, low, uplow; |
2560 | int32 num_var, n_subregions, c, num_eqns; |
2561 | int32 numnz, eq; |
2562 | int32 count, totvar; |
2563 | |
2564 | UNUSED_PARAMETER(vsta); |
2565 | UNUSED_PARAMETER(esta); |
2566 | |
2567 | sys = (slv9_system_t)usrmem; |
2568 | n_subregions = sys->subregions; |
2569 | coeff_matrix = sys->coeff_matrix; |
2570 | num_var = (*n) - n_subregions; |
2571 | num_eqns = num_var + 1; |
2572 | |
2573 | vfilter.matchbits = (VAR_ACTIVE_AT_BND | VAR_INCIDENT |
2574 | | VAR_SVAR | VAR_FIXED); |
2575 | vfilter.matchvalue = (VAR_ACTIVE_AT_BND | VAR_INCIDENT | VAR_SVAR); |
2576 | varlist = sys->mvlist; |
2577 | totvar = sys->mvtot; |
2578 | |
2579 | /* |
2580 | * Variables: Current Value, lower value and upper value. Note that for |
2581 | * this problem the variables are the vector of steps dx. So we "invent" |
2582 | * approximations for the bounds based on the bounds of the real |
2583 | * variables of the problem. The use of the parameter ASC_INFINITY is |
2584 | * Hack to keep CONOPT from complaining for large bounds. |
2585 | */ |
2586 | |
2587 | count = 0; |
2588 | for (c=0; c<totvar; c++) { |
2589 | var = varlist[c]; |
2590 | if (var_apply_filter(var,&vfilter)) { |
2591 | nominal = var_nominal(var); |
2592 | low = var_lower_bound(var); |
2593 | up = var_upper_bound(var); |
2594 | uplow = fabs( up - low); |
2595 | lower[count] = -uplow > -CONOPT_BOUNDLIMIT ? -uplow : -0.5*CONOPT_BOUNDLIMIT; |
2596 | upper[count] = uplow < CONOPT_BOUNDLIMIT ? uplow : 0.5*CONOPT_BOUNDLIMIT; |
2597 | curr[count] = 0.5 * nominal; |
2598 | count++; |
2599 | } |
2600 | } |
2601 | /* alphas for each subregion */ |
2602 | for (c=count; c<(*n); c++) { |
2603 | lower[c] = 0.0; |
2604 | upper[c] = 1.0; |
2605 | curr[c] = 1.0; |
2606 | } |
2607 | |
2608 | |
2609 | /* |
2610 | * vsta not in use since STATOK, ipsz[14], is zero |
2611 | */ |
2612 | |
2613 | /* |
2614 | * All the equations, but the last row (which is the objective), are |
2615 | * equalities. |
2616 | */ |
2617 | for (c = 0; c < (*m); c++) { |
2618 | type[c] = 0; |
2619 | } |
2620 | type[(*m)-1] = 3; |
2621 | |
2622 | |
2623 | /* |
2624 | * RHS. It is zero for all the equations except the summation of |
2625 | * alphas, whose RHS is one. |
2626 | */ |
2627 | for (c = 0; c < (*m); c++) { |
2628 | rhs[c] = 0; |
2629 | } |
2630 | rhs[(*m)-2] = 1.0; |
2631 | |
2632 | #ifdef DISUSED_CONOPT_PARAMETER |
2633 | /* |
2634 | * fv =0 for all linear relations. For the objective is the two |
2635 | * norm |
2636 | */ |
2637 | for (c = 0; c < (*m); c++) { |
2638 | fv[c] = 0; |
2639 | } |
2640 | obj_val = 0.0; |
2641 | for (c = 0; c<num_var; c++) { |
2642 | obj_val = obj_val + (curr[c] * curr[c]); |
2643 | } |
2644 | fv[(*m)-1] = obj_val; |
2645 | #endif |
2646 | |
2647 | /* |
2648 | * esta not used since STATOK is zero |
2649 | */ |
2650 | |
2651 | |
2652 | /* |
2653 | * For the following parameters, it is important ot see that: |
2654 | * 1) The values for the rows and nonzeros that conopt wants start |
2655 | * with 1, not with 0. |
2656 | * 2) The indeces of the arrays that we are using in the C side start |
2657 | * with 0. |
2658 | */ |
2659 | |
2660 | /* |
2661 | * colsta |
2662 | */ |
2663 | |
2664 | for (c=0; c<num_var; c++) { |
2665 | colsta[c] = 2 * c; |
2666 | } |
2667 | |
2668 | for (c=num_var; c<(*n); c++) { |
2669 | colsta[c] = 2 * num_var + num_eqns * (c - num_var); |
2670 | } |
2671 | |
2672 | colsta[*n] = *nz; /** @TODO check this */ |
2673 | |
2674 | /* |
2675 | rowno, value and nlflag can be done in same loop. The use of the |
2676 | parameter RTMAXJ is really a Hack to keep CONOPT from complaining |
2677 | about large derivatives |
2678 | */ |
2679 | |
2680 | numnz = 0; |
2681 | CONSOLE_DEBUG("NUM_VAR = %d",num_var); |
2682 | for (c=0; c<num_var; c++) { |
2683 | CONSOLE_DEBUG("C = %d",c); |
2684 | rowno[numnz] = c; |
2685 | nlflag[numnz] = 0; |
2686 | value[numnz] = -1; |
2687 | numnz++; |
2688 | CONSOLE_DEBUG("NUMNZ = %d",numnz); |
2689 | rowno[numnz] = *m - 1; |
2690 | nlflag[numnz] = 1; |
2691 | CONSOLE_DEBUG("FOUND A NONLINEAR NONZERO"); |
2692 | numnz++; |
2693 | CONSOLE_DEBUG("NUMNZ = %d",numnz); |
2694 | } |
2695 | |
2696 | for (c=num_var; c<(*n); c++) { |
2697 | numnz = 2 * num_var + num_eqns * (c - num_var); |
2698 | for(eq = 0; eq<num_eqns-1; eq++) { |
2699 | rowno[numnz] = eq; |
2700 | nlflag[numnz] = 0; |
2701 | deriv = -1.0 * (coeff_matrix->cols[c - num_var].element[eq]); |
2702 | if (deriv > RTMAXJ ) { |
2703 | deriv = 0.5 * RTMAXJ; |
2704 | } else { |
2705 | if (deriv < -RTMAXJ ) { |
2706 | deriv = -0.5*RTMAXJ; |
2707 | } |
2708 | } |
2709 | value[numnz] = deriv; |
2710 | numnz++; |
2711 | } |
2712 | rowno[numnz] = num_eqns - 1; |
2713 | nlflag[numnz] = 0; |
2714 | value[numnz] = 1.0; |
2715 | } |
2716 | |
2717 | return 0; |
2718 | } |
2719 | |
2720 | #if 0 /* not in API any more */ |
2721 | /* |
2722 | * COIFBL Defines the nonlinearities of the model by returning |
2723 | * numerical values. It works on a block of rows during each call. |
2724 | * COIFBL( x, g, otn, nto, from, to, jac, stcl, rnum, cnum, nl, strw, |
2725 | * llen, indx, mode, errcnt, n, m, n1, m1, nz, usrmem) |
2726 | * |
2727 | * x - punt of evaluation provided by conopt |
2728 | * g - vector of function values |
2729 | * otn - old to new permutation vector |
2730 | * nto - new to old permutation vector |
2731 | * from - range in permutation |
2732 | * to - range in permutation |
2733 | * jac - vector of jacobian values. |
2734 | * The following are vectors defining the jacobian structure |
2735 | * stcl - start of column pointers |
2736 | * rnum - row numbers |
2737 | * cnum - column numbers |
2738 | * nl - nonlinearity flags |
2739 | * strw - start row pointers |
2740 | * llen - count of linear jacobian elements |
2741 | * indx - pointers from the row-wise representation |
2742 | * mode - indicator of mode of evaluation |
2743 | * errcnt- number of function evaluation errors |
2744 | * n - umber of variables |
2745 | * m - number of constraints |
2746 | * n1 - n+1 |
2747 | * m1 - m+1 |
2748 | * nz - number of jacobian elements |
2749 | * usrmem- user memory defined by conopt |
2750 | */ |
2751 | static void slv9_coifbl(real64 *x, real64 *g, int32 *otn, int32 *nto, |
2752 | int32 *from, int32 *to, real64 *jac, int32 *stcl, |
2753 | int32 *rnum, int32 *cnum, int32 *nl, int32 *strw, |
2754 | int32 *llen, int32 *indx, int32 *mode, int32 *errcnt, |
2755 | int32 *n, int32 *m, int32 *n1, int32 *m1, |
2756 | int32 *nz, real64 *usrmem) |
2757 | { |
2758 | /* non defined for this solver */ |
2759 | |
2760 | /* stop gcc whining about unused parameter */ |
2761 | (void)x; (void)g; (void)otn; (void)nto; (void)from; (void)to; |
2762 | (void)jac; (void)stcl; (void)rnum; (void)cnum; (void)nl; (void)strw; |
2763 | (void)llen; (void)indx; (void)mode; (void)errcnt; (void)n; (void)m; |
2764 | (void)n1; (void)m1; (void)nz; |
2765 | (void)usrmem; |
2766 | |
2767 | return; |
2768 | } |
2769 | #endif |
2770 | |
2771 | /* |
2772 | * COIFDE Defines the nonlinearities of the model by returning |
2773 | * numerical values. It works on one row or equation at a time |
2774 | * COIFDE(x, g, jac, rowno, jcnm, mode, errcnt, newpt, n, nj, usrmem) |
2775 | * |
2776 | * x - punt of evaluation provided by conopt |
2777 | * g - function value |
2778 | * jac - jacobian values |
2779 | * rowno - number of the row for which nonlinearities will be eval |
2780 | * jcnm - list of column number fon the NL nonzeros |
2781 | * mode - indicator of mode of evaluation |
2782 | * errcnt - sum of number of func evaluation errors thus far |
2783 | * newpt - new point indicator |
2784 | * nj - number of nonlinear nonzero jacobian elements |
2785 | * n - number of variables |
2786 | * usrmem - user memory |
2787 | * |
2788 | * For the optimization problem at a boundary, this subroutine will |
2789 | * be called only of the objective function, constraint number m. |
2790 | * |
2791 | */ |
2792 | static int COI_CALL slv9_conopt_fdeval( |
2793 | double *x, double *g, double *jac |
2794 | , int *rowno, int *jcnm, int *mode, int *ignerr |
2795 | , int *errcnt, int *newpt, int *n, int *nj |
2796 | , double *usrmem |
2797 | ){ |
2798 | slv9_system_t sys; |
2799 | int32 num_vars, v; |
2800 | real64 obj, deriv; |
2801 | |
2802 | UNUSED_PARAMETER(jcnm); |
2803 | UNUSED_PARAMETER(errcnt); |
2804 | UNUSED_PARAMETER(newpt); |
2805 | UNUSED_PARAMETER(n); |
2806 | UNUSED_PARAMETER(nj); |
2807 | |
2808 | sys = (slv9_system_t)usrmem; |
2809 | num_vars = sys->con.n - sys->subregions; |
2810 | |
2811 | if (*mode == 1 || *mode == 3) { |
2812 | if (*rowno == sys->con.m - 1){ |
2813 | obj = 0.0; |
2814 | for (v=0; v<num_vars; v++) { |
2815 | obj = obj + (x[v] * x[v]); |
2816 | } |
2817 | *g = obj; |
2818 | } else { |
2819 | FPRINTF(ASCERR,"Wrong number of constraint in COIFDE"); |
2820 | return 1; |
2821 | } |
2822 | } |
2823 | |
2824 | /* |
2825 | * The use of the parameter RTMAXJ is really a Hack to keep CONOPT |
2826 | * from complaining about large derivatives. |
2827 | */ |
2828 | |
2829 | if (*mode == 2 || *mode == 3) { |
2830 | if (*rowno == sys->con.m - 1){ |
2831 | for (v=0; v<num_vars; v++) { |
2832 | deriv = 2.0 * x[v]; |
2833 | if (deriv > RTMAXJ ) { |
2834 | deriv = 0.5*RTMAXJ; |
2835 | } else { |
2836 | if (deriv < -RTMAXJ ) { |
2837 | deriv = -0.5*RTMAXJ; |
2838 | } |
2839 | } |
2840 | jac[v] = deriv; |
2841 | } |
2842 | } else { |
2843 | FPRINTF(ASCERR,"Wrong number of constraint in COIFDE"); |
2844 | return 1; |
2845 | } |
2846 | } |
2847 | |
2848 | return 0; |
2849 | } |
2850 | |
2851 | |
2852 | /* |
2853 | * COISTA Pass the solution from CONOPT to the modeler. It returns |
2854 | * completion status |
2855 | * COISTA(modsta, solsts, iter, objval, usrmem) |
2856 | * |
2857 | * modsta - model status |
2858 | * solsta - solver status |
2859 | * iter - number of iterations |
2860 | * objval - objective value |
2861 | * usrmem - user memory |
2862 | */ |
2863 | static int COI_CALL slv9_conopt_status(int *modsta, int *solsta, int *iter |
2864 | , double *objval, double *usrmem |
2865 | ){ |
2866 | slv9_system_t sys; |
2867 | |
2868 | sys = (slv9_system_t)usrmem; |
2869 | |
2870 | sys->con.modsta = *modsta; |
2871 | sys->con.solsta = *solsta; |
2872 | sys->con.iter = *iter; |
2873 | sys->con.obj = *objval; |
2874 | |
2875 | return 0; |
2876 | } |
2877 | |
2878 | |
2879 | /* |
2880 | * COIRS Pass the solution from CONOPT to the modeler. It returns |
2881 | * solution values |
2882 | * COIRS(val, xmar, xbas, xsta, yval, ymar, ybas, ysta, n, m, usrmem) |
2883 | * |
2884 | * xval - the solution values of the variables |
2885 | * xmar - corresponding marginal values |
2886 | * xbas - basis indicator for column (at bound, basic, nonbasic) |
2887 | * xsta - status of column (normal, nonoptimal, infeasible,unbounded) |
2888 | * yval - values of the left hand side in all the rows |
2889 | * ymar - corresponding marginal values |
2890 | * ybas - basis indicator for row |
2891 | * ysta - status of row |
2892 | * n - number of variables |
2893 | * m - number of constraints |
2894 | * usrmem - user memory |
2895 | */ |
2896 | static int COI_CALL slv9_conopt_solution(double *xval, double *xmar, int *xbas, int *xsta, |
2897 | double *yval, double *ymar, int *ybas, int * ysta, |
2898 | int *n, int *m, double *usrmem |
2899 | ){ |
2900 | slv9_system_t sys; |
2901 | struct opt_vector *opt_var_values; |
2902 | int32 c; |
2903 | real64 value; |
2904 | |
2905 | UNUSED_PARAMETER(xmar);UNUSED_PARAMETER(xbas);UNUSED_PARAMETER(xsta); |
2906 | UNUSED_PARAMETER(yval);UNUSED_PARAMETER(ymar);UNUSED_PARAMETER(ybas); |
2907 | UNUSED_PARAMETER(ysta);UNUSED_PARAMETER(m); |
2908 | |
2909 | sys = (slv9_system_t)usrmem; |
2910 | opt_var_values = sys->opt_var_values; |
2911 | |
2912 | for (c = 0; c < (*n); c++) { |
2913 | value = xval[c]; |
2914 | opt_var_values->element[c] = value; |
2915 | } |
2916 | |
2917 | return 0; |
2918 | } |
2919 | |
2920 | #if 0 |
2921 | /* |
2922 | * COIUSZ communicates and update of an existing model to CONOPT |
2923 | * COIUSZ(nintg, ipsz, nreal, rpsz, usrmem) |
2924 | * |
2925 | * nintg - number of positions in ipsz |
2926 | * ipsz - array describing problem size and options |
2927 | * nreal - number of positions in rpsz |
2928 | * rpsz - array of reals describing problem size and options |
2929 | * usrmem- user memory |
2930 | */ |
2931 | static void slv9_coiusz(int32 *nintg, int32 *ipsz, int32 *nreal, real64 *rpsz, |
2932 | real64 *usrmem) |
2933 | { |
2934 | /* non defined for this solver */ |
2935 | |
2936 | /* |
2937 | * stop gcc whining about unused parameter |
2938 | */ |
2939 | (void)nintg; (void)ipsz; (void)nreal; (void)rpsz; |
2940 | (void)usrmem; |
2941 | |
2942 | return; |
2943 | } |
2944 | #endif |
2945 | |
2946 | /* |
2947 | * COIOPT communicates non-default option values to CONOPT |
2948 | * COIOPT(name, rval, ival, lval, usrmem) |
2949 | * name - the name of a CONOPT CR-cell defined by the modeler |
2950 | * rval - the value to be assigned to name if the cells contains a real |
2951 | * ival - the value to be assigned to name if the cells contains an int |
2952 | * lval - the value to be assigned to name if the cells contains a log value |
2953 | * usrmem - user memory |
2954 | */ |
2955 | static int COI_CALL slv9_conopt_option( |
2956 | int *NCALL, double *rval, int *ival, int *logical |
2957 | , double *usrmem, char *name, int lenname |
2958 | ){ |
2959 | slv9_system_t sys; |
2960 | sys = (slv9_system_t)usrmem; |
2961 | |
2962 | UNUSED_PARAMETER(logical); |
2963 | |
2964 | name = memset(name,' ',8); |
2965 | while (sys->con.opt_count < slv9_PA_SIZE) { |
2966 | if (strlen(sys->p.parms[sys->con.opt_count].interface_label) == 6) { |
2967 | if (strncmp(sys->p.parms[sys->con.opt_count].interface_label, |
2968 | "R",1) == 0) { |
2969 | name = strncpy(name, sys->p.parms[sys->con.opt_count]. /* . break */ |
2970 | interface_label,6); |
2971 | *rval = sys->p.parms[sys->con.opt_count].info.r.value; |
2972 | sys->con.opt_count++; |
2973 | return 0; |
2974 | } else if (strncmp(sys->p.parms[sys->con.opt_count]. /* . break */ |
2975 | interface_label,"L",1) == 0) { |
2976 | name = strncpy(name,sys->p.parms[sys->con.opt_count]. /* . break */ |
2977 | interface_label,6); |
2978 | *ival = sys->p.parms[sys->con.opt_count].info.i.value; |
2979 | sys->con.opt_count++; |
2980 | return 0; |
2981 | } |
2982 | } |
2983 | sys->con.opt_count++; |
2984 | } |
2985 | |
2986 | /* sending blank to quit iterative calling */ |
2987 | name = memset(name,' ',8); |
2988 | return 0; |
2989 | } |
2990 | |
2991 | |
2992 | #if 0 /* not in API any more */ |
2993 | /* |
2994 | * COIPSZ communicates the model size and structure to CONOPT |
2995 | * COIPSZ(nintgr, ipsz, nreal, rpsz, usrmem) |
2996 | * |
2997 | * ningtr - number of positions in ipsz |
2998 | * ipsz - array describing problem size and options |
2999 | * nreal - number of positions in rpsz |
3000 | * rpsz - array of reals describing problem size and options |
3001 | * usrmem - user memory |
3002 | */ |
3003 | static void slv9_coipsz(int32 *nintg, int32 *ipsz, int32 *nreal, real64 *rpsz, |
3004 | real64 *usrmem) |
3005 | { |
3006 | slv9_system_t sys; |
3007 | |
3008 | /* |
3009 | * stop gcc whining about unused parameter |
3010 | */ |
3011 | (void)nintg; (void)nreal; |
3012 | |
3013 | sys = (slv9_system_t)usrmem; |
3014 | /* |
3015 | * Integer array |
3016 | */ |
3017 | ipsz[F2C(1)] = sys->con.n; /* variables */ |
3018 | ipsz[F2C(2)] = sys->con.m; /* constraints including objective */ |
3019 | ipsz[F2C(3)] = sys->con.nz; /* non zeros in Jacobian */ |
3020 | ipsz[F2C(4)] = sys->con.nz - (sys->con.m - 2); /* linear nonzeros */ |
3021 | ipsz[F2C(5)] = sys->con.m - 2; /* nonlinear nonzeros */ |
3022 | ipsz[F2C(6)] = -1; /* direction of optimization min */ |
3023 | ipsz[F2C(7)] = sys->con.m; /* objective will be last row */ |
3024 | ipsz[F2C(8)] = OPT_ITER_LIMIT; /* iteration limit */ |
3025 | ipsz[F2C(9)] = DOMLIM; /* max number of error in func evals */ |
3026 | ipsz[F2C(10)] = 0; /* output to file */ |
3027 | ipsz[F2C(11)] = 1; /* progress info to screen */ |
3028 | ipsz[F2C(12)] = 1; /* correct value of func in coirms */ |
3029 | ipsz[F2C(13)] = 0; /* not correct value of jacs in coirms */ |
3030 | ipsz[F2C(14)] = 0; /* status not known by modeler */ |
3031 | ipsz[F2C(15)] = 0; /* function value include only NL terms */ |
3032 | ipsz[F2C(16)] = 1; /* Objective is a constraint */ |
3033 | ipsz[F2C(17)] = 0; /* sorted order for jacobian */ |
3034 | ipsz[F2C(18)] = 0; /* append the log file after restarts */ |
3035 | ipsz[F2C(19)] = 0; /* one subroutine call to coirms */ |
3036 | ipsz[F2C(20)] = 0; /* eval subroutine is coifde */ |
3037 | ipsz[F2C(21)] = 0; /* no debugging of derivatives */ |
3038 | ipsz[F2C(22)] = 0; /* coifde not called for linear eqns */ |
3039 | /* |
3040 | * skipping remainder of ipsz which are fortran io parameters |
3041 | */ |
3042 | |
3043 | /* |
3044 | * Real array |
3045 | */ |
3046 | rpsz[F2C(1)] = ASC_INFINITY; /* infinity */ |
3047 | rpsz[F2C(2)] = -ASC_INFINITY; /* -infinity */ |
3048 | rpsz[F2C(3)] = UNDEFINED; /* undefined */ |
3049 | rpsz[F2C(6)] = 0; /* work space allocated by conopt */ |
3050 | rpsz[F2C(7)] = TIME_LIMIT; /* resource limit (time) */ |
3051 | rpsz[F2C(8)] = 1; /* initial value for vars if none given */ |
3052 | |
3053 | |
3054 | } |
3055 | #endif |
3056 | |
3057 | |
3058 | /** |
3059 | slv_conopt iterate calls conopt start, which calls coicsm |
3060 | to starts CONOPT. The use of conopt_start is a hack to avoid |
3061 | unresolved external during the linking of the CONOPT library. |
3062 | |
3063 | @see conopt.h |
3064 | */ |
3065 | static void slv_conopt_iterate(slv9_system_t sys){ |
3066 | int n; |
3067 | |
3068 | if(sys->con.cntvect == NULL){ |
3069 | sys->con.cntvect = ASC_NEW_ARRAY(int,COIDEF_Size()); |
3070 | } |
3071 | |
3072 | COIDEF_Ini(sys->con.cntvect); |
3073 | |
3074 | /* |
3075 | We pass pointer to sys as usrmem data. |
3076 | Cast back to slv9_system_t to access the information required |
3077 | */ |
3078 | COIDEF_UsrMem(sys->con.cntvect,(double *)sys); |
3079 | |
3080 | COIDEF_NumVar(sys->con.cntvect, &(sys->con.n)); |
3081 | COIDEF_NumCon(sys->con.cntvect, &(sys->con.m)); /* include the obj fn */ |
3082 | COIDEF_NumNZ(sys->con.cntvect, &(sys->con.nz)); |
3083 | COIDEF_NumNlNz(sys->con.cntvect, &(sys->con.nlnz)); |
3084 | COIDEF_OptDir(sys->con.cntvect, &(sys->con.optdir)); |
3085 | |
3086 | COIDEF_ObjCon(sys->con.cntvect, &(sys->con.objcon)); /* objective will be last row */ |
3087 | COIDEF_Base(sys->con.cntvect, &(sys->con.base)); |
3088 | COIDEF_ErrLim(sys->con.cntvect, &(DOMLIM)); |
3089 | COIDEF_ItLim(sys->con.cntvect, &(OPT_ITER_LIMIT)); |
3090 | |
3091 | COIDEF_ReadMatrix(sys->con.cntvect, &slv9_conopt_readmatrix); |
3092 | COIDEF_FDEval(sys->con.cntvect, &slv9_conopt_fdeval); |
3093 | COIDEF_Option(sys->con.cntvect, &slv9_conopt_option); |
3094 | COIDEF_Solution(sys->con.cntvect, &slv9_conopt_solution); |
3095 | COIDEF_Status(sys->con.cntvect, &slv9_conopt_status); |
3096 | COIDEF_Message(sys->con.cntvect, &asc_conopt_message); |
3097 | COIDEF_ErrMsg(sys->con.cntvect, &asc_conopt_errmsg); |
3098 | COIDEF_Progress(sys->con.cntvect, &asc_conopt_progress); |
3099 | |
3100 | /** @TODO implement the following options as well... */ |
3101 | #if 0 |
3102 | ipsz[F2C(10)] = 0; /* output to file */ |
3103 | ipsz[F2C(11)] = 1; /* progress info to screen */ |
3104 | ipsz[F2C(12)] = 1; /* correct value of func in coirms */ |
3105 | ipsz[F2C(13)] = 0; /* not correct value of jacs in coirms */ |
3106 | ipsz[F2C(14)] = 0; /* status not known by modeler */ |
3107 | ipsz[F2C(15)] = 0; /* function value include only NL terms */ |
3108 | ipsz[F2C(16)] = 1; /* Objective is a constraint */ |
3109 | ipsz[F2C(17)] = 0; /* sorted order for jacobian */ |
3110 | ipsz[F2C(18)] = 0; /* append the log file after restarts */ |
3111 | ipsz[F2C(19)] = 0; /* one subroutine call to coirms */ |
3112 | ipsz[F2C(20)] = 0; /* eval subroutine is coifde */ |
3113 | ipsz[F2C(21)] = 0; /* no debugging of derivatives */ |
3114 | ipsz[F2C(22)] = 0; /* coifde not called for linear eqns */ |
3115 | /* |
3116 | * skipping remainder of ipsz which are fortran io parameters |
3117 | */ |
3118 | |
3119 | /* |
3120 | * Real array |
3121 | */ |
3122 | rpsz[F2C(1)] = ASC_INFINITY; /* infinity */ |
3123 | rpsz[F2C(2)] = -ASC_INFINITY; /* -infinity */ |
3124 | rpsz[F2C(3)] = UNDEFINED; /* undefined */ |
3125 | rpsz[F2C(6)] = 0; /* work space allocated by conopt */ |
3126 | rpsz[F2C(7)] = TIME_LIMIT; /* resource limit (time) */ |
3127 | rpsz[F2C(8)] = 1; /* initial value for vars if none given */ |
3128 | #endif |
3129 | |
3130 | /* |
3131 | * reset count on coiopt calls |
3132 | */ |
3133 | sys->con.opt_count = 0; |
3134 | |
3135 | /* |
3136 | * do not keep model in memory after solution |
3137 | */ |
3138 | sys->con.kept = 0; |
3139 | |
3140 | COI_Solve(sys->con.cntvect); |
3141 | /* conopt_start(&(sys->con.kept), usrmem, &(sys->con.lwork), |
3142 | sys->con.work, &(sys->con.maxusd), &(sys->con.curusd)); */ |
3143 | |
3144 | /* |
3145 | * We assume that we get convergence in optimization problem at |
3146 | * boundary |
3147 | */ |
3148 | sys->con.optimized = 1; |
3149 | } |
3150 | |
3151 | #endif /* ASC_WITH_CONOPT */ |
3152 | |
3153 | /*-------------------end of conopt callbacks----------------------------------*/ |
3154 | |
3155 | |
3156 | /* |
3157 | * Creates an array of columns (containing an array of real elements |
3158 | * each) to storage the linear coefficient matrix of the optimization problem. |
3159 | * It also creates the arrays of reals required to storage the values |
3160 | * of the gradients of a subregion, which change depending on whether the |
3161 | * problem is a simulation or an optimization. |
3162 | */ |
3163 | static void create_opt_matrix_and_vectors(int32 num_opt_eqns, |
3164 | int32 n_subregions, |
3165 | struct opt_matrix *coeff_matrix, |
3166 | struct opt_vector *opt_var_values, |
3167 | struct opt_vector *invariant, |
3168 | struct opt_vector *variant, |
3169 | struct opt_vector *gradient, |
3170 | struct opt_matrix *multipliers) |
3171 | { |
3172 | int32 c; |
3173 | int32 num_vars; |
3174 | |
3175 | num_vars = num_opt_eqns - 1 + n_subregions; |
3176 | |
3177 | coeff_matrix->cols = (struct opt_vector *) |
3178 | (ascmalloc(n_subregions*sizeof(struct opt_vector))); |
3179 | |
3180 | if (g_optimizing) { |
3181 | multipliers->cols = (struct opt_vector *) |
3182 | (ascmalloc(n_subregions*sizeof(struct opt_vector))); |
3183 | } |
3184 | |
3185 | for (c=0; c<n_subregions; c++) { |
3186 | coeff_matrix->cols[c].element = |
3187 | (real64 *)(ascmalloc(num_opt_eqns*sizeof(real64))); |
3188 | } |
3189 | opt_var_values->element = (real64 *)(ascmalloc(num_vars*sizeof(real64))); |
3190 | |
3191 | if (g_optimizing) { |
3192 | gradient->element = (real64 *)(ascmalloc(num_opt_eqns*sizeof(real64))); |
3193 | } else { |
3194 | invariant->element = (real64 *)(ascmalloc(num_opt_eqns*sizeof(real64))); |
3195 | variant->element = (real64 *)(ascmalloc(num_opt_eqns*sizeof(real64))); |
3196 | } |
3197 | } |
3198 | |
3199 | |
3200 | /* |
3201 | * destroy the arrays created to storage the gradients for the optimization |
3202 | * problem |
3203 | */ |
3204 | static void destroy_opt_matrix_and_vectors(int32 n_subregions, |
3205 | struct opt_matrix *coeff_matrix, |
3206 | struct opt_vector *opt_var_values, |
3207 | struct opt_vector *invariant, |
3208 | struct opt_vector *variant, |
3209 | struct opt_vector *gradient, |
3210 | struct opt_matrix *multipliers) |
3211 | { |
3212 | int32 c; |
3213 | for (c=0; c<n_subregions; c++) { |
3214 | destroy_array(coeff_matrix->cols[c].element); |
3215 | if (g_optimizing) { |
3216 | destroy_array(multipliers->cols[c].element); |
3217 | } |
3218 | } |
3219 | destroy_array(coeff_matrix->cols); |
3220 | destroy_array(opt_var_values->element); |
3221 | if (g_optimizing) { |
3222 | destroy_array(multipliers->cols); |
3223 | destroy_array(gradient->element); |
3224 | } else { |
3225 | destroy_array(invariant->element); |
3226 | destroy_array(variant->element); |
3227 | } |
3228 | } |
3229 | |
3230 | |
3231 | |
3232 | /* |
3233 | * Set Factorization Options |
3234 | */ |
3235 | static void set_factor_options (linsolqr_system_t lsys) |
3236 | { |
3237 | linsolqr_prep(lsys,linsolqr_fmethod_to_fclass(ranki_ba2)); |
3238 | linsolqr_set_pivot_zero(lsys, 1e-12); |
3239 | linsolqr_set_drop_tolerance(lsys,1e-16); |
3240 | linsolqr_set_pivot_tolerance(lsys, 0.1); |
3241 | linsolqr_set_condition_tolerance(lsys, 0.1); |
3242 | } |
3243 | |
3244 | |
3245 | /* |
3246 | * Calculating the Lagrange Multipliers for each subregion |
3247 | * |
3248 | * We are assuming here that the matrix is structurally nonsingular |
3249 | * and than the rank is equal to the number of rows in the matrix. |
3250 | * Much more efficient checking must be done. |
3251 | */ |
3252 | static void get_multipliers(SlvClientToken asys, |
3253 | int32 subregion, |
3254 | int32 nrel, |
3255 | real64 *grad_obj, |
3256 | struct opt_matrix *multipliers) |
3257 | { |
3258 | slv9_system_t sys; |
3259 | linsolqr_system_t lsys; |
3260 | mtx_region_t *newblocks, *oneblock; |
3261 | int32 rank; |
3262 | int32 c, cr, len, row; |
3263 | real64 *weights; |
3264 | real64 summ; |
3265 | |
3266 | sys = SLV9(asys); |
3267 | check_system(sys); |
3268 | |
3269 | mtx_output_assign(sys->lin_mtx,nrel,nrel); |
3270 | rank = mtx_symbolic_rank(sys->lin_mtx); |
3271 | mtx_partition(sys->lin_mtx); |
3272 | len = mtx_number_of_blocks(sys->lin_mtx); |
3273 | newblocks = ASC_NEW_ARRAY(mtx_region_t,len); |
3274 | if (newblocks == NULL) { |
3275 | mtx_destroy(sys->lin_mtx); |
3276 | return; |
3277 | } |
3278 | for (c = 0 ; c < len; c++) { |
3279 | mtx_block(sys->lin_mtx,c,&(newblocks[c])); |
3280 | } |
3281 | for (c = 0 ; c < len; c++) { |
3282 | mtx_reorder(sys->lin_mtx,&(newblocks[c]),mtx_SPK1); |
3283 | } |
3284 | |
3285 | /* unifying block */ |
3286 | oneblock = (mtx_region_t *)ascmalloc(sizeof(mtx_region_t)); |
3287 | oneblock->row.low = oneblock->col.low = 0; |
3288 | oneblock->row.high = nrel-1; |
3289 | oneblock->col.high = nrel-1; |
3290 | |
3291 | /* |
3292 | * Scaling of the linear system |
3293 | */ |
3294 | |
3295 | /* |
3296 | *Calculating weights |
3297 | */ |
3298 | weights = ASC_NEW_ARRAY(real64,nrel); |
3299 | for (row=0; row<nrel; row++) { |
3300 | summ = mtx_sum_sqrs_in_row(sys->lin_mtx,row,&(oneblock->col)); |
3301 | if (summ <= 0.0) { |
3302 | weights[row] = 1.0; |
3303 | } else { |
3304 | weights[row] = 1.0 / sqrt(summ); |
3305 | } |
3306 | #if DEBUG |
3307 | FPRINTF(ASCERR," weight of row %d = %f \n",row,summ); |
3308 | #endif /* DEBUG */ |
3309 | } |
3310 | |
3311 | /* |
3312 | * Dividing rows by weights |
3313 | */ |
3314 | for (row=0; row<nrel; row++) { |
3315 | mtx_mult_row(sys->lin_mtx,row,weights[row],&(oneblock->col)); |
3316 | } |
3317 | |
3318 | /* |
3319 | * dividing rhs |
3320 | */ |
3321 | for (row=0; row<nrel; row++) { |
3322 | grad_obj[mtx_row_to_org(sys->lin_mtx,row)] = |
3323 | grad_obj[mtx_row_to_org(sys->lin_mtx,row)] * weights[row]; |
3324 | } |
3325 | |
3326 | /* |
3327 | * End of scaling |
3328 | */ |
3329 | |
3330 | lsys = linsolqr_create(); |
3331 | linsolqr_set_matrix(lsys,sys->lin_mtx); |
3332 | |
3333 | for (cr=0; cr<nrel; cr++) { |
3334 | multipliers->cols[subregion].element[cr] = 0.0; |
3335 | } |
3336 | |
3337 | set_factor_options(lsys); |
3338 | /* rhs for multipliers */ |
3339 | linsolqr_add_rhs(lsys,grad_obj,FALSE); |
3340 | linsolqr_set_region(lsys,*oneblock); |
3341 | linsolqr_factor(lsys,ranki_ba2); |
3342 | linsolqr_solve(lsys,grad_obj); |
3343 | for (cr=0; cr<nrel; cr++) { |
3344 | multipliers->cols[subregion].element[cr] = linsolqr_var_value |
3345 | (lsys,grad_obj,cr); |
3346 | #if SHOW_LAGRANGE_DETAILS |
3347 | FPRINTF(ASCERR, " Row = %d \n",cr); |
3348 | FPRINTF(ASCERR, |
3349 | "Multiplier = %f \n",multipliers->cols[subregion].element[cr]); |
3350 | #endif /* SHOW_LAGRANGE_DETAILS */ |
3351 | } |
3352 | linsolqr_set_matrix(lsys,NULL); |
3353 | mtx_destroy(sys->lin_mtx); |
3354 | linsolqr_destroy(lsys); |
3355 | destroy_array(newblocks); |
3356 | destroy_array(weights); |
3357 | ascfree(oneblock); |
3358 | } |
3359 | |
3360 | |
3361 | /* |
3362 | * Calculate the invariant part of the gradients of the subregions |
3363 | */ |
3364 | static void get_gradient_in_subregion(slv_system_t server, |
3365 | SlvClientToken asys, |
3366 | int32 subregion, |
3367 | int32 num_opt_eqns, |
3368 | struct opt_vector *gradient, |
3369 | struct opt_matrix *multipliers) |
3370 | { |
3371 | slv9_system_t sys; |
3372 | struct rel_relation **rlist; |
3373 | struct var_variable **vlist; |
3374 | struct rel_relation *rel; |
3375 | struct var_variable *var; |
3376 | var_filter_t vfilter; |
3377 | rel_filter_t rfilter; |
3378 | mtx_coord_t coord; |
3379 | real64 *tmp_value; |
3380 | real64 *derivatives, resid; |
3381 | real64 *grad_obj, *func_val; |
3382 | real64 *f_red_grad; |
3383 | struct opt_matrix rel_red_grad; |
3384 | int32 *variables_master, *variables_solver, count; |
3385 | int32 nvar, nrel, ntotvar, ntotrel; |
3386 | int32 countrel,countvar,cr,cv,len,vind; |
3387 | int32 nvnb, countnbv; |
3388 | FILE *lif; |
3389 | |
3390 | sys = SLV9(asys); |
3391 | check_system(sys); |
3392 | lif = LIF(sys); |
3393 | |
3394 | rlist = slv_get_master_rel_list(server); |
3395 | vlist = slv_get_master_var_list(server); |
3396 | ntotvar = slv_get_num_master_vars(server); |
3397 | ntotrel = slv_get_num_master_rels(server); |
3398 | tmp_value = ASC_NEW_ARRAY(real64,ntotvar); |
3399 | |
3400 | vfilter.matchbits = (VAR_ACTIVE | VAR_INCIDENT | VAR_NONBASIC |
3401 | | VAR_SVAR | VAR_FIXED); |
3402 | vfilter.matchvalue = (VAR_ACTIVE | VAR_INCIDENT | VAR_SVAR); |
3403 | nvar = slv_count_master_vars(server,&vfilter); |
3404 | |
3405 | rfilter.matchbits = (REL_INCLUDED | REL_EQUALITY | REL_ACTIVE ); |
3406 | rfilter.matchvalue =(REL_INCLUDED | REL_EQUALITY | REL_ACTIVE ); |
3407 | nrel = slv_count_master_rels(server,&rfilter); |
3408 | |
3409 | if (nrel != nvar) { |
3410 | FPRINTF(ASCERR," nrel = %d\n",nrel); |
3411 | FPRINTF(ASCERR," nvar = %d\n",nvar); |
3412 | FPRINTF(ASCERR, |
3413 | "PANIC: number relations does not match number of variables\n"); |
3414 | } |
3415 | |
3416 | /* |
3417 | * residual of the relations in the subregion |
3418 | */ |
3419 | func_val = ASC_NEW_ARRAY(real64,nrel); |
3420 | |
3421 | /* |
3422 | * Lagrange Multipliers of the subregion |
3423 | */ |
3424 | multipliers->cols[subregion].element = |
3425 | (real64 *)(ascmalloc(nrel*sizeof(real64))); |
3426 | /* |
3427 | * Gradients of the objective function |
3428 | */ |
3429 | grad_obj = ASC_NEW_ARRAY(real64,nvar); |
3430 | |
3431 | /* |
3432 | * Matrix for solving linear system |
3433 | */ |
3434 | sys->lin_mtx = mtx_create(); |
3435 | mtx_set_order(sys->lin_mtx,nrel); |
3436 | |
3437 | /* |
3438 | * Counting nonbasic variables |
3439 | */ |
3440 | vfilter.matchbits = (VAR_ACTIVE | VAR_INCIDENT | VAR_NONBASIC |
3441 | | VAR_SVAR | VAR_FIXED); |
3442 | vfilter.matchvalue = (VAR_ACTIVE | VAR_INCIDENT | VAR_NONBASIC |
3443 | | VAR_SVAR); |
3444 | nvnb = slv_count_master_vars(server,&vfilter); |
3445 | |
3446 | /* |
3447 | * Information for reduced gradient |
3448 | */ |
3449 | f_red_grad = ASC_NEW_ARRAY(real64,nvnb); |
3450 | rel_red_grad.cols = (struct opt_vector *) |
3451 | (ascmalloc(nvnb*sizeof(struct opt_vector))); |
3452 | for (cv=0; cv<nvnb; cv++) { |
3453 | rel_red_grad.cols[cv].element = |
3454 | (real64 *)(ascmalloc(nrel*sizeof(real64))); |
3455 | } |
3456 | |
3457 | /* |
3458 | * Setting every sindex to -1 |
3459 | */ |
3460 | for (cv=0; cv<ntotvar; cv++) { |
3461 | var_set_sindex(vlist[cv],-1); |
3462 | } |
3463 | for (cr=0; cr<ntotrel; cr++) { |
3464 | rel_set_sindex(rlist[cr],-1); |
3465 | } |
3466 | |
3467 | /* |
3468 | * Initializing values |
3469 | */ |
3470 | for (cv=0; cv<ntotvar;cv++) { |
3471 | tmp_value[cv] = 0.0; |
3472 | } |
3473 | for (cv=0; cv<num_opt_eqns;cv++) { |
3474 | gradient->element[cv] = 0.0; |
3475 | } |
3476 | |
3477 | for (cr=0; cr<nrel; cr++) { |
3478 | func_val[cr] = 0.0; |
3479 | multipliers->cols[subregion].element[cr] = 0.0; |
3480 | } |
3481 | |
3482 | for (cv=0; cv<nvnb; cv++) { |
3483 | f_red_grad[cv] = 0.0; |
3484 | for (cr=0; cr<nrel; cr++) { |
3485 | rel_red_grad.cols[cv].element[cr] = 0.0; |
3486 | } |
3487 | } |
3488 | |
3489 | for (cv=0; cv<nvar; cv++) { |
3490 | grad_obj[cv] = 0.0; |
3491 | } |
3492 | |
3493 | /* |
3494 | * Calculate Values |
3495 | */ |
3496 | vfilter.matchbits = (VAR_ACTIVE_AT_BND | VAR_INCIDENT |
3497 | | VAR_SVAR | VAR_FIXED); |
3498 | vfilter.matchvalue = (VAR_ACTIVE_AT_BND | VAR_INCIDENT | VAR_SVAR); |
3499 | |
3500 | /* |
3501 | * List of relations |
3502 | */ |
3503 | countrel = 0; |
3504 | countvar = 0; |
3505 | countnbv = 0; |
3506 | for (cr=0; cr<ntotrel; cr++) { |
3507 | rel = rlist[cr]; |
3508 | if (rel_apply_filter(rel,&rfilter)) { |
3509 | rel_set_sindex(rel,countrel); |
3510 | coord.col = rel_sindex(rel); |
3511 | len = rel_n_incidences(rel); |
3512 | variables_master = ASC_NEW_ARRAY(int32,len); |
3513 | variables_solver = ASC_NEW_ARRAY(int32,len); |
3514 | derivatives = ASC_NEW_ARRAY(real64,len); |
3515 | relman_diff_grad(rel,&vfilter,derivatives,variables_master, |
3516 | variables_solver,&count,&resid,1); |
3517 | func_val[countrel] = resid; |
3518 | #if SHOW_LAGRANGE_DETAILS |
3519 | FPRINTF(ASCERR,"Equation = %d \n",coord.col); |
3520 | FPRINTF(ASCERR,"Residual = %f \n",resid); |
3521 | #endif /* SHOW_LAGRANGE_DETAILS */ |
3522 | for (cv=0; cv<count;cv++) { |
3523 | var = vlist[variables_master[cv]]; |
3524 | if (!var_nonbasic(var)) { |
3525 | tmp_value[variables_master[cv]] = tmp_value[variables_master[cv]] + |
3526 | derivatives[cv] * RHO * resid; |
3527 | if(var_active(var)) { |
3528 | coord.row = var_sindex(var); |
3529 | if (coord.row == -1) { |
3530 | var_set_sindex(var,countvar); |
3531 | coord.row = countvar; |
3532 | countvar++; |
3533 | } |
3534 | assert(coord.col >= 0 && coord.col < mtx_order(sys->lin_mtx)); |
3535 | #if SHOW_LAGRANGE_DETAILS |
3536 | FPRINTF(ASCERR,"Coordinate row = %d \n",coord.row); |
3537 | FPRINTF(ASCERR,"Coordinate col = %d \n",coord.col); |
3538 | FPRINTF(ASCERR,"Derivative = %f \n",derivatives[cv]); |
3539 | #endif /* SHOW_LAGRANGE_DETAILS */ |
3540 | mtx_fill_org_value(sys->lin_mtx,&coord,derivatives[cv]); |
3541 | } |
3542 | } else { |
3543 | if (var_sindex(var)== -1) { |
3544 | var_set_sindex(var,countnbv); |
3545 | countnbv++; |
3546 | } |
3547 | rel_red_grad.cols[var_sindex(var)].element[countrel] = |
3548 | derivatives[cv]; |
3549 | #if SHOW_LAGRANGE_DETAILS |
3550 | FPRINTF(lif,"Nonbasic Variable "); |
3551 | print_var_name(lif,sys,var); PUTC('\n',lif); |
3552 | FPRINTF(ASCERR,"Derivative = %f \n",derivatives[cv]); |
3553 | #endif /* SHOW_LAGRANGE_DETAILS */ |
3554 | } |
3555 | } |
3556 | destroy_array(variables_master); |
3557 | destroy_array(variables_solver); |
3558 | destroy_array(derivatives); |
3559 | countrel++; |
3560 | } |
3561 | } |
3562 | |
3563 | /* |
3564 | * Objective function |
3565 | */ |
3566 | rel = sys->obj; |
3567 | len = rel_n_incidences(rel); |
3568 | variables_master = ASC_NEW_ARRAY(int32,len); |
3569 | variables_solver = ASC_NEW_ARRAY(int32,len); |
3570 | derivatives = ASC_NEW_ARRAY(real64,len); |
3571 | relman_diff_grad(rel,&vfilter,derivatives,variables_master, |
3572 | variables_solver,&count,&resid,1); |
3573 | for (cv=0; cv<count;cv++) { |
3574 | var = vlist[variables_master[cv]]; |
3575 | if (!var_nonbasic(var)) { |
3576 | #if SHOW_LAGRANGE_DETAILS |
3577 | FPRINTF(ASCERR,"Objective row = %d \n",var_sindex(var)); |
3578 | FPRINTF(ASCERR,"Derivative = %f \n",derivatives[cv]); |
3579 | #endif /* SHOW_LAGRANGE_DETAILS */ |
3580 | grad_obj[var_sindex(var)] = -1.0 * derivatives[cv]; |
3581 | } else { |
3582 | #if SHOW_LAGRANGE_DETAILS |
3583 | FPRINTF(ASCERR,"Non Basic Variable = %d \n",var_sindex(var)); |
3584 | FPRINTF(ASCERR,"Derivative in Objective = %f \n",derivatives[cv]); |
3585 | #endif /* SHOW_LAGRANGE_DETAILS */ |
3586 | f_red_grad[var_sindex(var)] = derivatives[cv] ; |
3587 | } |
3588 | } |
3589 | destroy_array(variables_master); |
3590 | destroy_array(variables_solver); |
3591 | destroy_array(derivatives); |
3592 | |
3593 | /* |
3594 | * Solving Linear System |
3595 | */ |
3596 | get_multipliers(asys,subregion,nrel,grad_obj,multipliers); |
3597 | |
3598 | countvar = 0; |
3599 | for (cv = 0; cv<ntotvar; cv++) { |
3600 |