1 |
/* |
2 |
* SlvDOF: ASCEND Degrees of freedom manager |
3 |
* by Benjamin Andrew Allan and Vicente Rico-Ramirez |
4 |
* Created: 7/11/94 |
5 |
* Version: $Revision: 1.24 $ |
6 |
* Version control file: $RCSfile: slvDOF.c,v $ |
7 |
* Date last modified: $Date: 1998/04/09 21:56:09 $ |
8 |
* Last modified by: $Author: rv2a $ |
9 |
* |
10 |
* This file is part of the SLV solver. |
11 |
* |
12 |
* Copyright (C) 1996 Benjamin Andrew Allan |
13 |
* |
14 |
* The SLV solver is free software; you can redistribute |
15 |
* it and/or modify it under the terms of the GNU General Public License as |
16 |
* published by the Free Software Foundation; either version 2 of the |
17 |
* License, or (at your option) any later version. |
18 |
* |
19 |
* The SLV solver is distributed in hope that it will be |
20 |
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
22 |
* General Public License for more details. |
23 |
* |
24 |
* You should have received a copy of the GNU General Public License |
25 |
* along with the program; if not, write to the Free Software Foundation, |
26 |
* Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check the file named |
27 |
* COPYING. COPYING is found in ../compiler. |
28 |
* |
29 |
*/ |
30 |
|
31 |
#include <stdarg.h> |
32 |
#include "utilities/ascConfig.h" |
33 |
#include "utilities/ascSignal.h" |
34 |
#include "compiler/compiler.h" |
35 |
#include "utilities/ascMalloc.h" |
36 |
#include "utilities/ascPanic.h" |
37 |
#include "general/list.h" |
38 |
#include "utilities/mem.h" |
39 |
#include "solver/mtx.h" |
40 |
#include "solver/slv_types.h" |
41 |
#include "solver/var.h" |
42 |
#include "solver/rel.h" |
43 |
#include "solver/discrete.h" |
44 |
#include "solver/conditional.h" |
45 |
#include "solver/logrel.h" |
46 |
#include "solver/bnd.h" |
47 |
#include "solver/relman.h" |
48 |
#include "solver/cond_config.h" |
49 |
#include "solver/slv_common.h" |
50 |
#include "solver/linsol.h" |
51 |
#include "solver/linsolqr.h" |
52 |
#include "solver/slv_client.h" |
53 |
#include "solver/slv_stdcalls.h" |
54 |
#include "solver/slvDOF.h" |
55 |
|
56 |
|
57 |
#define SLVDOF(s) ((slvDOF_system_t)(s)) |
58 |
|
59 |
#define DEBUG FALSE |
60 |
#define DEBUG_CONSISTENCY_ANALYSIS FALSE |
61 |
#define ELDEBUG 0 /* print debug statements in eligible code */ |
62 |
#define KILL 0 |
63 |
struct jacobian_data { |
64 |
mtx_matrix_t mtx; /* Transpose gradient of residuals */ |
65 |
mtx_region_t reg; /* Current block region */ |
66 |
}; |
67 |
|
68 |
typedef struct slvDOF_system_structure *slvDOF_system_t; |
69 |
|
70 |
struct slvDOF_system_structure { |
71 |
|
72 |
/** |
73 |
*** Problem definition |
74 |
**/ |
75 |
slv_system_t slv; /* slv_system_t back-link */ |
76 |
struct var_variable **vlist; /* Variable list (NULL terminated) */ |
77 |
struct rel_relation **rlist; /* Relation list (NULL terminated) */ |
78 |
|
79 |
/** |
80 |
*** Solver information |
81 |
**/ |
82 |
unsigned char *rows; /* marks on rows */ |
83 |
unsigned char *cols; /* marks on cols */ |
84 |
int32 *rowlist; /* list of newly marked rows */ |
85 |
int32 *collist; /* list of newly marked cols */ |
86 |
int integrity; /* ? Has the system been created */ |
87 |
slv_parameters_t p; /* Parameters */ |
88 |
slv_status_t s; /* Status (as of iteration end) */ |
89 |
int32 cap; /* Order of matrix/vectors */ |
90 |
int32 rank; /* Symbolic rank of problem */ |
91 |
int32 vused; /* Free and incident variables */ |
92 |
int32 vtotal; /* all variables */ |
93 |
int32 rused; /* Included relations */ |
94 |
int32 rtot; /* rellist len */ |
95 |
double clock; /* CPU time */ |
96 |
|
97 |
/** |
98 |
*** Calculated data (scaled) |
99 |
**/ |
100 |
struct jacobian_data J; /* linearized system */ |
101 |
}; |
102 |
|
103 |
/** |
104 |
*** Integrity checks |
105 |
*** ---------------- |
106 |
*** check_system(sys) |
107 |
**/ |
108 |
|
109 |
#define OK ((int)13695914) |
110 |
#define DESTROYED ((int)15784619) |
111 |
static int check_system(sys) |
112 |
slvDOF_system_t sys; |
113 |
/** |
114 |
*** Checks sys for NULL and for integrity. |
115 |
**/ |
116 |
{ |
117 |
if( sys == NULL ) { |
118 |
FPRINTF(stderr,"ERROR: (slvDOF) check_system\n"); |
119 |
FPRINTF(stderr," NULL system handle.\n"); |
120 |
return 1; |
121 |
} |
122 |
|
123 |
switch( sys->integrity ) { |
124 |
case OK: |
125 |
return 0; |
126 |
case DESTROYED: |
127 |
FPRINTF(stderr,"ERROR: (slvDOF) check_system\n"); |
128 |
FPRINTF(stderr," System was recently destroyed.\n"); |
129 |
return 1; |
130 |
default: |
131 |
FPRINTF(stderr,"ERROR: (slvDOF) check_system\n"); |
132 |
FPRINTF(stderr," System reused or never allocated.\n"); |
133 |
return 1; |
134 |
} |
135 |
} |
136 |
|
137 |
|
138 |
/** |
139 |
*** General input/output routines |
140 |
*** ----------------------------- |
141 |
*** print_var_name(out,sys,var) |
142 |
*** print_rel_name(out,sys,rel) |
143 |
**/ |
144 |
#define print_var_name(a,b,c) slv_print_var_name((a),(b->slv),(c)) |
145 |
#define print_rel_name(a,b,c) slv_print_rel_name((a),(b->slv),(c)) |
146 |
|
147 |
/** |
148 |
*** Array/vector operations |
149 |
*** ---------------------------- |
150 |
*** destroy_array(p) |
151 |
*** create_array(len,type) |
152 |
*** zero_array(arr,len,type) |
153 |
**/ |
154 |
|
155 |
#define destroy_array(p) \ |
156 |
if( (p) != NULL ) ascfree((p)) |
157 |
#define create_array(len,type) \ |
158 |
((len) > 0 ? (type *)ascmalloc((len)*sizeof(type)) : NULL) |
159 |
#define create_zero_array(len,type) \ |
160 |
((len) > 0 ? (type *)asccalloc((len),sizeof(type)) : NULL) |
161 |
|
162 |
/** |
163 |
*** External routines |
164 |
*** ----------------- |
165 |
*** See slv.h |
166 |
**/ |
167 |
|
168 |
static |
169 |
slvDOF_system_t slvDOF_create() |
170 |
{ |
171 |
slvDOF_system_t sys; |
172 |
|
173 |
sys = (slvDOF_system_t)asccalloc(1,sizeof(struct slvDOF_system_structure) ); |
174 |
sys->integrity = OK; |
175 |
sys->p.output.more_important = stdout; |
176 |
sys->p.output.less_important = NULL; |
177 |
sys->p.partition = TRUE; |
178 |
sys->s.ok = TRUE; |
179 |
sys->s.costsize = 0; |
180 |
sys->s.cost = NULL; /*redundant, but sanity preserving */ |
181 |
|
182 |
return(sys); |
183 |
} |
184 |
|
185 |
static void destroy_matrices(sys) |
186 |
slvDOF_system_t sys; |
187 |
{ |
188 |
if( sys->J.mtx ) { |
189 |
mtx_destroy(sys->J.mtx); |
190 |
} |
191 |
destroy_array(sys->rows); |
192 |
destroy_array(sys->cols); |
193 |
destroy_array(sys->rowlist); |
194 |
destroy_array(sys->collist); |
195 |
} |
196 |
|
197 |
static |
198 |
int slvDOF_destroy(slvDOF_system_t sys) |
199 |
{ |
200 |
if (check_system(sys)) return 1; |
201 |
destroy_matrices(sys); |
202 |
sys->integrity = DESTROYED; |
203 |
if (sys->s.cost) ascfree(sys->s.cost); |
204 |
ascfree( (POINTER)sys ); |
205 |
return 0; |
206 |
} |
207 |
|
208 |
|
209 |
#ifdef THIS_IS_AN_UNUSED_FUNCTION |
210 |
static |
211 |
void slvDOF_get_parameters(sys,parameters) |
212 |
slvDOF_system_t sys; |
213 |
slv_parameters_t *parameters; |
214 |
{ |
215 |
check_system(sys); |
216 |
mem_copy_cast(&(sys->p),parameters,sizeof(slv_parameters_t)); |
217 |
} |
218 |
#endif /* THIS_IS_AN_UNUSED_FUNCTION */ |
219 |
|
220 |
#ifdef THIS_IS_AN_UNUSED_FUNCTION |
221 |
static |
222 |
void slvDOF_set_parameters(sys,parameters) |
223 |
slvDOF_system_t sys; |
224 |
slv_parameters_t *parameters; |
225 |
{ |
226 |
check_system(sys); |
227 |
mem_copy_cast(parameters,&(sys->p),sizeof(slv_parameters_t)); |
228 |
} |
229 |
#endif /* THIS_IS_AN_UNUSED_FUNCTION */ |
230 |
|
231 |
#ifdef THIS_IS_AN_UNUSED_FUNCTION |
232 |
static |
233 |
void slvDOF_get_status(sys,status) |
234 |
slvDOF_system_t sys; |
235 |
slv_status_t *status; |
236 |
{ |
237 |
check_system(sys); |
238 |
mem_copy_cast(&(sys->s),status,sizeof(slv_status_t)); |
239 |
} |
240 |
#endif /* THIS_IS_AN_UNUSED_FUNCTION */ |
241 |
|
242 |
/** |
243 |
*** Performs structural analysis on the system, setting the flags in |
244 |
*** status. The problem must be set up, the relation/variable list |
245 |
*** must be non-NULL. sys->cap, vtotal, rtot must be set. |
246 |
**/ |
247 |
static void create_matrices(slv_system_t server,slvDOF_system_t sys) |
248 |
{ |
249 |
var_filter_t vfilter; |
250 |
rel_filter_t rfilter; |
251 |
|
252 |
sys->J.mtx = mtx_create(); |
253 |
mtx_set_order(sys->J.mtx,sys->cap); |
254 |
|
255 |
/** |
256 |
*** The server has marked incidence flags already. |
257 |
**/ |
258 |
/* count included equalities */ |
259 |
rfilter.matchbits = (REL_INCLUDED | REL_EQUALITY | REL_ACTIVE); |
260 |
rfilter.matchvalue = (REL_INCLUDED | REL_EQUALITY | REL_ACTIVE); |
261 |
sys->rused = slv_count_solvers_rels(server,&rfilter); |
262 |
|
263 |
/* count free and incident solver vars */ |
264 |
vfilter.matchbits = (VAR_FIXED | VAR_INCIDENT | VAR_SVAR | VAR_ACTIVE); |
265 |
vfilter.matchvalue = (VAR_INCIDENT | VAR_SVAR | VAR_ACTIVE); |
266 |
sys->vused = slv_count_solvers_vars(server,&vfilter); |
267 |
|
268 |
if (slv_std_make_incidence_mtx(server,sys->J.mtx,&vfilter,&rfilter)) { |
269 |
Asc_Panic(2, "create_matrices", |
270 |
"ABORT! slv_std_make_indicidence_mtx failed"); |
271 |
} |
272 |
/* Symbolic analysis */ |
273 |
sys->rtot = slv_get_num_solvers_rels(server); |
274 |
sys->vtotal = slv_get_num_solvers_vars(server); |
275 |
mtx_output_assign(sys->J.mtx,sys->rtot,sys->vtotal); |
276 |
/* symbolic rank is set */ |
277 |
sys->rank = mtx_symbolic_rank(sys->J.mtx); |
278 |
|
279 |
/* create integer,char workspaces. */ |
280 |
sys->rows = (unsigned char *)asccalloc(sys->cap,1); |
281 |
sys->cols = (unsigned char *)asccalloc(sys->cap,1); |
282 |
sys->rowlist = (int32 *)ascmalloc(sys->rtot*sizeof(int32)); |
283 |
sys->collist = (int32 *)ascmalloc(sys->vtotal*sizeof(int32)); |
284 |
|
285 |
/* Initialize Status */ |
286 |
sys->s.over_defined = (sys->rused > sys->vused); |
287 |
sys->s.under_defined = (sys->rused < sys->vused); |
288 |
sys->s.struct_singular = (sys->rank < sys->rused); |
289 |
sys->s.block.number_of = mtx_number_of_blocks(sys->J.mtx); |
290 |
} |
291 |
|
292 |
static int slvDOF_presolve(slv_system_t server, slvDOF_system_t sys) |
293 |
{ |
294 |
check_system(sys); |
295 |
sys->vlist = slv_get_solvers_var_list(server); |
296 |
sys->rlist = slv_get_solvers_rel_list(server); |
297 |
if( sys->vlist == NULL ) { |
298 |
FPRINTF(stderr,"ERROR: (slvDOF) slvDOF_presolve\n"); |
299 |
FPRINTF(stderr," Variable list not found.\n"); |
300 |
return 1; |
301 |
} else if( sys->rlist == NULL ) { |
302 |
FPRINTF(stderr,"ERROR: (slvDOF) slvDOF_presolve\n"); |
303 |
FPRINTF(stderr," Relation list not found.\n"); |
304 |
return 1; |
305 |
} |
306 |
|
307 |
sys->rtot= slv_get_num_solvers_rels(server); |
308 |
sys->vtotal= slv_get_num_solvers_vars(server); |
309 |
sys->cap = MAX(sys->rtot,sys->vtotal); |
310 |
|
311 |
destroy_matrices(sys); |
312 |
create_matrices(server,sys); |
313 |
|
314 |
/* Reset status */ |
315 |
sys->s.iteration = 0; |
316 |
sys->s.cpu_elapsed = 0.0; |
317 |
sys->s.converged = sys->s.diverged = sys->s.inconsistent = FALSE; |
318 |
sys->s.block.previous_total_size = 0; |
319 |
sys->s.block.current_block = -1; |
320 |
return 0; |
321 |
} |
322 |
|
323 |
/* this can be coded recursively, but it's a dumb idea. |
324 |
* see dof.pas:partition_calculated_region. |
325 |
*/ |
326 |
/* Note: it would be easy to return the list of unreachable relations |
327 |
* (those assigned to ineligible vars) as well. no known use for it though. |
328 |
*/ |
329 |
int slvDOF_eligible(slv_system_t server, int32 **vil) { |
330 |
|
331 |
mtx_matrix_t mtx; |
332 |
int32 *va, *rowlist, *collist; |
333 |
unsigned char *rows=NULL, *cols=NULL; |
334 |
int32 rmax,cmax,mmax,ccur,r,c,rt,ct,ft,rank,vsize; |
335 |
int i,newrows,newcols; |
336 |
struct rel_relation **rp; |
337 |
struct var_variable **vp; |
338 |
var_filter_t vfilter; |
339 |
mtx_coord_t coord; |
340 |
slvDOF_system_t sys; |
341 |
|
342 |
if (server==NULL || vil == NULL) { |
343 |
FPRINTF(stderr,"slvDOF_eligible called with NULL.\n"); |
344 |
return 0; |
345 |
} |
346 |
|
347 |
sys = slvDOF_create(); |
348 |
|
349 |
*vil = NULL; /* zero return pointer ahead of time */ |
350 |
if (sys==NULL) { |
351 |
FPRINTF(stderr,"slvDOF_eligible insufficient memory.\n"); |
352 |
return 0; |
353 |
} |
354 |
if (slvDOF_presolve(server,sys)) { |
355 |
FPRINTF(stderr,"slvDOF_eligible failed presolve."); |
356 |
/* need to destroy memory here */ |
357 |
slvDOF_destroy(sys); |
358 |
return 0; |
359 |
} |
360 |
|
361 |
vp = sys->vlist; |
362 |
rp = sys->rlist; |
363 |
rowlist = sys->rowlist; |
364 |
collist = sys->collist; |
365 |
rows = sys->rows; |
366 |
cols = sys->cols; |
367 |
/* nonsingular and not empty; no list */ |
368 |
rmax = sys->rused; |
369 |
rank = sys->rank; |
370 |
if (!(mtx=sys->J.mtx)) return 0; /* there is no jacobian-- wierd */ |
371 |
if (!mtx_check_matrix(mtx)) return 0; /* jacobian bad, very wierd */ |
372 |
|
373 |
cmax=sys->vtotal; |
374 |
mmax=sys->cap; |
375 |
|
376 |
rt=ct=ft=0; |
377 |
/* col marks: |
378 |
0 unvisited/ineligible |
379 |
1 visited |
380 |
row marks: |
381 |
0 unvisited |
382 |
1 visited |
383 |
*/ |
384 |
/* initing things. */ |
385 |
newcols = newrows = 0; /* next available ptrs in rellist,collist */ |
386 |
/* add free incident unassigned vars to the collist. since |
387 |
* fake and fixed cols never have incidence, we will never |
388 |
* mark them, nor fake or unincluded rows. |
389 |
*/ |
390 |
vfilter.matchbits = (VAR_INCIDENT | VAR_FIXED | VAR_SVAR | VAR_ACTIVE); |
391 |
vfilter.matchvalue = (VAR_INCIDENT | VAR_SVAR | VAR_ACTIVE); |
392 |
for (ccur=rank; ccur < mmax; ccur++) { |
393 |
i = mtx_col_to_org(mtx,ccur); |
394 |
if ( i < cmax ) { /* if col real */ |
395 |
if (var_apply_filter(vp[i],&vfilter)) { |
396 |
collist[newcols++] = ccur; |
397 |
cols[ccur] = 1; |
398 |
ct++; |
399 |
#if ELDEBUG |
400 |
PRINTF("marking free unassigned col %d\n",ccur); |
401 |
#endif |
402 |
} |
403 |
} |
404 |
} |
405 |
/* now mark up everyone who might be eligible */ |
406 |
do { |
407 |
while (newcols > 0) { |
408 |
/* mark all rows crossing newly marked cols */ |
409 |
/* should we allow incidence in unassigned rows to count? |
410 |
* we do. |
411 |
*/ |
412 |
coord.col = collist[--newcols]; |
413 |
#if ELDEBUG |
414 |
PRINTF("scanning col %d\n",coord.col); |
415 |
#endif |
416 |
coord.row = mtx_FIRST; |
417 |
while (mtx_next_in_col(mtx,&coord,mtx_ALL_ROWS), |
418 |
coord.row != mtx_LAST ) { |
419 |
#if ELDEBUG |
420 |
PRINTF("found row: %d rel:%d\n",coord.col, |
421 |
mtx_row_to_org(mtx,coord.row)); |
422 |
#endif |
423 |
if (!rows[coord.row]) { /* if not here before, mark row */ |
424 |
rows[coord.row] = 1; |
425 |
rowlist[newrows++] = coord.row; |
426 |
rt++; |
427 |
} |
428 |
} |
429 |
} |
430 |
while (newrows > 0) { |
431 |
/* set new mark flag on assigned col of new rows */ |
432 |
r = rowlist[--newrows]; |
433 |
if (!cols[r]) { |
434 |
#if ELDEBUG |
435 |
PRINTF("marking col %d\n",r); |
436 |
#endif |
437 |
cols[r] = 1; |
438 |
collist[newcols++] = r; |
439 |
ct++; |
440 |
} |
441 |
} |
442 |
} while (newcols>0); |
443 |
/* now remove the FALSE positive eligible vars */ |
444 |
for (r = 0; r < rank; r++) { |
445 |
/* assignments in unreachable rows are ineligible */ |
446 |
if (!rows[r] && cols[r]) { |
447 |
#if ELDEBUG |
448 |
PRINTF("removing col %d with unassignable row from eligibles.\n",r); |
449 |
#endif |
450 |
cols[r] = 0; |
451 |
ct--; |
452 |
} |
453 |
} |
454 |
#if ELDEBUG |
455 |
PRINTF("ct= %d, rt= %d\n",ct,rt); |
456 |
#endif |
457 |
va = *vil = create_zero_array(1+ct,int32); |
458 |
vsize = ct; |
459 |
va[ct]=(-1); |
460 |
ct=0; |
461 |
|
462 |
/* make up col report */ |
463 |
for (c=0;c<mmax;c++) { |
464 |
if (cols[c]==1) { |
465 |
#if ELDEBUG |
466 |
PRINTF("recording marked col %d\n",c); |
467 |
if (ct<vsize) {; |
468 |
#endif |
469 |
va[ct] = mtx_col_to_org(mtx,c); |
470 |
ct++; |
471 |
#if ELDEBUG |
472 |
} else { |
473 |
PRINTF("unexpectedly "); |
474 |
} |
475 |
PRINTF("got eligible col %d\n",c); |
476 |
#endif |
477 |
} |
478 |
} |
479 |
#if ELDEBUG |
480 |
PRINTF("last ct %d\n",ct-1); |
481 |
#endif |
482 |
slvDOF_destroy(sys); |
483 |
return 1; |
484 |
} |
485 |
|
486 |
/* this can be coded recursively, but it's a bad idea. |
487 |
see dof.pas:find_swap_vars if you can find the pascal version. |
488 |
Turn your head sideways and you see it is the same code as |
489 |
find eligible with different output and skipping all the debug. |
490 |
*/ |
491 |
|
492 |
int slvDOF_structsing(slv_system_t server, int32 rwhy, int32 **vover, |
493 |
int32 **rcomb, int32 **vfixed) { |
494 |
mtx_matrix_t mtx; |
495 |
const struct var_variable **fv=NULL; |
496 |
int32 *va, *ra, *fa, *rowlist, *collist; |
497 |
unsigned char *rows=NULL, *cols=NULL; |
498 |
int32 rmax,cmax,mmax,rcur,r,c,rt,ct,ft,rank,var,varmax; |
499 |
int i,newrows,newcols; |
500 |
struct rel_relation **rp; |
501 |
struct var_variable **vp; |
502 |
var_filter_t vfilter; |
503 |
mtx_coord_t coord; |
504 |
slvDOF_system_t sys; |
505 |
|
506 |
|
507 |
if (server==NULL || vover == NULL || rcomb == NULL || vfixed == NULL) { |
508 |
FPRINTF(stderr,"slvDOF_structsing called with NULL.\n"); |
509 |
return 0; |
510 |
} |
511 |
|
512 |
sys = slvDOF_create(); |
513 |
|
514 |
if (sys == NULL) { |
515 |
FPRINTF(stderr,"slvDOF_structsing insufficient memory.\n"); |
516 |
return 0; |
517 |
} |
518 |
if (slvDOF_presolve(server,sys)) { |
519 |
FPRINTF(stderr,"slvDOF_structsing failed presolve."); |
520 |
slvDOF_destroy(sys); |
521 |
return 0; |
522 |
} |
523 |
|
524 |
*vfixed = *vover = *rcomb = NULL; /* zero return pointers ahead of time */ |
525 |
vp = sys->vlist; |
526 |
rp = sys->rlist; |
527 |
rowlist = sys->rowlist; |
528 |
collist = sys->collist; |
529 |
rows = sys->rows; |
530 |
cols = sys->cols; |
531 |
/* nonsingular and not empty; no list */ |
532 |
rmax = sys->rused; |
533 |
rank = sys->rank; |
534 |
if (sys->rank == rmax && rmax > 0) { |
535 |
slvDOF_destroy(sys); |
536 |
return 0; |
537 |
} |
538 |
if ((mtx=sys->J.mtx)==NULL) return 0; /* there is no jacobian-- wierd */ |
539 |
if (!mtx_check_matrix(mtx)) return 0; /* jacobian bad, very wierd */ |
540 |
|
541 |
cmax=sys->vused; |
542 |
mmax=sys->cap; |
543 |
|
544 |
rt=ct=ft=0; |
545 |
if (rwhy > -1) rwhy = mtx_row_to_org(mtx,rwhy); |
546 |
/* col marks: |
547 |
0 unvisited/ineligible |
548 |
1 visited |
549 |
row marks: |
550 |
0 unvisited |
551 |
1 visited |
552 |
*/ |
553 |
vfilter.matchbits = (VAR_INCIDENT | VAR_FIXED | VAR_SVAR | VAR_ACTIVE); |
554 |
vfilter.matchvalue = vfilter.matchbits; |
555 |
/* initing things. */ |
556 |
newcols = newrows = 0; /* next available ptrs in rellist,collist */ |
557 |
/* add included unassigned user-interesting equations to rellist. |
558 |
* ignore fake and unincluded rows. |
559 |
*/ |
560 |
for (rcur = rank; rcur < mmax; rcur++) { |
561 |
i = mtx_row_to_org(mtx,rcur); |
562 |
if ( i < sys->rtot && (rwhy == -1 || rcur == rwhy)) { /* if row real */ |
563 |
if (rel_included(rp[i]) && rel_active(rp[i])) { |
564 |
rowlist[newrows++] = rcur; |
565 |
rows[rcur] = 1; |
566 |
rt++; |
567 |
} |
568 |
} |
569 |
} |
570 |
/* now mark up everyone who might be singular */ |
571 |
do { |
572 |
while (newrows > 0) { |
573 |
/* mark all cols crossing newly marked rows */ |
574 |
coord.row = rowlist[--newrows]; |
575 |
coord.col = mtx_FIRST; |
576 |
while (mtx_next_in_row(mtx,&coord,mtx_ALL_COLS), |
577 |
coord.col != mtx_LAST ) { |
578 |
if (coord.row==coord.col) continue; /* skip assigned var of row */ |
579 |
if (!cols[coord.col]) { /* if not here before, mark col */ |
580 |
cols[coord.col] = 1; |
581 |
collist[newcols++] = coord.col; |
582 |
ct++; |
583 |
} |
584 |
} |
585 |
} |
586 |
while (newcols > 0) { |
587 |
/* set new mark flag on assigned row of new cols */ |
588 |
c = collist[--newcols]; |
589 |
if (!rows[c]) { |
590 |
rows[c] = 1; |
591 |
rowlist[newrows++] = c; |
592 |
rt++; |
593 |
} |
594 |
} |
595 |
} while (newrows>0); |
596 |
|
597 |
va = *vover = create_zero_array(1+ct,int32); |
598 |
ra = *rcomb = create_zero_array(1+rt,int32); |
599 |
va[ct] = ra[rt] = (-1); |
600 |
rt = ct = 0; |
601 |
|
602 |
/* mark also the fixed columns in marked equations while making row report */ |
603 |
for (r=0; r<mmax; r++) { |
604 |
if (rows[r]>0) { |
605 |
ra[rt] = i = mtx_row_to_org(mtx,r); |
606 |
rt++; |
607 |
fv = rel_incidence_list(rp[i]); |
608 |
varmax = rel_n_incidences(rp[i]); |
609 |
if ( fv != NULL && varmax >0) { |
610 |
for (var = 0; var<varmax; var++) { |
611 |
if (var_apply_filter(fv[var],&vfilter)) { |
612 |
cols[mtx_org_to_col(mtx,var_sindex(fv[var]))] = 1; |
613 |
} |
614 |
} |
615 |
} |
616 |
} |
617 |
} |
618 |
/* make up free singular col report */ |
619 |
for (c = 0; c < cmax; c++) { |
620 |
if (cols[c] == 1) { |
621 |
va[ct] = mtx_col_to_org(mtx,c); |
622 |
ct++; |
623 |
} |
624 |
} |
625 |
|
626 |
/* make up overspecified cols report */ |
627 |
for (c=cmax;c<mmax;c++) { |
628 |
if (cols[c]) ft++; |
629 |
} |
630 |
fa = *vfixed = create_zero_array(1+ft,int32); |
631 |
fa[ft] = (-1); |
632 |
ft=0; |
633 |
for (c = cmax; c < mmax; c++) { |
634 |
if (cols[c]>0) { |
635 |
fa[ft++] = mtx_col_to_org(mtx,c); |
636 |
} |
637 |
} |
638 |
slvDOF_destroy(sys); |
639 |
return 1; |
640 |
} |
641 |
|
642 |
|
643 |
/* |
644 |
* CONDITIONAL MODELING |
645 |
* |
646 |
* Global Search Consistency Analysis |
647 |
* --------------------------------------------------------- |
648 |
* This Analysis performs a combinatorial search (over all the |
649 |
* alternative sets of equations) to find a consitent |
650 |
* partitioning of the variables (appropriate selection of |
651 |
* degrees of freedom). It checks first if the analysis is |
652 |
* necessary (checks which conditional statements may |
653 |
* change the structure of the system) and it will only consider |
654 |
* for the analysis those statements which may change the structure |
655 |
* of the system. |
656 |
*/ |
657 |
|
658 |
|
659 |
/* auxiliar structures */ |
660 |
struct bool_values { |
661 |
int32 *pre_val; /* previous values of dis_discrete */ |
662 |
int32 *cur_val; /* current values of dis_discrete */ |
663 |
}; |
664 |
|
665 |
/* |
666 |
* In each step of the combinatorial search it is necessary to find out |
667 |
* if the alternative being analyzed is square, underspecified, |
668 |
* structurally singular or overspecified. |
669 |
* |
670 |
* status = 1 ==> underspecified |
671 |
* status = 2 ==> square |
672 |
* status = 3 ==> structurally singular |
673 |
* status = 4 ==> overspecifed |
674 |
* status = 5 ==> Error !! ( insufficient memory, NULL argument, |
675 |
* failed to presolve) |
676 |
* |
677 |
* If the system is underspecified, we will get the number of the |
678 |
* degrees of freedom for the alternative |
679 |
* |
680 |
*/ |
681 |
|
682 |
int32 slvDOF_status(slv_system_t server, int32 *status, int32 *dof) |
683 |
{ |
684 |
slvDOF_system_t sys; |
685 |
|
686 |
if (server==NULL) { |
687 |
FPRINTF(ASCERR,"slvDOF_status called with NULL.\n"); |
688 |
(*status) = 5; |
689 |
return 0; |
690 |
} |
691 |
(*dof) = 0; |
692 |
sys = slvDOF_create(); |
693 |
|
694 |
if (sys == NULL) { |
695 |
FPRINTF(ASCERR,"slvDOF_status insufficient memory.\n"); |
696 |
(*status) = 5; |
697 |
return 0; |
698 |
} |
699 |
if (slvDOF_presolve(server,sys)) { |
700 |
FPRINTF(ASCERR,"slvDOF_status failed presolve."); |
701 |
(*status) = 5; |
702 |
slvDOF_destroy(sys); |
703 |
return 0; |
704 |
} |
705 |
|
706 |
if (sys->rank < sys->rused) { |
707 |
(*status) = 3; |
708 |
(*dof) = 0; |
709 |
slvDOF_destroy(sys); |
710 |
return 1; |
711 |
} |
712 |
|
713 |
if (sys->rused > sys->vused) { |
714 |
(*status) = 4; |
715 |
slvDOF_destroy(sys); |
716 |
return 1; |
717 |
} |
718 |
|
719 |
if ((sys->vused==sys->rused) && (sys->rank ==sys->rused)) { |
720 |
(*status) = 2; |
721 |
slvDOF_destroy(sys); |
722 |
return 1; |
723 |
} |
724 |
|
725 |
if (sys->vused > sys->rused) { |
726 |
(*status) = 1; |
727 |
(*dof) = sys->vused - sys->rused; |
728 |
slvDOF_destroy(sys); |
729 |
return 1; |
730 |
} |
731 |
|
732 |
return 1; |
733 |
} |
734 |
|
735 |
|
736 |
/* |
737 |
* the first element of cur_cases is in position one. The result is |
738 |
* the same array, but ordered and starting in position zero |
739 |
*/ |
740 |
static int32 *reorder_cases(int32 *cur_cases, int32 ncases) |
741 |
{ |
742 |
int32 cur_case,pos,tmp_num,c,ind; |
743 |
int32 *result; |
744 |
|
745 |
result = create_array(ncases,int32); |
746 |
for (c=1; c<=ncases; c++) { |
747 |
tmp_num = 0; |
748 |
for (ind=1; ind<=ncases; ind++) { |
749 |
cur_case = cur_cases[ind]; |
750 |
if (tmp_num < cur_case) { |
751 |
pos = ind; |
752 |
tmp_num = cur_case; |
753 |
} |
754 |
} |
755 |
cur_cases[pos] = 0; |
756 |
result[ncases-c] = tmp_num; |
757 |
} |
758 |
|
759 |
destroy_array(cur_cases); |
760 |
return result; |
761 |
} |
762 |
|
763 |
/* |
764 |
* Get the eligible var list for each alternative |
765 |
* Return: |
766 |
* 1 means everything went right |
767 |
* 0 means the analysis has failed with the current parititioning |
768 |
* -1 means a memory problem has occurred |
769 |
*/ |
770 |
static int32 get_eligible_vars(slv_system_t server,struct gl_list_t *disvars, |
771 |
int *combinations, int32 *terminate) |
772 |
{ |
773 |
struct var_variable **vslist; |
774 |
struct var_variable **vmlist; |
775 |
struct var_variable *mvar, *svar; |
776 |
var_filter_t vfilter; |
777 |
int32 *cur_cases; |
778 |
int32 *correct_cases; |
779 |
int32 *vars; |
780 |
int32 v, count, ind; |
781 |
int32 ncases; |
782 |
int32 mnum; |
783 |
int32 status,dof; |
784 |
|
785 |
vslist = slv_get_solvers_var_list(server); |
786 |
vmlist = slv_get_master_var_list(server); |
787 |
mnum = slv_get_num_master_vars(server); |
788 |
for (v=0; v<mnum; v++) { |
789 |
mvar = vmlist[v]; |
790 |
var_set_eligible_in_subregion(mvar,FALSE); |
791 |
} |
792 |
|
793 |
cur_cases = cases_matching(disvars,&ncases); |
794 |
correct_cases = reorder_cases(cur_cases,ncases); |
795 |
set_active_rels_in_subregion(server,correct_cases,ncases,disvars); |
796 |
set_active_vars_in_subregion(server); |
797 |
destroy_array(correct_cases); |
798 |
|
799 |
#if DEBUG_CONSISTENCY_ANALYSIS |
800 |
FPRINTF(ASCERR,"Analyzing alternative:\n"); |
801 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
802 |
|
803 |
if (!slvDOF_status(server,(&status),(&dof))) { |
804 |
FPRINTF(ASCERR,"ERROR in combinatorial search\n"); |
805 |
FPRINTF(ASCERR,"Combinatorial search aborted\n"); |
806 |
return -1; |
807 |
} else { |
808 |
if (status == 3) { |
809 |
#if DEBUG_CONSISTENCY_ANALYSIS |
810 |
FPRINTF(ASCERR,"Alternative is structurally singular\n"); |
811 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
812 |
(*terminate) = 0; |
813 |
return 0; |
814 |
} else { |
815 |
if (status == 4) { |
816 |
#if DEBUG_CONSISTENCY_ANALYSIS |
817 |
FPRINTF(ASCERR,"Alternative is overspecified\n"); |
818 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
819 |
(*terminate) = 0; |
820 |
return 0; |
821 |
} |
822 |
} |
823 |
} |
824 |
|
825 |
if (status == 1) { |
826 |
(*terminate) = 0; |
827 |
#if DEBUG_CONSISTENCY_ANALYSIS |
828 |
FPRINTF(ASCERR,"Alternative has % d degrees of freedom.\n",dof); |
829 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
830 |
if (slvDOF_eligible(server,&(vars))) { |
831 |
count = 0; |
832 |
while (vars[count] != -1) { |
833 |
ind = vars[count]; |
834 |
svar = vslist[ind]; |
835 |
v = var_mindex(svar); |
836 |
mvar = vmlist[v]; |
837 |
var_set_eligible_in_subregion(mvar,TRUE); |
838 |
count++; |
839 |
} |
840 |
destroy_array(vars); |
841 |
} |
842 |
if (dof > count) { |
843 |
#if DEBUG_CONSISTENCY_ANALYSIS |
844 |
FPRINTF(ASCERR, |
845 |
"Alternative does not have enough number of eligible vars\n"); |
846 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
847 |
return 0; |
848 |
} |
849 |
} |
850 |
|
851 |
if (status == 2) { |
852 |
#if DEBUG_CONSISTENCY_ANALYSIS |
853 |
FPRINTF(ASCERR,"Alternative is square.\n"); |
854 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
855 |
} |
856 |
|
857 |
vfilter.matchbits = (VAR_ACTIVE | VAR_INCIDENT | VAR_SVAR |
858 |
| VAR_ELIGIBLE_IN_SUBREGION); |
859 |
vfilter.matchvalue = (VAR_ACTIVE | VAR_INCIDENT | VAR_SVAR); |
860 |
|
861 |
for (v=0; v<mnum; v++) { |
862 |
mvar = vmlist[v]; |
863 |
if(var_apply_filter(mvar,&vfilter)) { |
864 |
var_set_eligible(mvar,FALSE); |
865 |
} |
866 |
var_set_eligible_in_subregion(mvar,FALSE); |
867 |
} |
868 |
(*combinations)++; |
869 |
return 1; |
870 |
} |
871 |
|
872 |
/* |
873 |
* Get the eligible set of variables for each of the combinations generated |
874 |
* by modifying the values of the boolean variables |
875 |
* Return: |
876 |
* 1 means everything went right |
877 |
* 0 means the analysis has failed with the current parititioning |
878 |
* -1 means a memory problem has occurred |
879 |
*/ |
880 |
static int32 do_search_consistency_combinations(slv_system_t server, |
881 |
struct gl_list_t *disvars, |
882 |
int32 dlen, int32 d, |
883 |
int32 *combinations, |
884 |
int32 *terminate) |
885 |
{ |
886 |
struct dis_discrete *cur_dis; |
887 |
int32 dpo, result; |
888 |
|
889 |
if(d < dlen) { |
890 |
dpo = d + 1; |
891 |
cur_dis = (struct dis_discrete *)(gl_fetch(disvars,d)); |
892 |
dis_set_boolean_value(cur_dis,TRUE); |
893 |
result = do_search_consistency_combinations(server,disvars,dlen, |
894 |
dpo,combinations,terminate); |
895 |
if (result != 1) { |
896 |
return result; |
897 |
} |
898 |
|
899 |
dis_set_boolean_value(cur_dis,FALSE); |
900 |
result = do_search_consistency_combinations(server,disvars,dlen, |
901 |
dpo,combinations,terminate); |
902 |
if (result != 1) { |
903 |
return result; |
904 |
} |
905 |
|
906 |
} else { |
907 |
if (d == dlen) { |
908 |
cur_dis = (struct dis_discrete *)(gl_fetch(disvars,d)); |
909 |
dis_set_boolean_value(cur_dis,TRUE); |
910 |
result = get_eligible_vars(server,disvars,combinations,terminate); |
911 |
if (result != 1) { |
912 |
return result; |
913 |
} |
914 |
dis_set_boolean_value(cur_dis,FALSE); |
915 |
result = get_eligible_vars(server,disvars,combinations,terminate); |
916 |
if (result != 1) { |
917 |
return result; |
918 |
} |
919 |
} else { |
920 |
FPRINTF(ASCERR,"ERROR: do_search_consistency_combinations \n"); |
921 |
FPRINTF(ASCERR," Wrong discrete var index as argument \n"); |
922 |
} |
923 |
} |
924 |
return 1; |
925 |
} |
926 |
|
927 |
/* |
928 |
* Storing original values of boolean variables |
929 |
*/ |
930 |
static void storing_original_bool_values(struct gl_list_t *bollist, |
931 |
struct bool_values *bval) |
932 |
{ |
933 |
struct dis_discrete *dvar; |
934 |
int32 d, dlen; |
935 |
|
936 |
dlen = gl_length(bollist); |
937 |
bval->pre_val = create_array(dlen,int32); |
938 |
bval->cur_val = create_array(dlen,int32); |
939 |
for (d=1; d<=dlen; d++){ |
940 |
dvar = (struct dis_discrete *)gl_fetch(bollist,d); |
941 |
bval->cur_val[d-1] = dis_value(dvar); |
942 |
bval->pre_val[d-1] = dis_previous_value(dvar); |
943 |
} |
944 |
} |
945 |
|
946 |
/* |
947 |
* Restoring original values of boolean variables |
948 |
*/ |
949 |
static void restoring_original_bool_values(struct gl_list_t *bollist, |
950 |
struct bool_values *bval) |
951 |
{ |
952 |
struct dis_discrete *dvar; |
953 |
int32 d, dlen; |
954 |
|
955 |
dlen = gl_length(bollist); |
956 |
for (d=1; d<=dlen; d++){ |
957 |
dvar = (struct dis_discrete *)gl_fetch(bollist,d); |
958 |
dis_set_boolean_value(dvar,bval->cur_val[d-1]); |
959 |
dis_set_value(dvar,bval->cur_val[d-1]); |
960 |
dis_set_previous_value(dvar,bval->pre_val[d-1]); |
961 |
} |
962 |
destroy_array(bval->cur_val); |
963 |
destroy_array(bval->pre_val); |
964 |
} |
965 |
|
966 |
/* |
967 |
* Restoring orignal configuration of the system |
968 |
*/ |
969 |
static void restore_configuration(slv_system_t server, |
970 |
struct gl_list_t *bollist) |
971 |
|
972 |
{ |
973 |
int32 *cur_cases, *correct_cases; |
974 |
int32 ncases; |
975 |
|
976 |
cur_cases = cases_matching(bollist,&ncases); |
977 |
correct_cases = reorder_cases(cur_cases,ncases); |
978 |
set_active_rels_in_subregion(server,correct_cases,ncases,bollist); |
979 |
set_active_vars_in_subregion(server); |
980 |
destroy_array(correct_cases); |
981 |
} |
982 |
|
983 |
/* |
984 |
* Perform a combinatorial consistency analysis for all the alternatives |
985 |
* that we can get from the combination of boolean values for the boolean |
986 |
* variables given in the list passed as argument |
987 |
*/ |
988 |
|
989 |
static int32 perform_combinatorial_consistency_analysis(slv_system_t server, |
990 |
struct gl_list_t *bollist, |
991 |
int32 *terminate) |
992 |
{ |
993 |
struct var_variable **vmlist; |
994 |
struct var_variable *mvar; |
995 |
var_filter_t vfilter; |
996 |
int32 *globeli; |
997 |
int32 d, dlen, max_comb, combinations; |
998 |
int32 mnum, v, elnum; |
999 |
int32 result; |
1000 |
int32 iter; |
1001 |
|
1002 |
/* |
1003 |
* Initializing eligible bit for variables |
1004 |
*/ |
1005 |
vmlist = slv_get_master_var_list(server); |
1006 |
mnum = slv_get_num_master_vars(server); |
1007 |
for (v=0; v<mnum; v++) { |
1008 |
mvar = vmlist[v]; |
1009 |
var_set_eligible(mvar,TRUE); |
1010 |
} |
1011 |
|
1012 |
dlen = gl_length(bollist); |
1013 |
|
1014 |
max_comb = 1; |
1015 |
for (d = 1; d<=dlen; d++) { |
1016 |
max_comb = max_comb * 2; |
1017 |
} |
1018 |
|
1019 |
d = 1; |
1020 |
combinations = 0; |
1021 |
#if DEBUG_CONSISTENCY_ANALYSIS |
1022 |
FPRINTF(ASCERR,"S e a r c h i n g \n"); |
1023 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
1024 |
result = do_search_consistency_combinations(server,bollist,dlen,d, |
1025 |
&(combinations),terminate); |
1026 |
|
1027 |
if (result != 1) { |
1028 |
#if DEBUG_CONSISTENCY_ANALYSIS |
1029 |
FPRINTF(ASCERR,"returning failed search after S e a r c h i n g\n"); |
1030 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
1031 |
return result; |
1032 |
} |
1033 |
|
1034 |
/* |
1035 |
* Getting the "globally" eligible variables |
1036 |
*/ |
1037 |
vfilter.matchbits = (VAR_INCIDENT | VAR_SVAR | VAR_ELIGIBLE | VAR_FIXED); |
1038 |
vfilter.matchvalue = (VAR_INCIDENT | VAR_SVAR | VAR_ELIGIBLE); |
1039 |
elnum = slv_count_master_vars(server,&vfilter); |
1040 |
|
1041 |
if (elnum > 0) { |
1042 |
globeli = (int32 *)ascmalloc(elnum*sizeof(int32)); |
1043 |
elnum = 0; |
1044 |
for (v=0; v<mnum; v++) { |
1045 |
mvar = vmlist[v]; |
1046 |
if(var_apply_filter(mvar,&vfilter)) { |
1047 |
#if DEBUG_CONSISTENCY_ANALYSIS |
1048 |
FPRINTF(ASCERR,"Eligible index = %d \n",v); |
1049 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
1050 |
globeli[elnum] = v; |
1051 |
elnum++; |
1052 |
} |
1053 |
} |
1054 |
} |
1055 |
|
1056 |
/* |
1057 |
* Recursively analysis |
1058 |
*/ |
1059 |
|
1060 |
if ((*terminate) == 1) { |
1061 |
if (elnum != 0) { |
1062 |
#if DEBUG_CONSISTENCY_ANALYSIS |
1063 |
FPRINTF(ASCERR,"ERROR: All alternatives are square but the \n"); |
1064 |
FPRINTF(ASCERR," Eligible set is not null\n"); |
1065 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
1066 |
destroy_array(globeli); |
1067 |
} |
1068 |
return 1; |
1069 |
} else { |
1070 |
if (elnum == 0) { |
1071 |
#if DEBUG_CONSISTENCY_ANALYSIS |
1072 |
FPRINTF(ASCERR,"No globally eligible variables to be fixed.\n"); |
1073 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
1074 |
return 0; |
1075 |
} |
1076 |
|
1077 |
for (v=0; v<elnum; v++) { |
1078 |
iter = 1; |
1079 |
mvar = vmlist[globeli[v]]; |
1080 |
var_set_fixed(mvar,TRUE); |
1081 |
var_set_potentially_fixed(mvar,TRUE); |
1082 |
#if DEBUG_CONSISTENCY_ANALYSIS |
1083 |
FPRINTF(ASCERR,"Fixing index = %d \n",globeli[v]); |
1084 |
FPRINTF(ASCERR,"N e s t e d S e a r c h \n"); |
1085 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
1086 |
result = perform_combinatorial_consistency_analysis(server,bollist, |
1087 |
&iter); |
1088 |
if (result != 1) { |
1089 |
#if DEBUG_CONSISTENCY_ANALYSIS |
1090 |
FPRINTF(ASCERR,"%d eliminated\n",globeli[v]); |
1091 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
1092 |
var_set_fixed(mvar,FALSE); |
1093 |
var_set_potentially_fixed(mvar,FALSE); |
1094 |
continue; |
1095 |
} else { |
1096 |
if (iter == 1) { |
1097 |
(*terminate) = 1; |
1098 |
#if DEBUG_CONSISTENCY_ANALYSIS |
1099 |
FPRINTF(ASCERR,"%d Acepted \n",globeli[v]); |
1100 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
1101 |
destroy_array(globeli); |
1102 |
return 1; |
1103 |
} else { |
1104 |
var_set_fixed(mvar,FALSE); |
1105 |
var_set_potentially_fixed(mvar,FALSE); |
1106 |
continue; |
1107 |
} |
1108 |
} |
1109 |
} |
1110 |
destroy_array(globeli); |
1111 |
#if DEBUG_CONSISTENCY_ANALYSIS |
1112 |
FPRINTF(ASCERR,"returning 0 after nested search\n"); |
1113 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
1114 |
return 0; |
1115 |
} |
1116 |
} |
1117 |
|
1118 |
/* |
1119 |
* Perform a combinatorial consistency analysis for all the alternatives |
1120 |
* that we can get from the combination of boolean values for the boolean |
1121 |
* variables given in the list passed as argument |
1122 |
*/ |
1123 |
|
1124 |
static int32 get_globally_consistent_set(slv_system_t server, |
1125 |
struct gl_list_t *bollist, |
1126 |
int32 **eliset) |
1127 |
{ |
1128 |
struct var_variable **vmlist; |
1129 |
struct var_variable *mvar; |
1130 |
var_filter_t vfilter; |
1131 |
int32 d, dlen, max_comb, combinations; |
1132 |
int32 mnum, v, elnum; |
1133 |
int32 terminate; |
1134 |
int32 result; |
1135 |
|
1136 |
/* |
1137 |
* Initializing eligible bit for variables |
1138 |
*/ |
1139 |
vmlist = slv_get_master_var_list(server); |
1140 |
mnum = slv_get_num_master_vars(server); |
1141 |
for (v=0; v<mnum; v++) { |
1142 |
mvar = vmlist[v]; |
1143 |
var_set_eligible(mvar,TRUE); |
1144 |
} |
1145 |
|
1146 |
dlen = gl_length(bollist); |
1147 |
|
1148 |
max_comb = 1; |
1149 |
for (d = 1; d<=dlen; d++) { |
1150 |
max_comb = max_comb * 2; |
1151 |
} |
1152 |
|
1153 |
/* |
1154 |
* initializing |
1155 |
*/ |
1156 |
*eliset = NULL; |
1157 |
terminate = 1; |
1158 |
|
1159 |
d = 1; |
1160 |
combinations = 0; |
1161 |
result = do_search_consistency_combinations(server,bollist,dlen,d, |
1162 |
&(combinations),&terminate); |
1163 |
if (result != 1) { |
1164 |
if (terminate == 0) { |
1165 |
#if DEBUG_CONSISTENCY_ANALYSIS |
1166 |
FPRINTF(ASCERR,"ERROR: some alternatives are either singular or\n"); |
1167 |
FPRINTF(ASCERR,"overspecified. All the alternatives have to be\n"); |
1168 |
FPRINTF(ASCERR, |
1169 |
"either square or underspecified to complete the analysis\n"); |
1170 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
1171 |
} |
1172 |
return 0; |
1173 |
} |
1174 |
|
1175 |
/* |
1176 |
* Getting the "globally" eligible variables |
1177 |
*/ |
1178 |
vfilter.matchbits = (VAR_INCIDENT | VAR_SVAR | VAR_ELIGIBLE | VAR_FIXED); |
1179 |
vfilter.matchvalue = (VAR_INCIDENT | VAR_SVAR | VAR_ELIGIBLE); |
1180 |
elnum = slv_count_master_vars(server,&vfilter); |
1181 |
|
1182 |
*eliset = (int32 *)ascmalloc((elnum+1)*sizeof(int32)); |
1183 |
elnum = 0; |
1184 |
for (v=0; v<mnum; v++) { |
1185 |
mvar = vmlist[v]; |
1186 |
if(var_apply_filter(mvar,&vfilter)) { |
1187 |
(*eliset)[elnum] = v; |
1188 |
elnum++; |
1189 |
} |
1190 |
} |
1191 |
(*eliset)[elnum] = -1; |
1192 |
|
1193 |
if (elnum == 0) { |
1194 |
if (terminate == 0) { |
1195 |
#if DEBUG_CONSISTENCY_ANALYSIS |
1196 |
FPRINTF(ASCERR, |
1197 |
"Some alternatives are underspecified, but there does\n"); |
1198 |
FPRINTF(ASCERR,"not exist a set of eligible variables consistent \n"); |
1199 |
FPRINTF(ASCERR,"with all the alternatives\n"); |
1200 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
1201 |
} else { |
1202 |
#if DEBUG_CONSISTENCY_ANALYSIS |
1203 |
FPRINTF(ASCERR,"All alternatives are already square\n"); |
1204 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
1205 |
} |
1206 |
return 0; |
1207 |
} else { |
1208 |
if (terminate == 1) { |
1209 |
#if DEBUG_CONSISTENCY_ANALYSIS |
1210 |
FPRINTF(ASCERR,"All alternatives are square but the \n"); |
1211 |
FPRINTF(ASCERR,"Eligible set is not null\n"); |
1212 |
#endif /* DEBUG_CONSISTENCY_ANALYSIS */ |
1213 |
} |
1214 |
} |
1215 |
return 1; |
1216 |
} |
1217 |
|
1218 |
|
1219 |
/* |
1220 |
* Get the list of boolean variables which can potentially cause |
1221 |
* a change in the structure of the problem |
1222 |
*/ |
1223 |
static |
1224 |
struct gl_list_t *get_list_of_booleans_for_analysis(slv_system_t server) |
1225 |
{ |
1226 |
dis_filter_t dfilter; |
1227 |
struct dis_discrete **boolist; |
1228 |
struct dis_discrete *dvar; |
1229 |
struct gl_list_t *bana; |
1230 |
struct gl_list_t *whens; |
1231 |
struct w_when *when; |
1232 |
int32 d, dnum, w, wlen, numdcs; |
1233 |
|
1234 |
boolist = slv_get_solvers_dvar_list(server); |
1235 |
dnum = slv_get_num_solvers_dvars(server); |
1236 |
for (d=0; d<dnum; d++) { |
1237 |
dvar = boolist[d]; |
1238 |
if(dis_inwhen(dvar) && dis_boolean(dvar)) { |
1239 |
whens = dis_whens_list(dvar); |
1240 |
if ( (whens != NULL) && (gl_length(whens) != 0)) { |
1241 |
dis_set_changes_structure(dvar,FALSE); |
1242 |
wlen = gl_length(whens); |
1243 |
for (w=1; w<=wlen; w++) { |
1244 |
when = (struct w_when *)gl_fetch(whens,w); |
1245 |
if (when_changes_structure(when)) { |
1246 |
dis_set_changes_structure(dvar,TRUE); |
1247 |
break; |
1248 |
} |
1249 |
} |
1250 |
} else { |
1251 |
dis_set_changes_structure(dvar,FALSE); |
1252 |
} |
1253 |
} |
1254 |
} |
1255 |
|
1256 |
dfilter.matchbits = (DIS_CHANGES_STRUCTURE); |
1257 |
dfilter.matchvalue = (DIS_CHANGES_STRUCTURE); |
1258 |
numdcs = slv_count_solvers_dvars(server,&dfilter); |
1259 |
|
1260 |
bana = gl_create(numdcs); |
1261 |
for (d=0;d<dnum; d++) { |
1262 |
dvar = boolist[d]; |
1263 |
if (dis_changes_structure(dvar)) { |
1264 |
gl_append_ptr(bana,dvar); |
1265 |
} |
1266 |
} |
1267 |
|
1268 |
return bana; |
1269 |
} |
1270 |
|
1271 |
/* |
1272 |
* Get a set of eligible variables consitent for all the alternative |
1273 |
* configurations |
1274 |
*/ |
1275 |
int32 get_globally_consistent_eligible(slv_system_t server,int32 **eliset) |
1276 |
{ |
1277 |
|
1278 |
struct dis_discrete **boolist; |
1279 |
struct dis_discrete *dvar; |
1280 |
struct gl_list_t *bana; |
1281 |
struct bool_values bval; |
1282 |
int32 need_consistency_analysis; |
1283 |
int32 result, d, dnum; |
1284 |
|
1285 |
if (server==NULL || eliset == NULL) { |
1286 |
FPRINTF(ASCERR," get_globally_consistent_eligible called with NULL.\n"); |
1287 |
return 0; |
1288 |
} |
1289 |
|
1290 |
boolist = slv_get_solvers_dvar_list(server); |
1291 |
dnum = slv_get_num_solvers_dvars(server); |
1292 |
need_consistency_analysis = slv_need_consistency(server); |
1293 |
|
1294 |
if(boolist == NULL ) { |
1295 |
FPRINTF(ASCERR,"ERROR: get_globally_consistent_eligible\n"); |
1296 |
FPRINTF(ASCERR," Discrete Variable list was never set.\n"); |
1297 |
return 0; |
1298 |
} |
1299 |
|
1300 |
if (!(need_consistency_analysis)) { |
1301 |
FPRINTF(ASCERR,"Global analysis is not required\n"); |
1302 |
FPRINTF(ASCERR,"All the alternatives have the same structure \n"); |
1303 |
return 1; |
1304 |
} |
1305 |
|
1306 |
bana = get_list_of_booleans_for_analysis(server); |
1307 |
|
1308 |
if (bana == NULL) { |
1309 |
FPRINTF(ASCERR,"ERROR: get_globally_consistent_eligible \n"); |
1310 |
FPRINTF(ASCERR," List of boolean vars could not be found\n"); |
1311 |
return 0; |
1312 |
} |
1313 |
|
1314 |
storing_original_bool_values(bana,&(bval)); |
1315 |
result = get_globally_consistent_set(server,bana,eliset); |
1316 |
|
1317 |
restoring_original_bool_values(bana,&(bval)); |
1318 |
restore_configuration(server,bana); |
1319 |
for (d=0;d<dnum; d++) { |
1320 |
dvar = boolist[d]; |
1321 |
if (dis_changes_structure(dvar)) { |
1322 |
dis_set_changes_structure(dvar,FALSE); |
1323 |
} |
1324 |
} |
1325 |
gl_destroy(bana); |
1326 |
|
1327 |
if (result == 1) { |
1328 |
return 1; |
1329 |
} else { |
1330 |
return 0; |
1331 |
} |
1332 |
|
1333 |
} |
1334 |
|
1335 |
/* |
1336 |
* Main function of the consistency analysis. |
1337 |
*/ |
1338 |
int32 consistency_analysis(slv_system_t server,int32 **fixed) |
1339 |
{ |
1340 |
|
1341 |
struct dis_discrete **boolist; |
1342 |
struct dis_discrete *dvar; |
1343 |
struct var_variable **vmlist; |
1344 |
struct var_variable *mvar; |
1345 |
struct gl_list_t *bana; |
1346 |
var_filter_t vfilter; |
1347 |
struct bool_values bval; |
1348 |
int32 need_consistency_analysis; |
1349 |
int32 result, elnum, mnum, v; |
1350 |
int32 terminate; |
1351 |
int32 d, dnum; |
1352 |
|
1353 |
if (server==NULL || fixed == NULL) { |
1354 |
FPRINTF(ASCERR,"consistency_analysis called with NULL.\n"); |
1355 |
return 0; |
1356 |
} |
1357 |
|
1358 |
boolist = slv_get_solvers_dvar_list(server); |
1359 |
dnum = slv_get_num_solvers_dvars(server); |
1360 |
need_consistency_analysis = slv_need_consistency(server);; |
1361 |
|
1362 |
if(boolist == NULL ) { |
1363 |
FPRINTF(ASCERR,"ERROR: consistency_analysis\n"); |
1364 |
FPRINTF(ASCERR," Discrete Variable list was never set.\n"); |
1365 |
return 0; |
1366 |
} |
1367 |
|
1368 |
if (!(need_consistency_analysis)) { |
1369 |
FPRINTF(ASCERR,"Consistency analysis is not required\n"); |
1370 |
FPRINTF(ASCERR,"All the alternatives have the same structure \n"); |
1371 |
return 1; |
1372 |
} |
1373 |
|
1374 |
bana = get_list_of_booleans_for_analysis(server); |
1375 |
|
1376 |
if (bana == NULL || gl_length(bana) == 0) { |
1377 |
FPRINTF(ASCERR,"ERROR: consistency_analysis\n"); |
1378 |
FPRINTF(ASCERR," List of boolean vars could not be found\n"); |
1379 |
return 0; |
1380 |
} |
1381 |
|
1382 |
storing_original_bool_values(bana,&(bval)); |
1383 |
|
1384 |
/* |
1385 |
* initializing |
1386 |
*/ |
1387 |
*fixed = NULL; |
1388 |
terminate = 1; |
1389 |
|
1390 |
vmlist = slv_get_master_var_list(server); |
1391 |
mnum = slv_get_num_master_vars(server); |
1392 |
|
1393 |
vfilter.matchbits = (VAR_POTENTIALLY_FIXED); |
1394 |
vfilter.matchvalue = (VAR_POTENTIALLY_FIXED); |
1395 |
|
1396 |
result = perform_combinatorial_consistency_analysis(server,bana,&terminate); |
1397 |
if (result == 1) { |
1398 |
/* |
1399 |
* Getting the set of eligible variables |
1400 |
*/ |
1401 |
elnum = slv_count_master_vars(server,&vfilter); |
1402 |
*fixed = (int32 *)ascmalloc((elnum+1)*sizeof(int32)); |
1403 |
elnum = 0; |
1404 |
for (v=0; v<mnum; v++) { |
1405 |
mvar = vmlist[v]; |
1406 |
if(var_apply_filter(mvar,&vfilter)) { |
1407 |
var_set_fixed(mvar,FALSE); |
1408 |
var_set_potentially_fixed(mvar,FALSE); |
1409 |
(*fixed)[elnum] = v; |
1410 |
elnum++; |
1411 |
} |
1412 |
} |
1413 |
(*fixed)[elnum] = -1; |
1414 |
|
1415 |
for (d=0;d<dnum; d++) { |
1416 |
dvar = boolist[d]; |
1417 |
if (dis_changes_structure(dvar)) { |
1418 |
dis_set_changes_structure(dvar,FALSE); |
1419 |
} |
1420 |
} |
1421 |
restoring_original_bool_values(bana,&(bval)); |
1422 |
restore_configuration(server,bana); |
1423 |
gl_destroy(bana); |
1424 |
return 1; |
1425 |
} else { |
1426 |
for (v=0; v<mnum; v++) { |
1427 |
mvar = vmlist[v]; |
1428 |
if(var_apply_filter(mvar,&vfilter)) { |
1429 |
var_set_fixed(mvar,FALSE); |
1430 |
var_set_potentially_fixed(mvar,FALSE); |
1431 |
} |
1432 |
} |
1433 |
|
1434 |
for (d=0;d<dnum; d++) { |
1435 |
dvar = boolist[d]; |
1436 |
if (dis_changes_structure(dvar)) { |
1437 |
dis_set_changes_structure(dvar,FALSE); |
1438 |
} |
1439 |
} |
1440 |
restoring_original_bool_values(bana,&(bval)); |
1441 |
restore_configuration(server,bana); |
1442 |
gl_destroy(bana); |
1443 |
return 0; |
1444 |
} |
1445 |
|
1446 |
} |
1447 |
|
1448 |
|