1 |
/* |
2 |
* MPS: Ascend MPS file generator |
3 |
* by Craig Schmidt |
4 |
* Created: 2/11/95 |
5 |
* Version: $Revision: 1.29 $ |
6 |
* Version control file: $RCSfile: slv6.c,v $ |
7 |
* Date last modified: $Date: 2000/01/25 02:27:38 $ |
8 |
* Last modified by: $Author: ballan $ |
9 |
* |
10 |
* This file is part of the SLV solver. |
11 |
* |
12 |
* Copyright (C) 1990 Karl Michael Westerberg |
13 |
* Copyright (C) 1993 Joseph Zaher |
14 |
* Copyright (C) 1994 Joseph Zaher, Benjamin Andrew Allan |
15 |
* Copyright (C) 1995 Craig Schmidt |
16 |
* |
17 |
* The SLV solver is free software; you can redistribute |
18 |
* it and/or modify it under the terms of the GNU General Public License as |
19 |
* published by the Free Software Foundation; either version 2 of the |
20 |
* License, or (at your option) any later version. |
21 |
* |
22 |
* The SLV solver is distributed in hope that it will be |
23 |
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
24 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
25 |
* General Public License for more details. |
26 |
* |
27 |
* You should have received a copy of the GNU General Public License |
28 |
* along with the program; if not, write to the Free Software Foundation, |
29 |
* Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check the file named |
30 |
* COPYING. COPYING is found in ../compiler. |
31 |
* |
32 |
*/ |
33 |
/* known bugs |
34 |
* still uses pl_ functions and assumes the old slv protocol. |
35 |
*/ |
36 |
#include "utilities/ascConfig.h" |
37 |
#include "utilities/ascMalloc.h" |
38 |
#include "utilities/set.h" |
39 |
#include "utilities/mem.h" |
40 |
#include "general/tm_time.h" |
41 |
#include "general/list.h" |
42 |
#include "general/dstring.h" |
43 |
#include "compiler/module.h" |
44 |
#include "compiler/compiler.h" |
45 |
#include "compiler/library.h" |
46 |
#include "compiler/instance.h" |
47 |
#include "compiler/instance_io.h" |
48 |
#include "solver/mtx.h" |
49 |
#include "solver/linsol.h" |
50 |
#include "solver/linsolqr.h" |
51 |
#include "solver/slv_types.h" |
52 |
#include "solver/var.h" |
53 |
#include "solver/rel.h" |
54 |
#include "solver/discrete.h" |
55 |
#include "solver/conditional.h" |
56 |
#include "solver/logrel.h" |
57 |
#include "solver/bnd.h" |
58 |
#include "solver/calc.h" |
59 |
#include "solver/relman.h" |
60 |
#include "solver/slv_common.h" |
61 |
#include "solver/slv_client.h" |
62 |
#include "solver/slv6.h" |
63 |
#include "solver/mps.h" |
64 |
#include "interface/old_utils.h" |
65 |
|
66 |
#if !defined(STATIC_MPS) && !defined(DYNAMIC_MPS) |
67 |
int slv6_register(SlvFunctionsT *f) |
68 |
{ |
69 |
(void)f; /* stop gcc whine about unused parameter */ |
70 |
|
71 |
FPRINTF(stderr,"makeMPS not compiled in this ASCEND IV.\n"); |
72 |
return 1; |
73 |
} |
74 |
#else /* either STATIC_MPS or DYNAMIC_MPS is defined */ |
75 |
#ifdef DYNAMIC_MPS |
76 |
/* do dynamic loading stuff. yeah, right */ |
77 |
#else /* following is used if STATIC_MPS is defined */ |
78 |
|
79 |
#ifndef KILL |
80 |
#define KILL TRUE |
81 |
#endif |
82 |
#define DEBUG FALSE |
83 |
|
84 |
struct slv6_system_structure { |
85 |
|
86 |
/** |
87 |
*** Problem definition |
88 |
**/ |
89 |
slv_system_t slv; /* slv_system_t back-link */ |
90 |
struct rel_relation *obj; /* Objective function: NULL = none */ |
91 |
struct var_variable **vlist; /* Variable list (NULL terminated) */ |
92 |
struct var_variable **vlist_user; /* User vlist (NULL = determine) */ |
93 |
bnd_boundary_t *blist; /* Boundary list (NULL terminated) */ |
94 |
bnd_boundary_t *blist_user; /* User blist (NULL = none) */ |
95 |
struct rel_relation **rlist; /* Relation list (NULL terminated) */ |
96 |
struct rel_relation **rlist_user; /* User rlist (NULL = none) */ |
97 |
struct ExtRelCache **erlist; /* External relations cache list */ |
98 |
struct ExtRelCache **erlist_user;/* User erlist (NULL = none) */ |
99 |
|
100 |
/** |
101 |
*** Solver information |
102 |
**/ |
103 |
int integrity; /* ? Has the system been created */ |
104 |
slv_parameters_t p; /* Parameters */ |
105 |
slv_status_t s; /* Status flags */ |
106 |
double clock; /* CPU time */ |
107 |
int iarray[slv6_IA_SIZE]; /* Integer subparameters */ |
108 |
double rarray[slv6_RA_SIZE]; /* Real subparameters */ |
109 |
char *carray[slv6_CA_SIZE]; /* Charptr subparameter */ |
110 |
|
111 |
/** |
112 |
*** Calculated Data |
113 |
*** |
114 |
**/ |
115 |
mps_data_t mps; /* the main chunk of data for the problem */ |
116 |
|
117 |
}; |
118 |
|
119 |
/* _________________________________________________________________________ */ |
120 |
|
121 |
/** |
122 |
*** Integrity checks |
123 |
*** ---------------- |
124 |
*** check_system(sys) |
125 |
**/ |
126 |
|
127 |
#define OK ((int)813025392) |
128 |
#define DESTROYED ((int)103289182) |
129 |
static int check_system(slv6_system_t sys) |
130 |
/** |
131 |
*** Checks sys for NULL and for integrity. |
132 |
**/ |
133 |
{ |
134 |
if( sys == NULL ) { |
135 |
FPRINTF(stderr,"ERROR: (slv6) check_system\n"); |
136 |
FPRINTF(stderr," NULL system handle.\n"); |
137 |
return 1; |
138 |
} |
139 |
|
140 |
switch( sys->integrity ) { |
141 |
case OK: |
142 |
return 0; |
143 |
case DESTROYED: |
144 |
FPRINTF(stderr,"ERROR: (slv6) check_system\n"); |
145 |
FPRINTF(stderr," System was recently destroyed.\n"); |
146 |
return 1; |
147 |
default: |
148 |
FPRINTF(stderr,"ERROR: (slv6) check_system\n"); |
149 |
FPRINTF(stderr," System reused or never allocated.\n"); |
150 |
return 1; |
151 |
} |
152 |
} |
153 |
|
154 |
/* _________________________________________________________________________ */ |
155 |
|
156 |
/** |
157 |
*** Array/vector operations |
158 |
*** ---------------------------- |
159 |
*** destroy_array(p) |
160 |
*** create_array(len,type) |
161 |
*** zero_array(arr,len,type) |
162 |
*** nuke_pointers(mps_data_t mps) - free allocated memory in mps |
163 |
**/ |
164 |
|
165 |
#define destroy_array(p) \ |
166 |
if( (p) != NULL ) ascfree((p)) |
167 |
#define create_array(len,type) \ |
168 |
((len) > 0 ? (type *)ascmalloc((len)*sizeof(type)) : NULL) |
169 |
#define create_zero_array(len,type) \ |
170 |
((len) > 0 ? (type *)asccalloc((len),sizeof(type)) : NULL) |
171 |
#define zero_array(arr,nelts,type) \ |
172 |
mem_zero_byte_cast((arr),0,(nelts)*sizeof(type)) |
173 |
/* Zeros an array of nelts objects, each having given type. */ |
174 |
|
175 |
|
176 |
static void nuke_pointers(mps_data_t mps) { /* free all allocated memory in mps data structure */ |
177 |
|
178 |
if (mps.Ac_mtx != NULL) { /* delete old matrix if the exist */ |
179 |
mtx_destroy(mps.Ac_mtx); |
180 |
mps.Ac_mtx = NULL; |
181 |
} |
182 |
|
183 |
if (mps.lbrow != NULL) { /* delete old vector if it exists */ |
184 |
destroy_array(mps.lbrow); |
185 |
mps.lbrow = NULL; |
186 |
} |
187 |
|
188 |
if (mps.ubrow != NULL) { /* delete old vector if it exists */ |
189 |
destroy_array(mps.ubrow); |
190 |
mps.ubrow = NULL; |
191 |
} |
192 |
|
193 |
if (mps.bcol != NULL) { /* delete old vector if the exist */ |
194 |
destroy_array(mps.bcol); |
195 |
mps.bcol = NULL; |
196 |
} |
197 |
|
198 |
if (mps.typerow != NULL) { /* delete old vector if it exists */ |
199 |
destroy_array(mps.typerow); |
200 |
mps.typerow = NULL; |
201 |
} |
202 |
|
203 |
if (mps.relopcol != NULL) { /* delete old vector if it exists */ |
204 |
destroy_array(mps.relopcol); |
205 |
mps.relopcol = NULL; |
206 |
} |
207 |
} |
208 |
|
209 |
/* _________________________________________________________________________ */ |
210 |
|
211 |
/** |
212 |
*** General input/output routines |
213 |
*** ----------------------------- |
214 |
*** fp = MIF(sys) |
215 |
*** fp = LIF(sys) |
216 |
**/ |
217 |
|
218 |
static FILE *get_output_file(FILE *fp) |
219 |
/** |
220 |
*** Returns fp if fp!=NULL, or a file pointer |
221 |
*** open to nul device if fp == NULL. |
222 |
**/ |
223 |
{ |
224 |
static FILE *nuldev = NULL; |
225 |
static char fname[] = "/dev/null"; |
226 |
|
227 |
if( fp==NULL ) { |
228 |
if(nuldev==NULL) |
229 |
if( (nuldev=fopen(fname,"w")) == NULL ) { |
230 |
FPRINTF(stderr,"ERROR: (slv6) get_output_file\n"); |
231 |
FPRINTF(stderr," Unable to open %s.\n",fname); |
232 |
} |
233 |
fp=nuldev; |
234 |
} |
235 |
return(fp); |
236 |
} |
237 |
|
238 |
/* #define MIF(sys) get_output_file( (sys)->p.output.more_important ) |
239 |
* #define LIF(sys) get_output_file( (sys)->p.output.less_important ) |
240 |
*/ |
241 |
|
242 |
/* _________________________________________________________________________ */ |
243 |
|
244 |
/** |
245 |
*** Routines for common filters |
246 |
*** ----------------- |
247 |
*** free_inc_var_filter - true for non-fixed incident variables |
248 |
*** inc_rel_filter - true for incident relations |
249 |
**/ |
250 |
|
251 |
extern boolean free_inc_var_filter(struct var_variable *var) |
252 |
/** |
253 |
*** I've been calling this particular var filter a lot , |
254 |
*** so I decided to make it a subroutine. Returns true if |
255 |
*** var is not fixed and incident in something. |
256 |
**/ |
257 |
{ |
258 |
var_filter_t vfilter; |
259 |
vfilter.matchbits = (VAR_FIXED | VAR_INCIDENT | VAR_ACTIVE); |
260 |
vfilter.matchvalue = (VAR_INCIDENT | VAR_ACTIVE); |
261 |
|
262 |
/* vfilter.fixed = var_false;*/ /* calc for all non-fixed vars */ |
263 |
/* vfilter.incident = var_true; */ /* incident vars only */ |
264 |
/* vfilter.in_block = var_ignore; */ |
265 |
|
266 |
return var_apply_filter(var,&vfilter); |
267 |
} |
268 |
|
269 |
static boolean inc_rel_filter(struct rel_relation *rel) |
270 |
/** |
271 |
*** Returns true if rel is an incident relation. |
272 |
**/ |
273 |
{ |
274 |
rel_filter_t rfilter; /* filter for included rels */ |
275 |
rfilter.matchbits = (REL_INCLUDED | REL_ACTIVE); |
276 |
rfilter.matchvalue = (REL_INCLUDED| REL_ACTIVE ); |
277 |
/* rfilter.included = rel_true; |
278 |
rfilter.equality = rel_ignore; |
279 |
rfilter.in_block = rel_ignore; |
280 |
rfilter.in_subregion = rel_ignore; */ |
281 |
|
282 |
return rel_apply_filter(rel,&rfilter); |
283 |
} |
284 |
|
285 |
|
286 |
/* _________________________________________________________________________ */ |
287 |
|
288 |
/** |
289 |
*** Routines to calculate the mps problem representation |
290 |
*** -------------------- |
291 |
*** var_relaxed - is the variable relaxed or not? |
292 |
*** calc_c - calculate c vector, coefficients of objective |
293 |
(called by calc_matrix) |
294 |
*** calc_bounds - convert var bounds to an array of numbers |
295 |
*** calc_reloplist - convert relation operators <=, >=, = to array of numbers |
296 |
*** calc_svtlist - create array of numbers containing var types |
297 |
*** calc_matrix - compute entire matrix representaion of problem |
298 |
**/ |
299 |
|
300 |
static boolean calc_c(mtx_matrix_t mtx, /* matrix to store derivs */ |
301 |
int32 org_row, /* original number of row to store them */ |
302 |
struct rel_relation *obj) /* expression to diffs */ |
303 |
/** |
304 |
*** Calculate gradient of the objective function. (or any expression, for that matter) |
305 |
*** On the linear system we should have, this is the c vector of |
306 |
*** our problem max/min {cx: Ax<=b}. |
307 |
*** On nonlinear problems is the linearization of problem at current point |
308 |
**/ |
309 |
{ |
310 |
var_filter_t vfilter; |
311 |
int32 row; |
312 |
|
313 |
if ((mtx == NULL) || (obj == NULL)) { /* got a bad pointer */ |
314 |
FPRINTF(stderr,"ERROR: (slv6) calc_c\n"); |
315 |
FPRINTF(stderr," Routine was passed a NULL pointer!\n"); |
316 |
return FALSE; |
317 |
} |
318 |
|
319 |
vfilter.matchbits = (VAR_FIXED | VAR_INCIDENT | VAR_ACTIVE); |
320 |
vfilter.matchvalue = (VAR_INCIDENT | VAR_ACTIVE); |
321 |
/* vfilter.fixed = var_false; |
322 |
vfilter.incident = var_true; |
323 |
vfilter.in_block = var_ignore; */ |
324 |
|
325 |
row = mtx_org_to_row(mtx,org_row); /* convert from original numbering to current */ |
326 |
|
327 |
#ifndef KILL |
328 |
exprman_diffs(obj, &vfilter, row, mtx); /* find the deriviative, sets calc_ok as result */ |
329 |
#else |
330 |
FPRINTF(stderr," function calc_c is slv6 is broken.\n"); |
331 |
FPRINTF(stderr," It calls exprman_diffs with wrong number of args.\n"); |
332 |
exit; |
333 |
#endif |
334 |
return calc_ok; /* did things work out ?, calc_ok in calc.h */ |
335 |
} |
336 |
|
337 |
|
338 |
static real64 *calc_bounds(struct var_variable **vlist, /* variable list to get bounds */ |
339 |
int32 vinc, /* number of incident variables */ |
340 |
boolean upper) /* do upper, else lower */ |
341 |
|
342 |
/** |
343 |
** Stores the upper or lower bounds of all non-fixed, incident vars |
344 |
** in a new array, which is returned by the routine |
345 |
**/ |
346 |
{ |
347 |
real64 *tmp,*tmp_array_origin; /* temporary storage for our bounds data */ |
348 |
|
349 |
if (vlist == NULL) { /* got a bad pointer */ |
350 |
FPRINTF(stderr,"ERROR: (slv6) calc_bounds\n"); |
351 |
FPRINTF(stderr," Routine was passed a NULL variable list pointer!\n"); |
352 |
return FALSE; |
353 |
} |
354 |
|
355 |
tmp_array_origin = create_array(vinc,real64); |
356 |
if (tmp_array_origin == NULL) { |
357 |
FPRINTF(stderr,"ERROR: (slv6) calc_bounds\n"); |
358 |
FPRINTF(stderr," Memory allocation failed!\n"); |
359 |
return FALSE; |
360 |
} |
361 |
|
362 |
tmp = tmp_array_origin; |
363 |
for( ; *vlist != NULL ; ++vlist ) |
364 |
if( free_inc_var_filter(*vlist) ) |
365 |
if (upper) { *tmp=var_upper_bound(*vlist); tmp++; } |
366 |
else { *tmp=var_lower_bound(*vlist); tmp++; } |
367 |
|
368 |
return tmp_array_origin; |
369 |
} |
370 |
|
371 |
|
372 |
static char *calc_reloplist(struct rel_relation **rlist, |
373 |
int32 rused) /* entry for each relation */ |
374 |
/** |
375 |
*** This function constructs the a list of relational operators: <=, >=, = |
376 |
*** from the relations list. The values for each relational operator |
377 |
*** corresponds to rel_TOK_less, rel_TOK_equal, and rel_TOK_greater. |
378 |
*** (Defined in rel.h) |
379 |
*** Or rel_TOK_nonincident for relations that aren't incident (see slv6.h) |
380 |
*** |
381 |
*** Note: the rel_less, rel_equal, and rel_greater routines in rel.h don't |
382 |
*** behave as you'd expect, and should _not_ be used. Use rel_type instead. |
383 |
**/ |
384 |
{ |
385 |
char *reloplist; |
386 |
char *tmp; /* pointer for storage */ |
387 |
|
388 |
reloplist = create_array(rused,char); /* see macro, over all incident relations */ |
389 |
if (reloplist == NULL) { /* memory allocation failed */ |
390 |
FPRINTF(stderr,"ERROR: (slv6) calc_reloplist\n"); |
391 |
FPRINTF(stderr," Memory allocation failed!\n"); |
392 |
return NULL; |
393 |
} |
394 |
|
395 |
tmp = reloplist; |
396 |
for ( ;*rlist != NULL; rlist++) |
397 |
{ |
398 |
if (inc_rel_filter(*rlist)) /* is an incident var */ |
399 |
switch (rel_type(*rlist)) { |
400 |
case e_less: |
401 |
case e_lesseq: |
402 |
*tmp = rel_TOK_less; |
403 |
break; |
404 |
|
405 |
case e_equal: |
406 |
*tmp = rel_TOK_equal; |
407 |
break; |
408 |
case e_greater: |
409 |
case e_greatereq: |
410 |
*tmp = rel_TOK_greater; |
411 |
break; |
412 |
default: |
413 |
FPRINTF(stderr,"ERROR: (slv6) calc_reloplist\n"); |
414 |
FPRINTF(stderr," Unknown relation type (not greater, less, or equal)\n"); |
415 |
return NULL; |
416 |
} |
417 |
else |
418 |
*tmp = rel_TOK_nonincident; |
419 |
|
420 |
tmp++; /* increment to new location in array */ |
421 |
|
422 |
} |
423 |
|
424 |
return reloplist; |
425 |
} |
426 |
|
427 |
|
428 |
static char *calc_svtlist( struct var_variable **vlist, /* input, not modified */ |
429 |
int32 vused, /* number of vars (incident or nonincident, free or fixed) */ |
430 |
int *solver_var_used, /* number of each type of var are cached */ |
431 |
int *solver_relaxed_used, |
432 |
int *solver_int_used, |
433 |
int *solver_binary_used, |
434 |
int *solver_semi_used, |
435 |
int *solver_other_used, |
436 |
int *solver_fixed) |
437 |
/** |
438 |
*** This function constructs the solver var list from the variable list. |
439 |
*** |
440 |
*** WARNING: This routine assumes that a struct var_variable *is an Instance. |
441 |
*** In the future this is going to change, and this routine will break. |
442 |
*** |
443 |
**/ |
444 |
{ |
445 |
struct TypeDescription *type; /* type of the current var */ |
446 |
struct TypeDescription *solver_var_type; /* type of the standard types */ |
447 |
struct TypeDescription *solver_int_type; |
448 |
struct TypeDescription *solver_binary_type; |
449 |
struct TypeDescription *solver_semi_type; |
450 |
|
451 |
char *svtlist; /* pointer for storage */ |
452 |
char *tmp; /* temp pointer to set values */ |
453 |
|
454 |
/* get the types for variable definitions */ |
455 |
|
456 |
if( (solver_var_type = FindType(SOLVER_VAR_STR)) == NULL ) { |
457 |
FPRINTF(stderr,"ERROR: (slv6.c) get_solver_var_type\n"); |
458 |
FPRINTF(stderr," Type solver_var not defined.\n"); |
459 |
FPRINTF(stderr," MPS will not work.\n"); |
460 |
return NULL; |
461 |
} |
462 |
if( (solver_int_type = FindType(SOLVER_INT_STR)) == NULL ) { |
463 |
FPRINTF(stderr,"ERROR: (slv6.c) get_solver_var_type\n"); |
464 |
FPRINTF(stderr," Type solver_int not defined.\n"); |
465 |
FPRINTF(stderr," MPS will not work.\n"); |
466 |
return NULL; |
467 |
} |
468 |
if( (solver_binary_type = FindType(SOLVER_BINARY_STR)) == NULL ) { |
469 |
FPRINTF(stderr,"ERROR: (slv6.c) get_solver_var_type\n"); |
470 |
FPRINTF(stderr," Type solver_binary not defined.\n"); |
471 |
FPRINTF(stderr," MPS will not work.\n"); |
472 |
return NULL; |
473 |
} |
474 |
if( (solver_semi_type = FindType(SOLVER_SEMI_STR)) == NULL ) { |
475 |
FPRINTF(stderr,"ERROR: (slv6.c) get_solver_var_type\n"); |
476 |
FPRINTF(stderr," Type solver_semi not defined.\n"); |
477 |
FPRINTF(stderr," MPS will not work.\n"); |
478 |
return NULL; |
479 |
} |
480 |
|
481 |
/* allocate memory and initialize stuff */ |
482 |
svtlist = create_array(vused,char); /* see macro */ |
483 |
if (svtlist == NULL) { /* memory allocation failed */ |
484 |
FPRINTF(stderr,"ERROR: (slv6) calc_svtlist\n"); |
485 |
FPRINTF(stderr," Memory allocation failed for solver var type list!\n"); |
486 |
return NULL; |
487 |
} |
488 |
|
489 |
*solver_var_used = 0; |
490 |
*solver_relaxed_used = 0; |
491 |
*solver_int_used = 0; |
492 |
*solver_binary_used = 0; |
493 |
*solver_semi_used = 0; |
494 |
*solver_other_used = 0; |
495 |
*solver_fixed = 0; |
496 |
tmp = svtlist; |
497 |
|
498 |
/* loop over all vars */ |
499 |
|
500 |
for( ; *vlist != NULL ; ++vlist ) { |
501 |
if( free_inc_var_filter(*vlist) ) |
502 |
{ |
503 |
type = InstanceTypeDesc( (struct Instance *) *vlist); |
504 |
|
505 |
if (type == MoreRefined(type,solver_binary_type) ) |
506 |
{ |
507 |
if (var_relaxed(*vlist)) |
508 |
{ |
509 |
*tmp = SOLVER_RELAXED; |
510 |
*solver_relaxed_used++; |
511 |
} |
512 |
else |
513 |
{ |
514 |
*tmp = SOLVER_BINARY; |
515 |
*solver_binary_used++; |
516 |
} |
517 |
} |
518 |
else |
519 |
{ |
520 |
if (type == MoreRefined(type,solver_int_type) ) |
521 |
{ |
522 |
if (var_relaxed(*vlist)) |
523 |
{ |
524 |
*tmp = SOLVER_RELAXED; |
525 |
*solver_relaxed_used++; |
526 |
} |
527 |
else |
528 |
{ |
529 |
*tmp = SOLVER_INT; |
530 |
*solver_int_used++; |
531 |
} |
532 |
} |
533 |
else |
534 |
{ |
535 |
if (type == MoreRefined(type,solver_semi_type) ) |
536 |
{ |
537 |
if (var_relaxed(*vlist)) |
538 |
{ |
539 |
*tmp = SOLVER_RELAXED; |
540 |
*solver_relaxed_used++; |
541 |
} |
542 |
else |
543 |
{ |
544 |
*tmp = SOLVER_SEMI; |
545 |
*solver_semi_used++; |
546 |
} |
547 |
} |
548 |
else |
549 |
{ |
550 |
if (type == MoreRefined(type,solver_var_type) ) |
551 |
{ /* either solver var or some refinement */ |
552 |
*tmp = SOLVER_VAR; |
553 |
*solver_var_used++; |
554 |
} |
555 |
else |
556 |
{ |
557 |
FPRINTF(stderr,"ERROR: (slv6) determine_svtlist\n"); |
558 |
FPRINTF(stderr," Unknown solver_var type encountered.\n"); |
559 |
/* should never get to here */ |
560 |
} |
561 |
} /* if semi */ |
562 |
} /* if int */ |
563 |
} /* if binary */ |
564 |
} /* if free inc var */ |
565 |
else |
566 |
{ |
567 |
*tmp = SOLVER_FIXED; |
568 |
*solver_fixed++; |
569 |
} |
570 |
|
571 |
tmp++; |
572 |
|
573 |
} /* for */ |
574 |
|
575 |
return svtlist; |
576 |
|
577 |
} |
578 |
|
579 |
static mtx_matrix_t calc_matrix(int32 cap, |
580 |
int32 rused, |
581 |
int32 vused, |
582 |
struct rel_relation **rlist, |
583 |
struct rel_relation *obj, |
584 |
int32 crow, |
585 |
slv_status_t *s, |
586 |
int32 *rank, |
587 |
real64 **rhs_orig) |
588 |
/** |
589 |
int32 cap, in: capacity of matrix |
590 |
int32 rused, in: total number of relations used |
591 |
int32 vused, in: total number of variables used |
592 |
struct rel_relation **rlist, in: Relation list (NULL terminated) |
593 |
struct rel_relation *obj, in: objective function |
594 |
int32 crow, in: row to store objective row |
595 |
slv_status_t *s, out: s.block.jactime, and s.calc_ok |
596 |
int32 *rank, out |
597 |
real64 **rhs_orig out: rhs array origin |
598 |
**/ |
599 |
/** |
600 |
*** Creates and calculates a matrix representation of the A matrix, c row, |
601 |
*** and the RHS or b column (which is stored in rhs_orig). |
602 |
*** On nonlinear problems is the linearization of problem at current point. |
603 |
*** |
604 |
*** Note: the residual stored in the rhs array is not the real right hand side. |
605 |
*** The residual returned by the diffs call is just the value of |
606 |
** (lhs expr) - (rhs expr) |
607 |
*** we want the residual excluding the current variables. |
608 |
*** At the moment there isn't a |
609 |
*** clean way to do this. It will be calculated in the real_rhs routine. |
610 |
*** This routine |
611 |
*** will take for each relation: |
612 |
*** sum(i, (Jacobian value var[i])*(Variable value var[i])) - rhs[i] |
613 |
*** which is the real rhs. |
614 |
*** However, this will _not_ be valid for the nonlinear case. |
615 |
*** Other than this, the mps file will be the linearization of a nonlinear |
616 |
*** system at the |
617 |
*** current point. If you are adding an MINLP feature, |
618 |
*** you'll need to come up with a better way. |
619 |
*** |
620 |
*** |
621 |
*** MPS matrix strucutre |
622 |
*** v |
623 |
*** min/max cx: u |
624 |
*** Ax (<= = >=) b s |
625 |
*** e |
626 |
*** 1 d |
627 |
*** |
628 |
*** | | |
629 |
*** | | |
630 |
*** \ / \ / |
631 |
*** |
632 |
*** +- -+ |
633 |
*** 1 -> | | |
634 |
*** | | |
635 |
*** | A | |
636 |
*** | | |
637 |
*** rused -> | | |
638 |
*** +- -+ |
639 |
*** |
640 |
*** crow -> [ c ] |
641 |
*** |
642 |
*** |
643 |
*** rused row of last incident relation |
644 |
*** crow = rused + 1, row of cost vector |
645 |
*** vused column of last incident variable |
646 |
*** |
647 |
*** cap = max(vused+1,rused), size of sparse square matrix |
648 |
*** cap = N ---> row/column 0 to N-1 exist |
649 |
*** |
650 |
**/ |
651 |
{ |
652 |
mtx_matrix_t mtx; /* main data structure */ |
653 |
var_filter_t vfilter; /* checks for free incident vars in relman_diffs */ |
654 |
double time0; /* time of Jacobian calculation, among other things */ |
655 |
struct rel_relation **rp; /* relation pointer */ |
656 |
real64 *rhs; /* temporary pointer for our RHS data */ |
657 |
|
658 |
if(obj == NULL) { /* a little preflight checking */ |
659 |
FPRINTF(stderr,"ERROR: (slv6) calc_matrix\n"); |
660 |
FPRINTF(stderr," System must have an objective!\n"); |
661 |
return NULL; |
662 |
} |
663 |
|
664 |
time0=tm_cpu_time(); /* start timing */ |
665 |
s->calc_ok = TRUE; /* no errors yet */ |
666 |
|
667 |
mtx = mtx_create(); /* create 0 order matrix */ |
668 |
mtx_set_order(mtx,cap); /* adjust size of square matrix to size of cap |
669 |
(cap set in presolve.) The relman_diffs |
670 |
routine returns values in the matrix */ |
671 |
/* these routines don't return success/fail */ |
672 |
|
673 |
vfilter.matchbits = (VAR_FIXED | VAR_INCIDENT | VAR_ACTIVE); |
674 |
vfilter.matchvalue = (VAR_INCIDENT | VAR_ACTIVE); |
675 |
/* vfilter.fixed = var_false; |
676 |
vfilter.incident = var_true; |
677 |
vfilter.in_block = var_ignore; */ |
678 |
|
679 |
/* want to save column of residuals as they come along from relman_diffs */ |
680 |
*rhs_orig = create_array(rused,real64); |
681 |
if(*rhs_orig == NULL) { /* memory allocation failed */ |
682 |
FPRINTF(stderr,"ERROR: (slv6) calc_matrix\n"); |
683 |
FPRINTF(stderr," Memory allocation for right hand side failed!\n"); |
684 |
return NULL; |
685 |
} |
686 |
rhs = *rhs_orig; |
687 |
|
688 |
|
689 |
/* note: the rhs array is the residual at the current point, not what we want! |
690 |
see further comments at the start of this routine */ |
691 |
|
692 |
for( rp = rlist ; *rp != NULL ; ++rp ) { |
693 |
/* fill out A matrix only for used elements */ |
694 |
if( inc_rel_filter(*rp) ) { |
695 |
*rhs = relman_diffs(*rp,&vfilter,mtx); |
696 |
/*calculate each row of A matrix here! */ |
697 |
rhs++; |
698 |
if( ! calc_ok ) { /* error check each call, calc_ok is in calc.h */ |
699 |
s->calc_ok = FALSE; /* error in diffs ! */ |
700 |
FPRINTF(stderr,"ERROR: (slv6) calc_matrix\n"); |
701 |
FPRINTF(stderr," Error in calculating A matrix.\n"); |
702 |
destroy_array(rhs_orig); /* clean up house, then die */ |
703 |
mtx_destroy(mtx); /* zap all alocated memory */ |
704 |
return NULL; |
705 |
} |
706 |
} |
707 |
} |
708 |
/* Calculate the rank of the matrix, before we add extra rows/cols */ |
709 |
mtx_output_assign(mtx, crow, vused); |
710 |
if(! mtx_output_assigned(mtx)) { /* output assignment failed */ |
711 |
FPRINTF(stderr,"ERROR: (slv6) calc_matrix\n"); |
712 |
FPRINTF(stderr," Output assignment to calculate rank of problem failed.\n"); |
713 |
mtx_destroy(mtx); /* zap all alocated memory */ |
714 |
destroy_array(rhs_orig); /* clean up house, then die */ |
715 |
return NULL; |
716 |
} |
717 |
*rank = mtx_symbolic_rank(mtx); |
718 |
|
719 |
if( *rank < 0 ) { |
720 |
FPRINTF(stderr,"ERROR: (slv6) calc_matrix\n"); |
721 |
FPRINTF(stderr," Symbolic rank calculation failed, matrix may be bad.\n"); |
722 |
return mtx; |
723 |
} |
724 |
|
725 |
/* calculate the c vector and save it to the matrix */ |
726 |
if( ! calc_c(mtx, mtx_org_to_row(mtx,crow), obj) ) { |
727 |
s->calc_ok = FALSE; /* error in diffs ! */ |
728 |
FPRINTF(stderr,"ERROR: (slv6) calc_matrix\n"); |
729 |
FPRINTF(stderr," Error in calculating objective coefficients.\n"); |
730 |
mtx_destroy(mtx); /* commit suicide */ |
731 |
destroy_array(rhs_orig); /* clean up house, then die */ |
732 |
return NULL; |
733 |
} |
734 |
|
735 |
s->block.jactime = tm_cpu_time() - time0; /* set overall jacobian time */ |
736 |
|
737 |
return mtx; |
738 |
} |
739 |
|
740 |
|
741 |
static void real_rhs(mtx_matrix_t Ac_mtx, /* Matrix representation of problem */ |
742 |
char relopcol[], /* is it incident? */ |
743 |
struct var_variable **vlist, /* Variable list (NULL terminated) */ |
744 |
int32 rused, /* in: total number of relations used */ |
745 |
real64 rhs[]) /* out: rhs array origin */ |
746 |
/** |
747 |
*** Takes the residuals stored in rhs, and converts them into the actual right |
748 |
*** hand sides we want. |
749 |
*** |
750 |
*** Note: the residual stored in the rhs array is not the real right hand side. |
751 |
*** The residual returned by the diffs call is just the value of |
752 |
** (lhs expr) - (rhs expr) |
753 |
*** we want the residual excluding the current variables. At the moment there isn't a |
754 |
*** clean way to do this. It will be calculated in the real_rhs routine. This routine |
755 |
*** will take for each relation: |
756 |
*** sum(i, (Jacobian value var[i])*(Variable value var[i])) - rhs[i] |
757 |
*** which is the real rhs. However, this will _not_ be valid for the nonlinear case. |
758 |
*** Other than this, the mps file will be the linearization of a nonlinear system at the |
759 |
*** current point. If you are adding an MINLP feature, you'll need to come up with a better way. |
760 |
*** |
761 |
**/ |
762 |
{ |
763 |
real64 a; /* value of mtx element */ |
764 |
mtx_coord_t nz; /* coordinate of row/column in A matrix */ |
765 |
mtx_range_t range; /* storage for range of A matrix, run down a column */ |
766 |
int32 currow; /* counter for current row */ |
767 |
int orgrow; /* original row number */ |
768 |
int orgcol; /* orignal col number */ |
769 |
double rowval; /* the sum of a[i]*x[i] in the row */ |
770 |
|
771 |
if(rhs == NULL) { /* a little preflight checking */ |
772 |
FPRINTF(stderr,"ERROR: (slv6) real_rhs\n"); |
773 |
FPRINTF(stderr," The routine was passed a NULL rhs pointer!\n"); |
774 |
return; |
775 |
} |
776 |
|
777 |
for(currow = 0; currow < rused; currow++) { /* loop over all rows, is _current_ column number */ |
778 |
orgrow = mtx_row_to_org(Ac_mtx, currow); |
779 |
if (relopcol[orgrow] != rel_TOK_nonincident) { /* if it is incident row */ |
780 |
|
781 |
nz.col = mtx_FIRST; /* first nonzero col */ |
782 |
nz.row = currow; /* current row */ |
783 |
rowval = 0.0; /* accumulate value here */ |
784 |
|
785 |
a = mtx_next_in_row(Ac_mtx,&nz,mtx_range(&range,0,rused)); |
786 |
|
787 |
do { orgcol = mtx_col_to_org(Ac_mtx, nz.col); |
788 |
rowval += a*var_value(*(vlist+orgcol)); |
789 |
a = mtx_next_in_row(Ac_mtx,&nz,mtx_range(&range,0,rused)); |
790 |
|
791 |
} while (nz.col != mtx_LAST); |
792 |
|
793 |
rhs[orgrow] = rowval - rhs[orgrow]; /* set real value of right hand side */ |
794 |
|
795 |
} |
796 |
} |
797 |
|
798 |
} |
799 |
|
800 |
/* _________________________________________________________________________ */ |
801 |
|
802 |
/** |
803 |
*** Routines used by presolve |
804 |
*** -------------------- |
805 |
*** insure_bounds - fix inconsistent bounds |
806 |
*** update_vlist - add vars to vlist |
807 |
*** determine_vlist - build new vlist |
808 |
**/ |
809 |
|
810 |
|
811 |
static void insure_bounds(FILE *mif,slv6_system_t sys, struct var_variable *var) |
812 |
/** |
813 |
*** Insures that the variable value is within its bounds. |
814 |
**/ |
815 |
{ |
816 |
real64 val,low,high; |
817 |
|
818 |
low = var_lower_bound(var); |
819 |
high = var_upper_bound(var); |
820 |
val = var_value(var); |
821 |
if( low > high ) { |
822 |
FPRINTF(mif,"Bounds for variable "); |
823 |
slv_print_var_name(mif,sys->slv,var); |
824 |
FPRINTF(mif," are inconsistent [%g,%g].\n",low,high); |
825 |
FPRINTF(mif,"Bounds will be swapped.\n"); |
826 |
var_set_upper_bound(var, low); |
827 |
var_set_lower_bound(var, high); |
828 |
low = var_lower_bound(var); |
829 |
high = var_upper_bound(var); |
830 |
} |
831 |
|
832 |
if( low > val ) { |
833 |
FPRINTF(mif,"Variable "); |
834 |
slv_print_var_name(mif,sys->slv,var); |
835 |
FPRINTF(mif," was initialized below its lower bound.\n"); |
836 |
FPRINTF(mif,"It will be moved to its lower bound.\n"); |
837 |
var_set_value(var, low); |
838 |
} else if( val > high ) { |
839 |
FPRINTF(mif,"Variable "); |
840 |
slv_print_var_name(mif,sys->slv,var); |
841 |
FPRINTF(mif," was initialized above its upper bound.\n"); |
842 |
FPRINTF(mif,"It will be moved to its upper bound.\n"); |
843 |
var_set_value(var, high); |
844 |
} |
845 |
} |
846 |
|
847 |
#ifndef KILL |
848 |
|
849 |
static struct var_variable **update_vlist(struct var_variable * *vlist, expr_t expr) |
850 |
/** |
851 |
*** Updates vlist, adding variables incident on given expression. The |
852 |
*** old list is destroyed and the new list is returned. |
853 |
**/ |
854 |
{ |
855 |
struct var_variable **newlist,**elist; |
856 |
long nelts; |
857 |
|
858 |
elist = expr_incidence_list(expr,NULL); |
859 |
if( vlist == NULL ) return(elist); |
860 |
if( (nelts=pl_length(elist)) == 0 ) { |
861 |
ascfree( (POINTER)elist ); |
862 |
return(vlist); |
863 |
} |
864 |
|
865 |
nelts += pl_length(vlist) + 1; |
866 |
newlist = (struct var_variable **)ascmalloc( sizeof(struct var_variable *) * (int)nelts ); |
867 |
pl_merge_0(newlist,vlist,elist); |
868 |
ascfree( (POINTER)vlist ); |
869 |
ascfree( (POINTER)elist ); |
870 |
return(newlist); |
871 |
} |
872 |
|
873 |
#endif |
874 |
|
875 |
#ifndef KILL |
876 |
|
877 |
static void determine_vlist(slv6_system_t sys) |
878 |
/** |
879 |
*** This function constructs the variable list from the relation list. It |
880 |
*** is assumed that sys->vlist_user == NULL so that this is necessary. |
881 |
**/ |
882 |
{ |
883 |
bnd_boundary_t *bp; |
884 |
struct rel_relation **rp; |
885 |
|
886 |
if( pl_length(sys->vlist) > 0 ) |
887 |
ascfree( (POINTER)sys->vlist ); |
888 |
sys->vlist = NULL; |
889 |
for( bp=sys->blist ; *bp != NULL ; ++bp ) { |
890 |
sys->vlist = update_vlist(sys->vlist,bnd_lhs(*bp)); |
891 |
sys->vlist = update_vlist(sys->vlist,bnd_rhs(*bp)); |
892 |
} |
893 |
for( rp=sys->rlist ; *rp != NULL ; ++rp ) { |
894 |
sys->vlist = update_vlist(sys->vlist,rel_lhs(*rp)); |
895 |
sys->vlist = update_vlist(sys->vlist,rel_rhs(*rp)); |
896 |
} |
897 |
if( sys->obj ) |
898 |
sys->vlist = update_vlist(sys->vlist,sys->obj); |
899 |
|
900 |
if( sys->vlist == NULL ) |
901 |
slv6_set_var_list(sys,NULL); |
902 |
} |
903 |
|
904 |
#endif |
905 |
|
906 |
/* _________________________________________________________________________ */ |
907 |
|
908 |
/** |
909 |
*** External routines used from slv0 without modificiation |
910 |
*** |
911 |
*** slv6_set_var_list(sys,vlist) |
912 |
*** slv6_get_var_list(sys) |
913 |
*** slv6_set_bnd_list(sys,blist) |
914 |
*** slv6_get_bnd_list(sys) |
915 |
*** slv6_set_rel_list(sys,rlist) |
916 |
*** slv6_get_rel_list(sys) |
917 |
*** slv6_set_extrel_list(sys,erlist) |
918 |
*** slv6_get_extrel_list(sys) |
919 |
*** slv6_count_vars(sys,vfilter) |
920 |
*** slv6_count_bnds(sys,bfilter) |
921 |
*** slv6_count_rels(sys,rfilter) |
922 |
*** slv6_set_obj_function(sys,obj) |
923 |
*** slv6_get_obj_function(sys) |
924 |
*** slv6_get_parameters(sys,parameters) |
925 |
*** slv6_set_parameters(sys,parameters) |
926 |
*** slv6_get_status(sys,status) |
927 |
*** slv6_dump_internals(sys,level) |
928 |
**/ |
929 |
|
930 |
|
931 |
void slv6_set_var_list(sys,vlist) |
932 |
slv6_system_t sys; |
933 |
struct var_variable **vlist; |
934 |
{ |
935 |
static struct var_variable *empty_list[] = {NULL}; |
936 |
check_system(sys); |
937 |
if( sys->vlist_user == NULL ) |
938 |
if( sys->vlist != NULL && pl_length(sys->vlist) > 0 ) |
939 |
ascfree( (POINTER)(sys->vlist) ); |
940 |
sys->vlist_user = vlist; |
941 |
sys->vlist = (vlist==NULL ? empty_list : vlist); |
942 |
sys->s.ready_to_solve = FALSE; |
943 |
} |
944 |
|
945 |
struct var_variable **slv6_get_var_list(sys) |
946 |
slv6_system_t sys; |
947 |
{ |
948 |
check_system(sys); |
949 |
return( sys->vlist_user ); |
950 |
} |
951 |
|
952 |
void slv6_set_bnd_list(sys,blist) |
953 |
slv6_system_t sys; |
954 |
bnd_boundary_t *blist; |
955 |
{ |
956 |
static bnd_boundary_t empty_list[] = {NULL}; |
957 |
check_system(sys); |
958 |
sys->blist_user = blist; |
959 |
sys->blist = (blist==NULL ? empty_list : blist); |
960 |
sys->s.ready_to_solve = FALSE; |
961 |
} |
962 |
|
963 |
bnd_boundary_t *slv6_get_bnd_list(sys) |
964 |
slv6_system_t sys; |
965 |
{ |
966 |
check_system(sys); |
967 |
return( sys->blist_user ); |
968 |
} |
969 |
|
970 |
void slv6_set_rel_list(sys,rlist) |
971 |
slv6_system_t sys; |
972 |
struct rel_relation **rlist; |
973 |
{ |
974 |
static struct rel_relation *empty_list[] = {NULL}; |
975 |
check_system(sys); |
976 |
sys->rlist_user = rlist; |
977 |
sys->rlist = (rlist==NULL ? empty_list : rlist); |
978 |
sys->s.ready_to_solve = FALSE; |
979 |
} |
980 |
|
981 |
struct rel_relation **slv6_get_rel_list(sys) |
982 |
slv6_system_t sys; |
983 |
{ |
984 |
check_system(sys); |
985 |
return( sys->rlist_user ); |
986 |
} |
987 |
|
988 |
void slv6_set_extrel_list(sys,erlist) |
989 |
slv6_system_t sys; |
990 |
struct ExtRelCache **erlist; |
991 |
{ |
992 |
static struct ExtRelCache *empty_list[] = {NULL}; |
993 |
check_system(sys); |
994 |
sys->erlist_user = erlist; |
995 |
sys->erlist = (erlist==NULL ? empty_list : erlist); |
996 |
sys->s.ready_to_solve = FALSE; |
997 |
} |
998 |
|
999 |
struct ExtRelCache **slv6_get_extrel_list(sys) |
1000 |
slv6_system_t sys; |
1001 |
{ |
1002 |
check_system(sys); |
1003 |
return( sys->erlist_user ); |
1004 |
} |
1005 |
|
1006 |
int slv6_count_vars(sys,vfilter) |
1007 |
slv6_system_t sys; |
1008 |
var_filter_t *vfilter; |
1009 |
{ |
1010 |
struct var_variable **vp; |
1011 |
int32 count = 0; |
1012 |
check_system(sys); |
1013 |
for( vp=sys->vlist; *vp != NULL; vp++ ) |
1014 |
if( var_apply_filter(*vp,vfilter) ) ++count; |
1015 |
return( count ); |
1016 |
} |
1017 |
|
1018 |
int slv6_count_bnds(sys,bfilter) |
1019 |
slv6_system_t sys; |
1020 |
bnd_filter_t *bfilter; |
1021 |
{ |
1022 |
bnd_boundary_t *bp; |
1023 |
int32 count = 0; |
1024 |
check_system(sys); |
1025 |
for( bp=sys->blist; *bp != NULL; bp++ ) |
1026 |
if( bnd_apply_filter(*bp,bfilter) ) ++count; |
1027 |
return( count ); |
1028 |
} |
1029 |
|
1030 |
int slv6_count_rels(sys,rfilter) |
1031 |
slv6_system_t sys; |
1032 |
rel_filter_t *rfilter; |
1033 |
{ |
1034 |
struct rel_relation **rp; |
1035 |
int32 count = 0; |
1036 |
check_system(sys); |
1037 |
for( rp=sys->rlist; *rp != NULL; rp++ ) |
1038 |
if( rel_apply_filter(*rp,rfilter) ) ++count; |
1039 |
return( count ); |
1040 |
} |
1041 |
|
1042 |
void slv6_set_obj_relation(slv6_system_t sys,struct rel_relation *obj) |
1043 |
{ |
1044 |
check_system(sys); |
1045 |
sys->obj = obj; |
1046 |
sys->s.ready_to_solve = FALSE; |
1047 |
} |
1048 |
|
1049 |
struct rel_relation *slv6_get_obj_relation(slv6_system_t sys) |
1050 |
{ |
1051 |
check_system(sys); |
1052 |
return(sys->obj); |
1053 |
} |
1054 |
|
1055 |
void slv6_get_parameters(sys,parameters) |
1056 |
slv6_system_t sys; |
1057 |
slv_parameters_t *parameters; |
1058 |
{ |
1059 |
check_system(sys); |
1060 |
mem_copy_cast(&(sys->p),parameters,sizeof(slv_parameters_t)); |
1061 |
} |
1062 |
|
1063 |
void slv6_set_parameters(sys,parameters) |
1064 |
slv6_system_t sys; |
1065 |
slv_parameters_t *parameters; |
1066 |
{ |
1067 |
check_system(sys); |
1068 |
if (parameters->whose==slv6_solver_number) |
1069 |
mem_copy_cast(parameters,&(sys->p),sizeof(slv_parameters_t)); |
1070 |
} |
1071 |
|
1072 |
void slv6_get_status(sys,status) |
1073 |
slv6_system_t sys; |
1074 |
slv_status_t *status; |
1075 |
{ |
1076 |
check_system(sys); |
1077 |
mem_copy_cast(&(sys->s),status,sizeof(slv_status_t)); |
1078 |
} |
1079 |
|
1080 |
void slv6_dump_internals(sys,level) |
1081 |
slv6_system_t sys; |
1082 |
int level; |
1083 |
{ |
1084 |
check_system(sys); |
1085 |
if (level > 0) { |
1086 |
FPRINTF(stderr,"ERROR: (slv6) slv6_dump_internals\n"); |
1087 |
FPRINTF(stderr," slv6 does not dump its internals.\n"); |
1088 |
} |
1089 |
} |
1090 |
|
1091 |
|
1092 |
/* _________________________________________________________________________ */ |
1093 |
|
1094 |
/** |
1095 |
*** External routines with minor modifications |
1096 |
*** ----------------- |
1097 |
*** slv6_get_linsol_sys(sys) just returns NULL & error msg |
1098 |
*** slv6_change_basis just return FALSE & error msg |
1099 |
**/ |
1100 |
|
1101 |
|
1102 |
linsol_system_t slv6_get_linsol_sys(sys) /* just returns NULL & error msg */ |
1103 |
slv6_system_t sys; |
1104 |
{ |
1105 |
|
1106 |
/* In the MPS file maker, there is no linsol_sys to return. |
1107 |
So I just write out an error message, and return a NULL pointer */ |
1108 |
|
1109 |
FPRINTF(stderr,"ERROR: (slv6) slv6_change_basis\n"); |
1110 |
FPRINTF(stderr," This solver does not support changing the basis.\n"); |
1111 |
|
1112 |
return NULL; |
1113 |
} |
1114 |
|
1115 |
|
1116 |
boolean slv6_change_basis(slv6_system_t sys,int32 var, mtx_range_t *rng){ |
1117 |
|
1118 |
/* In the MPS file maker, changing the basis doesn't make any sense. |
1119 |
Nor, for that matter, is there a basis in the first place. |
1120 |
So I just write out an error message, and return FALSE */ |
1121 |
|
1122 |
FPRINTF(stderr,"ERROR: (slv6) slv6_change_basis\n"); |
1123 |
FPRINTF(stderr," This solver does not support changing the basis.\n"); |
1124 |
|
1125 |
return FALSE; |
1126 |
} |
1127 |
|
1128 |
|
1129 |
/* _________________________________________________________________________ */ |
1130 |
|
1131 |
/** |
1132 |
*** External routines unique to slv6 (Based on routines from slv0) |
1133 |
*** ----------------- |
1134 |
*** slv6_create() added solver specific initialization |
1135 |
*** slv6_destroy(sys) added solver specific dealocation |
1136 |
*** slv6_eligible_solver(sys) see if solver can do the current problem |
1137 |
*** slv6_presolve(sys) set up system and create matrix/vectors |
1138 |
*** slv6_solve(sys) call MPS routines |
1139 |
*** slv6_iterate(sys) just calls slv6_solve |
1140 |
*** slv6_resolve(sys) just calls slv6_solve |
1141 |
**/ |
1142 |
|
1143 |
|
1144 |
slv6_system_t slv6_create() /* added mps initialization */ |
1145 |
{ |
1146 |
slv6_system_t sys; |
1147 |
|
1148 |
/*** This routine allocates memory and initializes all data structures |
1149 |
*** It should be a good source of comments on the system parameters and |
1150 |
*** status flags used in slv6 |
1151 |
**/ |
1152 |
|
1153 |
/*** Allocate main system memory ***/ |
1154 |
|
1155 |
sys = (slv6_system_t)ascmalloc( sizeof(struct slv6_system_structure) ); |
1156 |
mem_zero_byte_cast(sys,0,sizeof(struct slv6_system_structure)); |
1157 |
sys->integrity = OK; |
1158 |
|
1159 |
|
1160 |
/*** Initialize system parameters ***/ |
1161 |
|
1162 |
sys->p.output.more_important = stdout; /* used in MIF macro */ |
1163 |
sys->p.output.less_important = NULL; /* used in LIF macro (which is not used) */ |
1164 |
|
1165 |
sys->p.tolerance.pivot = 0.1; /* these tolerances are never used */ |
1166 |
sys->p.tolerance.singular = 1e-12; |
1167 |
sys->p.tolerance.feasible = 1e-8; |
1168 |
sys->p.tolerance.stationary = 1e-8; |
1169 |
sys->p.tolerance.termination = 1e-12; |
1170 |
sys->p.time_limit = 1500.0; /* never used */ |
1171 |
sys->p.iteration_limit = 100; /* never used */ |
1172 |
sys->p.partition = FALSE; /* never used, but don't want partitioning */ |
1173 |
sys->p.ignore_bounds = FALSE; /* never used, but must satisfy bounds */ |
1174 |
sys->p.whose = slv6_solver_number; /* read in slv6_set_parameters */ |
1175 |
sys->p.rho = 1.0; |
1176 |
sys->p.sp.iap=&(sys->iarray[0]); /* all defaults in iarray are 0 */ |
1177 |
sys->p.sp.rap=&(sys->rarray[0]); /* all defaults in rarray are 0 */ |
1178 |
sys->p.sp.cap=&(sys->carray[0]); /* all defaults in carray are NULL */ |
1179 |
sys->p.sp.vap=NULL; /* not currently used */ |
1180 |
|
1181 |
|
1182 |
/*** Initialize mps data structure ***/ |
1183 |
|
1184 |
sys->mps.Ac_mtx = NULL; /* set all pointers to NULL - will all be set in presolve */ |
1185 |
sys->mps.lbrow = NULL; /* all other data in mps structure is 0 */ |
1186 |
sys->mps.ubrow = NULL; |
1187 |
sys->mps.bcol = NULL; |
1188 |
sys->mps.typerow = NULL; |
1189 |
sys->mps.relopcol = NULL; |
1190 |
|
1191 |
|
1192 |
/*** Initialize status flags ***/ |
1193 |
|
1194 |
sys->s.over_defined = FALSE; /* set to (sys->mps.rinc > sys->mps.vinc) in slv6_presolve */ |
1195 |
sys->s.under_defined = FALSE; /* set to (sys->mps.rinc < sys->mps.vinc) in slv6_presolve */ |
1196 |
sys->s.struct_singular = FALSE; /* set to (sys->mps.rank < sys->mps.rinc) in slv6_presolve */ |
1197 |
sys->s.calc_ok = TRUE; /* set in calc_matrix (FALSE if error occurs with diffs calc) */ |
1198 |
sys->s.ok = TRUE; /* set to (sys->s.calc_ok && !sys->s.struct_singular) in slv6_presolve */ |
1199 |
sys->s.ready_to_solve = FALSE; /* set to (sys->.ok) after slv6_presolve, |
1200 |
set FALSE after: slv6_set_var_list, slv6_set_bnd_list, |
1201 |
slv6_set_rel_list, slv6_set_extrel_list, slv6_set_obj_function |
1202 |
tested in slv6_solve */ |
1203 |
sys->s.converged = FALSE; /* set FALSE after slv6_presolve; set TRUE after slv6_solve */ |
1204 |
sys->s.diverged = FALSE; /* always FALSE, never used */ |
1205 |
sys->s.inconsistent = FALSE; /* always FALSE, never used */ |
1206 |
sys->s.iteration_limit_exceeded = FALSE; /* always FALSE, never used */ |
1207 |
sys->s.time_limit_exceeded = FALSE; /* always FALSE, never used */ |
1208 |
|
1209 |
sys->s.block.number_of = 1; /* always 1, just have 1 block */ |
1210 |
sys->s.block.current_block = 0; /* always 1, start in first and only block */ |
1211 |
sys->s.block.current_size = 0; /* set to sys->mps.vused in slv6_presolve */ |
1212 |
sys->s.block.previous_total_size = 0; /* always 0, never used */ |
1213 |
|
1214 |
/* same : */ |
1215 |
sys->s.block.iteration = 0; /* set to 0 after slv6_presolve; set to 1 after slv6_solve */ |
1216 |
sys->s.iteration = 0; /* set to 0 after slv6_presolve; set to 1 after slv6_solve */ |
1217 |
|
1218 |
/* same : */ |
1219 |
sys->s.block.cpu_elapsed = 0.0; /* set to time taken by slv6_presolve and slv6_solve */ |
1220 |
sys->s.cpu_elapsed = 0.0; /* set to time taken by slv6_presolve and slv6_solve */ |
1221 |
|
1222 |
sys->s.block.functime = 0.0; /* always 0.0 since no function evaluation, never used */ |
1223 |
sys->s.block.residual = 0.0; /* always 0.0 since not iterating, never used */ |
1224 |
sys->s.block.jactime = 0.0; /* calculated in slv6_presolve, time for jacobian eval */ |
1225 |
|
1226 |
sys->s.costsize = sys->s.block.number_of; /* just one cost block, which will be set in */ |
1227 |
|
1228 |
sys->s.cost=create_zero_array(sys->s.costsize,struct slv_block_cost); /* allocate memory */ |
1229 |
|
1230 |
|
1231 |
/* Note: the cost vars are equivalent to other sys->s.* vars |
1232 |
|
1233 |
sys->s.cost->size = sys->s.block.current_size |
1234 |
sys->s.cost->iterations = sys->s.block.iteration |
1235 |
sys->s.cost->jacs = sys->s.block.iteration |
1236 |
sys->s.cost->funcs = always 0 since no function evals needed |
1237 |
sys->s.cost->time = sys->s.block.cpu_elapsed |
1238 |
sys->s.cost->resid = 0.0 whatever this is ? |
1239 |
sys->s.cost->functime = 0.0 since no function evals needed |
1240 |
sys->s.cost->jactime = sys->s.block.jactime |
1241 |
|
1242 |
*/ |
1243 |
|
1244 |
return(sys); |
1245 |
} |
1246 |
|
1247 |
|
1248 |
int slv6_destroy(sys) |
1249 |
slv6_system_t sys; |
1250 |
{ |
1251 |
int i; |
1252 |
|
1253 |
if (check_system(sys)) return 1; |
1254 |
slv6_set_var_list(sys,(struct var_variable **)NULL); |
1255 |
slv6_set_obj_function(sys,NULL); |
1256 |
slv6_set_bnd_list(sys,NULL); |
1257 |
slv6_set_rel_list(sys,NULL); |
1258 |
slv6_set_extrel_list(sys,NULL); |
1259 |
sys->integrity = DESTROYED; |
1260 |
if (sys->s.cost) ascfree(sys->s.cost); /* deallocate cost array */ |
1261 |
|
1262 |
/* deallocate strings here */ |
1263 |
for (i=0; i< slv6_CA_SIZE; i++) { |
1264 |
if (sys->p.sp.cap[i] != NULL) ascfree(sys->p.sp.cap[i]); /* deallocate old, if any */ |
1265 |
} |
1266 |
|
1267 |
nuke_pointers(sys->mps); /* free memory, and set all pointers to NULL */ |
1268 |
ascfree( (POINTER)sys ); |
1269 |
|
1270 |
|
1271 |
return 0; |
1272 |
} |
1273 |
|
1274 |
|
1275 |
boolean slv6_eligible_solver(sys) |
1276 |
|
1277 |
/*** The system must have a relation list and objective before |
1278 |
*** slv6_eligible_solver will return true |
1279 |
**/ |
1280 |
|
1281 |
slv6_system_t sys; |
1282 |
{ |
1283 |
struct rel_relation **rp; |
1284 |
var_filter_t vfilter; |
1285 |
|
1286 |
check_system(sys); |
1287 |
if( sys->rlist == NULL ) { |
1288 |
FPRINTF(stderr,"ERROR: (slv6) slv6_eligible_solver\n"); |
1289 |
FPRINTF(stderr," Relation list was never set.\n"); |
1290 |
return (FALSE); |
1291 |
} |
1292 |
if( sys->obj == NULL ) { |
1293 |
FPRINTF(stderr,"ERROR: (slv6) slv6_eligible_solver\n"); |
1294 |
FPRINTF(stderr," No objective in problem.\n"); |
1295 |
return (FALSE); |
1296 |
} |
1297 |
|
1298 |
/* To Do: External Relations are currently being ingored. Is that proper? |
1299 |
What if they're nonlinear */ |
1300 |
|
1301 |
vfilter.matchbits = (VAR_FIXED | VAR_INCIDENT | VAR_ACTIVE); |
1302 |
vfilter.matchvalue = (VAR_INCIDENT | VAR_ACTIVE); |
1303 |
/* |
1304 |
vfilter.fixed = var_false; |
1305 |
vfilter.incident = var_true; |
1306 |
vfilter.in_block = var_ignore; */ |
1307 |
|
1308 |
/* Check that the system is linear if iarray[SP6_NONLIN] == 0 */ |
1309 |
if (sys->iarray[SP6_NONLIN] == 0){ |
1310 |
for( rp=sys->rlist ; *rp != NULL ; ++rp ) /* check relations */ |
1311 |
if(!relman_is_linear(*rp,&vfilter)) { |
1312 |
FPRINTF(MIF(sys), "ERROR: With the current settings, the MPS generator can only\n"); |
1313 |
FPRINTF(MIF(sys), " handle linear models. Nonlinearity in constraint:\n"); |
1314 |
slv_print_rel_name(MIF(sys),sys->slv, *rp); |
1315 |
return(FALSE); /* don't do nonlinearities */ |
1316 |
} |
1317 |
#ifndef KILL |
1318 |
if (!exprman_is_linear(sys->obj,&vfilter)){ |
1319 |
FPRINTF(MIF(sys), "ERROR: With the current settings, the MPS generator can only\n"); |
1320 |
FPRINTF(MIF(sys), " handle linear models. Nonlinearity in objective.\n"); |
1321 |
return(FALSE); /* don't do nonlinearities */ |
1322 |
} |
1323 |
#else |
1324 |
FPRINTF(stderr," function slv6_elegible_solver is slv6 is broken.\n"); |
1325 |
FPRINTF(stderr," It calls exprman_is_linear with wrong number of args.\n"); |
1326 |
exit; |
1327 |
#endif |
1328 |
} |
1329 |
|
1330 |
/* Note: initially I had this routine check to see if solver could handle |
1331 |
binary, integer, semicontinuous, etc. Now I just convert types automatically. |
1332 |
Binary vars become integer vars if a solver can do int but not binary. |
1333 |
Semicontinuous vars become regular solver vars, with warnings about the |
1334 |
conversion. If it can't handle integer vars, they are treated as regular |
1335 |
solver vars, with warnings. |
1336 |
|
1337 |
These conversions take place in the MPS.c file.*/ |
1338 |
|
1339 |
return TRUE; |
1340 |
} |
1341 |
|
1342 |
void slv6_presolve(sys) |
1343 |
slv6_system_t sys; |
1344 |
{ |
1345 |
struct var_variable **vp; |
1346 |
struct rel_relation **rp; |
1347 |
bnd_boundary_t *bp; |
1348 |
int32 cap; |
1349 |
|
1350 |
bnd_filter_t bfilter; |
1351 |
|
1352 |
/* Check if necessary pointers are non-NULL */ |
1353 |
check_system(sys); |
1354 |
if( sys->vlist == NULL ) { |
1355 |
FPRINTF(stderr,"ERROR: (slv6) slv6_presolve\n"); |
1356 |
FPRINTF(stderr," Variable list was never set.\n"); |
1357 |
return; |
1358 |
} |
1359 |
if( sys->blist == NULL ) { |
1360 |
FPRINTF(stderr,"ERROR: (slv6) slv6_presolve\n"); |
1361 |
FPRINTF(stderr," Boundary list was never set.\n"); |
1362 |
return; |
1363 |
} |
1364 |
if( sys->rlist == NULL ) { |
1365 |
FPRINTF(stderr,"ERROR: (slv6) slv6_presolve\n"); |
1366 |
FPRINTF(stderr," Relation list was never set.\n"); |
1367 |
return; |
1368 |
} |
1369 |
|
1370 |
/* time presolve */ |
1371 |
sys->clock = tm_cpu_time(); /* record start time */ |
1372 |
|
1373 |
/* set up vlist, if necessary, and set all vars, rels, and boundary's |
1374 |
to being nonincident, set up index scheme */ |
1375 |
|
1376 |
#ifndef KILL |
1377 |
if( sys->vlist_user == NULL ) determine_vlist(sys); |
1378 |
#else |
1379 |
if( sys->vlist_user == NULL ){ |
1380 |
FPRINTF(stderr," function determine_vlist is slv6 is broken.\n"); |
1381 |
exit; |
1382 |
} |
1383 |
#endif |
1384 |
sys->mps.cap = 0; |
1385 |
for( vp=sys->vlist,cap=0 ; *vp != NULL ; ++vp ) { |
1386 |
var_set_sindex(*vp,cap++); |
1387 |
var_set_in_block(*vp,FALSE); |
1388 |
} |
1389 |
sys->mps.cap = cap; |
1390 |
for( rp=sys->rlist,cap=0 ; *rp != NULL ; ++rp ) { |
1391 |
rel_set_index(*rp,cap++); |
1392 |
rel_set_in_block(*rp,FALSE); |
1393 |
rel_set_satisfied(*rp,FALSE); |
1394 |
} |
1395 |
sys->mps.cap = MAX(sys->mps.cap,cap+1); /* allow an extra relation for crow, |
1396 |
cap = N --> row/col 0 to N-1 exist */ |
1397 |
for( bp = sys->blist ; *bp != NULL ; ++bp ) { |
1398 |
bnd_set_in_block(*bp,FALSE); |
1399 |
bnd_set_active(*bp,FALSE); |
1400 |
} |
1401 |
|
1402 |
/** |
1403 |
*** Now mark all variables appearing in the objective function, |
1404 |
*** the boundaries and the relations as incident. |
1405 |
**/ |
1406 |
|
1407 |
/* Mark all variables appearing in the objective function as incident */ |
1408 |
if( sys->obj ) exprman_decide_incidence_obj(sys->obj); |
1409 |
|
1410 |
/* Set incidence of included vars in included bounds, calc bused, set all bounds inactive */ |
1411 |
sys->mps.bused = 0; |
1412 |
bfilter.included = bnd_true; |
1413 |
bfilter.in_block = bnd_ignore; |
1414 |
for( bp = sys->blist ; *bp != NULL ; bp++ ) { |
1415 |
if( bnd_apply_filter(*bp,&bfilter) ) { |
1416 |
bndman_decide_incidence(*bp); /* mark incident variables */ |
1417 |
sys->mps.bused++; |
1418 |
} |
1419 |
} |
1420 |
|
1421 |
/* Count the incident relations in rused */ |
1422 |
sys->mps.rused = 0; |
1423 |
sys->mps.rinc = 0; |
1424 |
for( rp = sys->rlist ; *rp != NULL ; rp++ ) { |
1425 |
rel_set_satisfied(*rp,FALSE); |
1426 |
if( inc_rel_filter(*rp) ) { |
1427 |
relman_decide_incidence(*rp); /* mark incident variables in included rels */ |
1428 |
sys->mps.rinc++; |
1429 |
} |
1430 |
sys->mps.rused++; |
1431 |
} |
1432 |
|
1433 |
/* compute info for variables */ |
1434 |
sys->mps.vused = 0; /* number starting at 0 */ |
1435 |
sys->mps.vinc = 0; |
1436 |
for( vp = sys->vlist ; *vp != NULL ; vp++ ) { |
1437 |
if( free_inc_var_filter(*vp) ) |
1438 |
sys->mps.vinc++; |
1439 |
sys->mps.vused++; /* count up incident, non-fixed vars */ |
1440 |
} |
1441 |
|
1442 |
/* calculate values for other index_mps_t vars */ |
1443 |
sys->mps.crow = sys->mps.rused; /* note rused = N means rows 0 to N-1, exist, |
1444 |
the next one will be numbered rused */ |
1445 |
/* calculate rank later */ |
1446 |
|
1447 |
/* Call slv6_elgibile_solver to see if the solver has a chance */ |
1448 |
/* If not bail now ... requires the incidence values of prev section be set */ |
1449 |
if(! slv6_eligible_solver(sys)) return; |
1450 |
|
1451 |
/* Make sure that at least one incident variable and at least one incident |
1452 |
relation exist, else bail */ |
1453 |
if ((sys->mps.rinc == 0) || (sys->mps.vinc == 0)) { |
1454 |
FPRINTF(stderr,"ERROR: (slv6) slv6_presolve\n"); |
1455 |
FPRINTF(stderr," Your model must have at least one incident variable and equation.\n"); |
1456 |
FPRINTF(stderr," Incident variables: %d\n", sys->mps.vinc); |
1457 |
FPRINTF(stderr," Incident equations: %d\n", sys->mps.rinc); |
1458 |
return; |
1459 |
} |
1460 |
|
1461 |
/* free memory, and set all pointers to NULL */ |
1462 |
nuke_pointers(sys->mps); |
1463 |
|
1464 |
/* setup matrix representaion of problem */ |
1465 |
sys->mps.Ac_mtx = calc_matrix(sys->mps.cap, |
1466 |
sys->mps.rused, |
1467 |
sys->mps.vused, |
1468 |
sys->rlist, |
1469 |
sys->obj, |
1470 |
sys->mps.crow, |
1471 |
&sys->s, /* how long for the jacobian calcs and any errors */ |
1472 |
&sys->mps.rank, |
1473 |
&sys->mps.bcol); |
1474 |
if( sys->mps.Ac_mtx == NULL ) { |
1475 |
FPRINTF(stderr,"ERROR: (slv6) slv6_presolve\n"); |
1476 |
FPRINTF(stderr," Call to calc_matrix failed.\n"); |
1477 |
nuke_pointers(sys->mps); |
1478 |
return; |
1479 |
} |
1480 |
|
1481 |
/* get upper bound row */ |
1482 |
sys->mps.ubrow = calc_bounds(sys->vlist, sys->mps.vinc, TRUE); |
1483 |
if (sys->mps.ubrow == NULL) { |
1484 |
FPRINTF(stderr,"ERROR: (slv6) slv6_presolve\n"); |
1485 |
FPRINTF(stderr," Error in calculating variable upper bounds.\n"); |
1486 |
nuke_pointers(sys->mps); |
1487 |
return; |
1488 |
} |
1489 |
|
1490 |
/* get lower bound row */ |
1491 |
sys->mps.lbrow = calc_bounds(sys->vlist, sys->mps.vinc, FALSE); |
1492 |
if (sys->mps.lbrow == NULL) { |
1493 |
FPRINTF(stderr,"ERROR: (slv6) slv6_presolve\n"); |
1494 |
FPRINTF(stderr," Error in calculating variable lower bounds.\n"); |
1495 |
nuke_pointers(sys->mps); |
1496 |
return; |
1497 |
} |
1498 |
|
1499 |
/* Call calc_svtlist to allocate array of variable types */ |
1500 |
sys->mps.typerow = calc_svtlist(sys->vlist, |
1501 |
sys->mps.vinc, |
1502 |
&sys->mps.solver_var_used, /* output */ |
1503 |
&sys->mps.solver_relaxed_used, /* output */ |
1504 |
&sys->mps.solver_int_used, /* output */ |
1505 |
&sys->mps.solver_binary_used, /* output */ |
1506 |
&sys->mps.solver_semi_used, /* output */ |
1507 |
&sys->mps.solver_other_used, /* output */ |
1508 |
&sys->mps.solver_fixed); /* output */ |
1509 |
if(sys->mps.typerow == NULL) { /* allocation failed */ |
1510 |
FPRINTF(stderr,"ERROR: (slv6) slv6_presolve\n"); |
1511 |
FPRINTF(stderr," Error in calculating the variable type list!\n"); |
1512 |
nuke_pointers(sys->mps); |
1513 |
return; |
1514 |
} |
1515 |
|
1516 |
/* Call calc_reloplist here, to calculate the relational operators >=, <=, = */ |
1517 |
sys->mps.relopcol = calc_reloplist(sys->rlist, sys->mps.rinc); |
1518 |
if(sys->mps.relopcol == NULL) { /* allocation failed */ |
1519 |
FPRINTF(stderr,"ERROR: (slv6) slv6_presolve\n"); |
1520 |
FPRINTF(stderr," Error in calculating the relational operators!\n"); |
1521 |
nuke_pointers(sys->mps); |
1522 |
return; |
1523 |
} |
1524 |
|
1525 |
/* adjust the rhs vector so it actually contains the rhs */ |
1526 |
real_rhs(sys->mps.Ac_mtx, /* Matrix representation of problem */ |
1527 |
sys->mps.relopcol, /* is it incident? */ |
1528 |
sys->vlist, /* in: Variable list (NULL terminated) */ |
1529 |
sys->mps.rused, /* in: total number of relations used */ |
1530 |
sys->mps.bcol); /* out: rhs array origin */ |
1531 |
|
1532 |
|
1533 |
/* Call insure_bounds over all vars to make bounds self-consistent */ |
1534 |
for( vp=sys->vlist; *vp != NULL ; ++vp ) |
1535 |
insure_bounds(MIF(sys),sys, *vp); |
1536 |
|
1537 |
/* Reset status flags */ |
1538 |
sys->s.over_defined = (sys->mps.rinc > sys->mps.vinc); |
1539 |
sys->s.under_defined = (sys->mps.rinc < sys->mps.vinc); |
1540 |
sys->s.struct_singular = (sys->mps.rank < sys->mps.rinc); |
1541 |
sys->s.ok = sys->s.calc_ok && !sys->s.struct_singular; |
1542 |
sys->s.ready_to_solve = sys->s.ok; |
1543 |
|
1544 |
sys->s.converged = FALSE; /* changes to true after slv6_solve */ |
1545 |
sys->s.block.current_size = sys->mps.vused; |
1546 |
sys->s.cost->size = sys->s.block.current_size; |
1547 |
|
1548 |
sys->s.cpu_elapsed = (double)(tm_cpu_time() - sys->clock); /* record times */ |
1549 |
sys->s.block.cpu_elapsed = sys->s.cpu_elapsed; |
1550 |
sys->s.cost->time = sys->s.cpu_elapsed; |
1551 |
sys->s.cost->jactime = sys->s.block.jactime; /* from calc_matrix */ |
1552 |
|
1553 |
sys->s.block.iteration = 0; /* reset iteration "count", changes to 1 after slv6_solve */ |
1554 |
sys->s.iteration = 0; |
1555 |
sys->s.cost->iterations = 0; |
1556 |
sys->s.cost->jacs = 0; |
1557 |
|
1558 |
} |
1559 |
|
1560 |
void slv6_solve(sys) |
1561 |
slv6_system_t sys; |
1562 |
{ |
1563 |
|
1564 |
/* make sure none of the mps pointers are NULL */ |
1565 |
if ((sys->mps.Ac_mtx == NULL) || |
1566 |
(sys->mps.lbrow == NULL) || |
1567 |
(sys->mps.ubrow == NULL) || |
1568 |
(sys->mps.bcol == NULL) || |
1569 |
(sys->mps.typerow == NULL) || |
1570 |
(sys->mps.relopcol == NULL)) { |
1571 |
FPRINTF(MIF(sys),"ERROR: Matrix representation of problem is not available.\n"); |
1572 |
FPRINTF(MIF(sys)," Perhaps the presolve routine was not called before slv6_solve.\n"); |
1573 |
return; |
1574 |
} |
1575 |
|
1576 |
/* Check system to see if it can be solved */ |
1577 |
check_system(sys); |
1578 |
if( !sys->s.ready_to_solve ) { |
1579 |
FPRINTF(stderr,"ERROR: (slv6) slv6_solve\n"); |
1580 |
FPRINTF(stderr," Not ready to solve.\n"); |
1581 |
return; |
1582 |
} |
1583 |
|
1584 |
sys->clock = tm_cpu_time(); /* record start time for solve */ |
1585 |
|
1586 |
|
1587 |
/* FPRINTF(MIF(sys),"_________________________________________\n"); |
1588 |
mtx_write_region_human(MIF(sys), sys->mps.Ac_mtx, mtx_ENTIRE_MATRIX); |
1589 |
FPRINTF(MIF(sys),"_________________________________________\n"); |
1590 |
*/ |
1591 |
|
1592 |
/* Call write_mps to create the mps file */ |
1593 |
write_MPS(sys->carray[SP6_FILENAME], /* filename for output */ |
1594 |
sys->mps, /* main chunk of data */ |
1595 |
sys->iarray, /* Integer subparameters */ |
1596 |
sys->rarray); /* Real subparameters */ |
1597 |
|
1598 |
/* replace .mps with .map at end of filename */ |
1599 |
*(sys->carray[SP6_FILENAME]+strlen(sys->carray[SP6_FILENAME])-2) = 'a'; |
1600 |
*(sys->carray[SP6_FILENAME]+strlen(sys->carray[SP6_FILENAME])-1) = 'p'; |
1601 |
|
1602 |
/* writes out a file mapping the CXXXXXXX variable names with the actual ASCEND names */ |
1603 |
write_name_map(sys->carray[SP6_FILENAME], /* user-specified filename */ |
1604 |
sys->vlist); |
1605 |
|
1606 |
|
1607 |
|
1608 |
sys->s.cpu_elapsed += (double)(tm_cpu_time() - sys->clock); |
1609 |
/* compute total elapsed time */ |
1610 |
sys->s.block.cpu_elapsed = sys->s.cpu_elapsed; |
1611 |
sys->s.cost->time = sys->s.cpu_elapsed; |
1612 |
|
1613 |
sys->s.converged = TRUE; |
1614 |
sys->s.ready_to_solve = FALSE; /* !sys->s.converged */ |
1615 |
|
1616 |
sys->s.block.iteration = 1; /* change iteration "count", goes to 0 after slv6_presolve */ |
1617 |
sys->s.iteration = 1; |
1618 |
sys->s.cost->iterations = 1; |
1619 |
sys->s.cost->jacs = 1; |
1620 |
sys->s.ready_to_solve = FALSE; |
1621 |
|
1622 |
} |
1623 |
|
1624 |
|
1625 |
void slv6_iterate(sys) |
1626 |
slv6_system_t sys; |
1627 |
{ |
1628 |
/* Writing an MPS file is a one shot deal. Thus, an interation |
1629 |
is equivalent to solving the problem. So we just call |
1630 |
slv6_solve */ |
1631 |
|
1632 |
check_system(sys); |
1633 |
slv6_solve(sys); |
1634 |
|
1635 |
} |
1636 |
|
1637 |
|
1638 |
void slv6_resolve(sys) |
1639 |
slv6_system_t sys; |
1640 |
{ |
1641 |
|
1642 |
/* This routine is meant to be called when the following parts of |
1643 |
the system change: |
1644 |
- any parameter except "partition". |
1645 |
- variable values. |
1646 |
- variable nominal values. |
1647 |
- variable bounds. |
1648 |
However, if var values or bounds change, we need a new MPS file, |
1649 |
so there is no way to use the previous solution. |
1650 |
Just call slv6_solve, and do it the normal way. |
1651 |
*/ |
1652 |
|
1653 |
check_system(sys); |
1654 |
slv6_solve(sys); |
1655 |
} |
1656 |
|
1657 |
|
1658 |
int slv6_register(SlvFunctionsT *sft) |
1659 |
{ |
1660 |
if (sft==NULL) { |
1661 |
FPRINTF(stderr,"slv6_register called with NULL pointer\n"); |
1662 |
return 1; |
1663 |
} |
1664 |
|
1665 |
sft->name = "makeMPS"; |
1666 |
sft->ccreate = slv6_create; |
1667 |
sft->cdestroy = slv6_destroy; |
1668 |
sft->celigible = slv6_eligible_solver; |
1669 |
sft->getparam = slv6_get_parameters; |
1670 |
sft->setparam = slv6_set_parameters; |
1671 |
sft->getstatus = slv6_get_status; |
1672 |
sft->solve = slv6_solve; |
1673 |
sft->presolve = slv6_presolve; |
1674 |
sft->iterate = slv6_iterate; |
1675 |
sft->resolve = slv6_resolve; |
1676 |
sft->getlinsol = slv6_get_linsol_sys; |
1677 |
sft->getlinsys = slv6_get_linsolqr_sys; |
1678 |
sft->getsysmtx = slv6_get_jacobian; |
1679 |
sft->dumpinternals = slv6_dump_internals; |
1680 |
return 0; |
1681 |
} |
1682 |
#endif /* #else clause of DYNAMIC_MPS */ |
1683 |
#endif /* #else clause of !STATIC_MPS && !DYNAMIC_MPS */ |