/[ascend]/trunk/ascend4/solver/mps.c
ViewVC logotype

Contents of /trunk/ascend4/solver/mps.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations) (download) (as text)
Fri Oct 29 20:54:12 2004 UTC (17 years, 6 months ago) by aw0a
File MIME type: text/x-csrc
File size: 37084 byte(s)
Setting up web subdirectory in repository
1 /*
2 * Contents: MPS module
3 *
4 * Authors: Craig Schmidt
5 *
6 * Dates: 02/95 - Original version
7 *
8 * Description: This module will create an MPS file representation
9 * of the current system, and a file mapping
10 * variable names to MPS names.
11 *
12 * Version: $Revision: 1.13 $
13 * Version control file: $RCSfile: mps.c,v $
14 * Date last modified: $Date: 2000/01/25 02:27:03 $
15 * Last modified by: $Author: ballan $
16 *
17 * This file is part of the SLV solver.
18 * The write_MPS routine is passed a mps_data_t
19 * data structure, the solver subparameters, and the
20 * name of the file.
21 *
22 * The write_name_map routine creates a file linking the
23 * ascend name of a variable and CXXXXXXX
24 *
25 * This file is part of the SLV solver.
26 *
27 * Copyright (C) 1990 Karl Michael Westerberg
28 * Copyright (C) 1993 Joseph Zaher
29 * Copyright (C) 1994 Joseph Zaher, Benjamin Andrew Allan
30 * Copyright (C) 1995 Craig Schmidt
31 *
32 * The SLV solver is free software; you can redistribute
33 * it and/or modify it under the terms of the GNU General Public License as
34 * published by the Free Software Foundation; either version 2 of the
35 * License, or (at your option) any later version.
36 *
37 * The SLV solver is distributed in hope that it will be
38 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
39 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
40 * General Public License for more details.
41 *
42 * You should have received a copy of the GNU General Public License
43 * along with the program; if not, write to the Free Software Foundation,
44 * Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check the file named
45 * COPYING. COPYING is found in ../compiler.
46 */
47
48 /*** MPS matrix strucutre
49 *** v
50 *** min/max cx: Ax<=b u
51 *** s
52 *** e
53 *** 1 d
54 ***
55 *** | |
56 *** | |
57 *** \ / \ /
58 ***
59 *** +- -+
60 *** 1 -> | |
61 *** | |
62 *** | A |
63 *** | |
64 *** rused -> | |
65 *** +- -+
66 ***
67 *** crow -> [ c ]
68 **/
69
70 #include <time.h>
71 #include <errno.h>
72 #include "utilities/ascConfig.h"
73 #include "compiler/compiler.h"
74 #include "utilities/ascMalloc.h"
75 #include "general/list.h"
76 #include "utilities/set.h"
77 #include "general/tm_time.h"
78 #include "utilities/mem.h"
79 #include "solver/mtx.h"
80 #include "solver/slv_types.h"
81 #include "solver/var.h"
82 #include "solver/rel.h"
83 #include "solver/discrete.h"
84 #include "solver/conditional.h"
85 #include "solver/logrel.h"
86 #include "solver/bnd.h"
87 #include "solver/slv_common.h"
88 #include "solver/linsol.h"
89 #include "solver/linsolqr.h"
90 #include "solver/slv_client.h"
91 #include "solver/slv6.h"
92 #include "solver/mps.h"
93
94 #ifdef STATIC_MPS
95
96 /* _________________________________________________________________________ */
97
98 /**
99 *** Utility routines
100 *** ----------------------------
101 *** stamp - stamp file header with a unique timestamp
102 *** process_name - do tilde expansion, check for .mps or .map, etc.
103 *** open_write - open the designated file for write access
104 *** close_file - close the file
105 *** print_col_element - print either the first or second column entry
106 *** print_col - prints out a column of data from the Ac_mtx
107 **/
108
109 static void stamp(FILE *outfile, boolean newstamp, boolean dostamp, boolean dostr)
110 /**
111 *** Write a unique stamp to file, create a new one
112 *** if newstamp is true
113 **/
114 {
115 static char stampstr[26];
116 static unsigned long stamptime;
117 time_t now;
118
119 now = time(NULL);
120
121 if (newstamp) { /* generate new stamp */
122 stamptime = (unsigned long) clock();
123 sprintf(&stampstr[0], "%-26s", ctime(&now));
124 }
125
126 if (dostamp) FPRINTF(outfile,"%-8x", stamptime); /* only 8 chars for stamp in MPS, so show hex */
127 if (dostr) FPRINTF(outfile," %s", &stampstr); /* print friendlier form */
128 }
129
130 static FILE *open_write(const char *filename)
131 /**
132 *** Open file for write access, return NULL if error
133 **/
134 {
135 FILE *f;
136 errno = 0;
137 if (filename == NULL) filename = "\0"; /* shouldn't pass null to fopen */
138 f = fopen(filename, "w");
139 if( f == NULL ) {
140 FPRINTF(stderr,"ERROR: (MPS) open_write\n");
141 FPRINTF(stderr," Unable to open %s. Error:%s\n",
142 filename, strerror(errno));
143 }
144
145 return f;
146 }
147
148
149 static boolean close_file(FILE *f)
150 /**
151 *** Close file and handle errors
152 **/
153 {
154 int s = 0;
155 if(f == NULL) return TRUE; /* ignore this case */
156
157 errno = 0;
158 s = fclose(f);
159 if (s == EOF)
160 {
161 FPRINTF(stderr,"ERROR: (MPS) open_write\n");
162 perror(" Unable to close file");
163 return FALSE;
164 }
165 else
166 return TRUE;
167 }
168
169
170 /* define constants for whether this is the first or second value on the line */
171 #define ONE 0
172 #define TWO 1
173
174 static void print_col_element(FILE *out,
175 int32 var,
176 int32 rel,
177 real64 value) /* value of mtx element */
178 /**
179 *** Prints the appropriate variable and relation labels, and
180 *** the value of the element. If the the variable is different
181 *** from last call of this routine, the first column is used.
182 *** Otherwise it alternates, putting 2 values per line.
183 ***
184 *** A value of -1 for var is a special case, meaning that you just
185 *** want a newline if the last call was in the middle of a line
186 **/
187 {
188 static int32 oldvar;
189 static int onetwo; /* is it the first or second value on the line (ONE or TWO) */
190
191 /* set up state */
192
193 if (var == -1) { /* just write newline if last time were in middle of line */
194 if (onetwo == ONE)
195 FPRINTF(out,"\n");
196 return;
197 }
198
199 if (oldvar != var) { /* are at a new variable */
200 onetwo = ONE;
201 oldvar = var;
202 }
203 else
204 if (onetwo == ONE)
205 onetwo = TWO;
206 else onetwo = ONE;
207
208 /* print full names if in first col, else just the rel label */
209
210 /* Format: Field 2 Field 3 Field 4 Field 5 Field 6
211 (5-12) (15-22) (25-36) (40-47) (50-61)
212 Column Row 1 Value 1 Row 2 Value 2
213 name name name name
214 */
215
216 if (onetwo == ONE)
217
218 /* 1111 2222 3 */
219 /* 1234 2345 2345 6 */
220 FPRINTF(out," C%07d R%07d %12.6G", var, rel, value);
221 else
222 /* 3334 4445 */
223 /* 7890 7890 */
224 FPRINTF(out," R%07d %12.6G\n", rel, value);
225
226 }
227
228
229 void print_col(FILE *out, /* file */
230 mtx_matrix_t Ac_mtx, /* Matrix representation of problem */
231 char typerow[], /* array of variable type data */
232 int32 curcol, /* current column number */
233 int32 rused, /* number of relations */
234 int32 vused, /* number of vars */
235 int dointeger, /* supports integer vars */
236 int dobinary) /* supports binary vars */
237 /**
238 *** Uses print_col_element to print an entire column of the Ac_mtx
239 *** It uses the values of dointeger and dobinary to determine
240 *** if any INTORG markers are needed
241 **/
242 {
243 static boolean inBinInt = FALSE; /* are we currently in a binary or integer var region ? */
244 static int marknum = 0; /* number for marker label */
245 real64 value; /* value of mtx element */
246 mtx_coord_t nz; /* coordinate of row/column in A matrix */
247 mtx_range_t range; /* define range */
248 int32 orgcol; /* original column number */
249 char coltype; /* type of current column */
250 char nexttype; /* type of next column */
251
252 orgcol = mtx_col_to_org(Ac_mtx, curcol);
253 coltype = typerow[orgcol]; /* get cur col type */
254 if (curcol != vused-1) /* don't go beyond array limits */
255 nexttype = typerow[mtx_col_to_org(Ac_mtx, curcol+1)];
256 else
257 nexttype = 0;
258
259 if (coltype != SOLVER_FIXED) { /* only bother with incident, nonfixed variables */
260
261 /* do an INTORG marker if start of binary/integer var */
262 if ((! inBinInt) && (((coltype == SOLVER_BINARY) && (dobinary == 0)) ||
263 ((coltype == SOLVER_INT) && (dointeger == 0)))) {
264 inBinInt = TRUE; /* turn on flag */
265
266 /* 1 2 3 4 *
267 * 1234 234567890123456789012345678901234567 */
268 FPRINTF(out," M%07d 'MARKER' 'INTORG'\n", marknum);
269 }
270
271 nz.row = mtx_FIRST; /* first nonzero row */
272 nz.col = curcol; /* current col */
273
274 /* note: since mtx_FIRST = mtx_LAST, can't use a while loop */
275 value = mtx_next_in_col(Ac_mtx,&nz,mtx_range(&range,0,rused));
276 do {
277 print_col_element(out, orgcol, mtx_row_to_org(Ac_mtx, nz.row), value); /* print out a nonzero element */
278 value = mtx_next_in_col(Ac_mtx,&nz,mtx_range(&range,0,rused));
279 } while (nz.row != mtx_LAST);
280
281 print_col_element(out, -1 , 0, 0.0); /* clean up newline */
282
283 /* close marker if in last column or next type is not an int or bin */
284 if (((inBinInt) && (curcol == (vused-1))) ||
285 (inBinInt && ((nexttype != SOLVER_BINARY) && (nexttype != SOLVER_INT )))) {
286
287 inBinInt = FALSE; /* turn on flag */
288 /* 1 2 3 4 *
289 * 1234 234567890123456789012345678901234567 */
290 FPRINTF(out," E%07d 'MARKER' 'INTEND'\n", marknum++); /* advance number */
291 }
292
293 }
294
295 }
296
297 /* _________________________________________________________________________ */
298
299 /** write_name_map
300 ***
301 *** writes out a file mapping the VXXXXXXX variable names
302 *** with the actual ASCEND names
303 **/
304
305 extern boolean write_name_map(const char *name, /* filename for output */
306 struct var_variable **vlist) /* Variable list (NULL terminated) */
307 {
308 FILE *out;
309 int i;
310
311 if ((vlist == NULL) || (name == NULL)) { /* got a bad pointer */
312 FPRINTF(stderr,"ERROR: (MPS) write_name_map\n");
313 FPRINTF(stderr," Routine was passed a NULL pointer!\n");
314 return FALSE;
315 }
316
317 out = open_write(name);
318 if (out == NULL)
319 return FALSE;
320
321 FPRINTF(out,"ASCEND/MPS Variable Name Mapping\n\n");
322 FPRINTF(out,"Timestamp: ");
323 stamp(out,FALSE,TRUE,TRUE); /* use same stamp as in write_MPS, which was already called */
324 FPRINTF(out,"\n");
325 FPRINTF(out,"MPS Name ASCEND Name\n");
326 FPRINTF(out,"-------- -----------\n");
327
328 for(; *vlist != NULL ; ++vlist )
329 if( free_inc_var_filter(*vlist) )
330 {
331 FPRINTF(out,"C%07d ",var_sindex(*vlist));
332
333 /* old way: just the unqualified names */
334 /* slv_print_var_name(out,*vlist); */
335
336 /* now, from instance_io.h, the full qualified name */
337 WriteInstanceName(out, var_instance(*vlist), NULL);
338 FPRINTF(out,"\n");
339 }
340
341 return close_file(out);
342
343 }
344
345 /* _________________________________________________________________________ */
346
347 /** routines used by write_MPS
348 ***
349 *** do_name - create header NAME section
350 *** do_rows - name constraints: just needs matrix of info
351 *** scan_SOS - identify special ordered sets
352 *** do_columns - create A matrix
353 *** do_rhs - create rhs
354 *** do_bounds - create BOUNDS section
355 **/
356
357
358 /* create header */
359 static void do_name(FILE *out, /* file */
360 int obj, /* how does it know to max/min */
361 int bo, /* QOMILP style cutoff */
362 int eps, /* QOMILP style termination criteria */
363 double boval, /* value of cutoff */
364 double epsval) /* value of termination criteria */
365 {
366
367 /** Relevant options:
368 ***
369 *** sp.ia[SP6_OBJ] 0->solver assumes minimization, do nothing special
370 *** 1->solver assumes maximization, swap obj coeff for min problems
371 *** 2->solver support SCICONIC style MINIMIZE
372 *** 3->solver supports QOMILP style MAX/MIN in names section
373 ***
374 *** sp.ia[SP6_BO] 0->no support
375 *** 1->solver supports QOMILP style BO cutoff bound in names section
376 *** Note: value of bound is in sp.ra[SP6_BNDVAL]
377 *** sp.ia[SP6_EPS] 0->no support
378 *** 1->solver supports QOMILP style EPS termination criterion
379 *** Note: value of bound is in sp.ra[SP6_EPSVAL]
380 ***
381 *** sp.ra[SP6_BOVAL] value of QOMILP style BO cutoff bound in names section
382 *** Note: Ignored if sp.ia[SP6_BO]=0
383 *** sp.ra[SP6_EPSVAL] value of QOMILP style EPS termination criterion
384 *** Note: Ignored if sp.ia[SP6_EPS]=0
385 **/
386
387 /* Note: ASCEND assumes we're _minimizing_ the objective */
388 /* Name can only be 8 characters, so display number in hex */
389
390 switch (obj) {
391 case 0:
392 case 1: /* general case: Ok for CPLEXl, OSL, lpsolve */
393 FPRINTF(out,"NAME ");
394 stamp(out,TRUE,TRUE,FALSE); /* create new timestamp, name map comes later */
395 FPRINTF(out,"\n");
396 break;
397
398 case 2: /* with SCIONIC use MINIMISE */
399 FPRINTF(out,"NAME ");
400 stamp(out,TRUE,TRUE,FALSE); /* create new timestamp, name map comes later */
401 FPRINTF(out,"MINIMISE\n"); /* British spelling */
402 break;
403
404 case 3: /* with QOMILP use MIN */
405 FPRINTF(out,"NAME ");
406 stamp(out,TRUE,TRUE,TRUE); /* create new timestamp, name map comes later */
407 FPRINTF(out,"\n");
408 FPRINTF(out," MIN\n"); /* optimization direction */
409 break;
410
411 default: FPRINTF(stderr,"ERROR: (MPS) do_name\n");
412 FPRINTF(stderr," Unknown option for objective!\n");
413 }
414
415 if (bo == 1)
416 FPRINTF(out," BO %12.8f\n", boval); /* Numbers in 25-36 for QOMILP */
417
418 if (eps == 1)
419 FPRINTF(out," EPS %12.2f\n", epsval);
420
421 }
422
423
424 static void do_rows(FILE *out, /* file */
425 char relopcol[], /* array of data */
426 int32 rused) /* size of array */
427 {
428 int i;
429
430 FPRINTF(out,"ROWS\n"); /* section header */
431
432 for (i = 0; i < rused; i++)
433 switch (relopcol[i]) {
434 case rel_TOK_less: FPRINTF(out," L R%07d\n", i);
435 break;
436 case rel_TOK_equal: FPRINTF(out," E R%07d\n", i);
437 break;
438 case rel_TOK_greater: FPRINTF(out," G R%07d\n", i);
439 break;
440 case rel_TOK_nonincident: break;
441
442 default: FPRINTF(stderr,"ERROR: (MPS) do_rows\n");
443 FPRINTF(stderr," Unknown value for relational operators!\n");
444 }
445
446 FPRINTF(out," N R%07d\n", rused); /* objective row */
447
448 }
449
450
451 static void upgrade_vars(FILE *out, /* file */
452 char typerow[], /* array of variable type data */
453 real64 ubrow[], /* to change ub on int->bin */
454 int32 vused, /* number of vars */
455 int relaxed, /* should the relaxed problem be solved */
456 int dointeger, /* supports integer vars */
457 int dobinary, /* supports binary vars */
458 int dosemi) /* supports semi-continuous vars */
459
460 /** This very simple routine checks to see if a variables type is currently
461 *** supported. If not, it converts it into a type which is, printing a
462 *** warning about the conversion to stderr.
463 ***
464 *** It does bin -> integer
465 *** integer -> bin
466 *** semi -> solver_var
467 *** bin -> solver_var
468 *** integer -> solver_var
469 *** conversions, as appropriate.
470 **/
471
472 {
473 int orgcol; /* original column number */
474
475 for(orgcol = 0; orgcol < vused; orgcol++) /* loop over all columns, is _original_ column number */
476 if (typerow[orgcol] != SOLVER_FIXED) { /* only bother with incident variables */
477
478 if ((relaxed == 1) && ((typerow[orgcol] == SOLVER_BINARY) || /* if relaxed convert it to solver_var */
479 (typerow[orgcol] == SOLVER_INT) ||
480 (typerow[orgcol] == SOLVER_SEMI)))
481 typerow[orgcol] = SOLVER_VAR;
482 else
483
484 /* upgrade types as appropriate here */
485 /* if defined a binary var, and solver only supports integer vars, "upgrade" to an int var, etc. */
486 if ((typerow[orgcol] == SOLVER_BINARY) && (dointeger != 2) && (dobinary == 2)) {
487 typerow[orgcol] = SOLVER_INT;
488 }
489 else if ((typerow[orgcol] == SOLVER_INT) && (dointeger == 2) && (dobinary != 2)) {
490 FPRINTF(stderr,"WARNING: Variable C%07d was treated as a %s instead of a %s.\n", orgcol, SOLVER_BINARY_STR, SOLVER_INT_STR);
491 FPRINTF(stderr," The selected MILP solver does not support %s.\n", SOLVER_INT_STR);
492 FPRINTF(stderr," Upper bound was set to 1.0.\n");
493 typerow[orgcol] = SOLVER_BINARY;
494 ubrow[orgcol] = 1.0; /* note: changed bound */
495 }
496 else if ((typerow[orgcol] == SOLVER_SEMI) && (dosemi == 0)) { /* semi not supported */
497 FPRINTF(stderr,"WARNING: Variable C%07d was converted from a %s to a %s.\n", orgcol, SOLVER_SEMI_STR, SOLVER_VAR_STR);
498 FPRINTF(stderr," The selected MILP solver does not support %s.\n", orgcol, SOLVER_SEMI_STR);
499 FPRINTF(stderr," The solution found may not be correct for your model.\n");
500 typerow[orgcol] = SOLVER_VAR;
501 }
502 else if ((typerow[orgcol] == SOLVER_BINARY) && (dointeger == 2) && (dobinary ==2)) { /* neither is supported */
503 FPRINTF(stderr,"WARNING: Variable C%07d was treated as a %s instead of a %s.\n", orgcol, SOLVER_VAR_STR, SOLVER_BINARY_STR);
504 FPRINTF(stderr," The selected MILP solver only supports %s.\n", SOLVER_VAR_STR);
505 typerow[orgcol] = SOLVER_VAR;
506 }
507 else if ((typerow[orgcol] == SOLVER_INT) && (dointeger == 2) && (dobinary == 2)) { /* neither is supported */
508 FPRINTF(stderr,"WARNING: Variable C%07d was treated as a %s instead of a %s.\n", orgcol, SOLVER_VAR_STR, SOLVER_INT_STR);
509 FPRINTF(stderr," The selected MILP solver only supports %s.\n", SOLVER_VAR_STR);
510 typerow[orgcol] = SOLVER_VAR;
511 }
512 }
513 }
514
515
516
517 void scan_SOS(mtx_matrix_t Ac_mtx, /* Matrix representation of problem */
518 char relopcol[], /* array of relational operator data */
519 real64 bcol[], /* array of RHS data */
520 char typerow[], /* array of variable type data */
521 int32 rused, /* size of arrays */
522 int32 vused, /* number of vars */
523 int32 *sosvarptr, /* output: number of variables used
524 in SOS's */
525 int32 *sosrelptr) /* output: number of relations
526 defining SOS's */
527
528 /** This routine identifies relations which are special ordered sets.
529 *** It used the Ac_mtx matrix, and reorganizes it into the following
530 *** format:
531 *** 1 sosvar vused
532 *** | | |
533 *** + + +
534 *** 1 -> | xxxxx |
535 *** | xxx |
536 *** | xxxx |
537 *** sosrel -> | xx |
538 *** | x x x x x |
539 *** | x x x x |
540 *** | x x x x x |
541 *** | x x x x x |
542 *** | x x x x |
543 *** rused -> | x x x x x |
544 *** crow
545 ***
546 *** sosvar = number of vars involved in SOS's
547 *** sosrel = number of SOS equations
548 ***
549 *** The nomenclature of SOS's is really confused. The number used
550 *** depends on the solver/modeling language in use. In this case we are
551 *** looking for equations of the form sum(i, x[i]) = 1, which I'll call
552 *** a SOS1, and sum(i, x[i]) <= 1, which I'll call a SOS3.
553 ***
554 *** First, this routine checks to see if a relation is >=. If so, it
555 *** can't be SOS, so that row is skipped. Next, it checks to see
556 *** if the RHS is 1. If not, that row is skipped.
557 ***
558 *** Note that overlapping SOS's are not allowed by the MPS format.
559 *** That is, a variable can only be part of one SOS.
560 ***
561 *** This routine checks to be sure that all vars involved are binary
562 *** or integer. If so, the row is a SOS. If not, it's just a regular
563 *** constraint. (It doesn't explicitly check the upper bounds on
564 *** integer vars, since if their not 1 the model will be infeasible.)
565 ***
566 *** Note that this routine uses the current row/col, not the original like most
567 *** other routines. The columns are reorganized so that all vars of a SOS are
568 *** together, as shown above.
569 **/
570
571 {
572 real64 value; /* value of mtx element */
573 mtx_coord_t nz; /* coordinate of row/column for going down RHS column */
574 mtx_range_t range; /* storage for range of A matrix, run down a column */
575 int32 current_row; /* counter for row being examined */
576 int32 current_col; /* counter for column being examined */
577 int32 not_row; /* counter for row at end of matrix which is not an SOS */
578 boolean isSOS; /* is the current row a SOS ? */
579
580 current_row = 0; /* initialize stuff */
581 not_row = rused-1; /* rel 0 to rused-1 are actually used */
582 current_col = 0;
583
584 while (current_row <= not_row) /* examin each row of the A matrix once */
585 {
586 if ((bcol[mtx_row_to_org(Ac_mtx, current_row)] == 1.0) && (relopcol[mtx_row_to_org(Ac_mtx, current_row)] != rel_TOK_greater)) /* see if row coefficients ok */
587 {
588 /* it is a SOS if all coefficients are 1,
589 and all columns with nonzero coeff are >= current_col
590 i.e. the equation doesn't contain any vars from prev SOS equations */
591
592 isSOS = TRUE;
593 nz.col = mtx_FIRST; /* first nonzero col (1) */
594 nz.row = current_row; /* use current row */
595
596 do { /* loop until done or find a value != 1.0 */
597
598 value = mtx_next_in_row(Ac_mtx,&nz,mtx_range(&range,0,vused));
599 if ((nz.col != mtx_FIRST) && (nz.col != mtx_LAST)) {
600 if ( nz.col < current_col) {
601 isSOS = FALSE; /* overlaps prev SOS */
602 FPRINTF(stderr, "nz.col, current_col, mtx_FIRST: %d %d %d\n", nz.col, current_col, mtx_FIRST);
603 }
604 if ((typerow[mtx_col_to_org(Ac_mtx, nz.col)] != SOLVER_BINARY) &&
605 ( typerow[mtx_col_to_org(Ac_mtx, nz.col)] != SOLVER_INT)) {
606 isSOS = FALSE; /* var is wrong type */
607 FPRINTF(stderr, "typerow: %d\n", typerow[mtx_col_to_org(Ac_mtx, nz.col)]);
608 }
609 }
610
611 } while ( (value == 1.0) && (nz.row != mtx_LAST) && isSOS );
612
613 if (nz.col != mtx_LAST) isSOS = FALSE; /* only true if terminated due to mxt_LAST */
614 FPRINTF(stderr, "isSOS,nz.col:%d, %d\n", isSOS,nz.col);
615
616 }
617 else
618 isSOS = FALSE;
619
620 if (isSOS) /* reorder columns so all line up in first cols */
621 {
622 FPRINTF(stderr, "current_row, not_row:%d, %d\n", current_row, not_row);
623 /* Is a SOS, so rearrange columns so all the vars in the equation
624 are from current_col on. Also advance current_row by one. */
625
626 nz.col = mtx_FIRST; /* first nonzero col */
627 nz.row = current_row; /* use current row */
628
629 mtx_next_in_row(Ac_mtx,&nz,mtx_range(&range,0,vused));
630 while( nz.col != mtx_LAST) {
631 mtx_swap_cols(Ac_mtx, nz.col, current_col++);
632 mtx_next_in_row(Ac_mtx,&nz,mtx_range(&range,0,vused));
633 }
634 current_row++; /* now examine next row */
635 }
636 else
637 {
638 /* Isn't a SOS, so swap current_row with not_row,
639 to get it out of the way.
640 Also decrement not_row by one */
641
642 mtx_swap_rows(Ac_mtx, current_row, not_row--);
643
644 }
645 }
646
647 *sosvarptr = current_col;
648 *sosrelptr = current_row;
649 }
650
651
652 void do_columns(FILE *out, /* file */
653 mtx_matrix_t Ac_mtx, /* Matrix representation of problem */
654 char typerow[], /* array of variable type data */
655 int32 rused, /* number of relations */
656 int32 vused, /* number of vars */
657 int32 sosvar, /* number of variables used in SOS's */
658 int32 sosrel, /* number of relations that
659 are SOS's */
660 int dointeger, /* supports integer vars */
661 int dobinary) /* supports binary vars */
662 /***
663 *** Creates the main A matrix of data. It handles SOS's, relying on
664 *** the values of sosvar and sosrel (which should be 0 is there aren't
665 *** any SOS's). It mostly just calls print_col, the appropriate number
666 *** of times.
667 ***/
668 {
669 mtx_range_t range; /* storage for range of A matrix, run down a column */
670 int32 curcol; /* counter for current column */
671 int32 currow; /* current row number */
672 int sosnum; /* number used in marker labels */
673 int upcol; /* upper counter on column in SOS */
674
675 FPRINTF(out,"COLUMNS\n"); /* section header */
676
677 sosnum = 0;
678 curcol = 0;
679
680 /* loop over every SOS */
681 for (currow = 0; currow < sosrel ; currow++) {
682
683 /* 0 1 2 3 4 *
684 * 1234 234567890123456789012345678901234567 */
685 FPRINTF(out," M%07d 'MARKER' 'SETORG'\n", sosnum);
686
687 /* figure out end point of next SOS */
688 upcol = mtx_nonzeros_in_row(Ac_mtx,currow,mtx_range(&range,0,vused-1)) + curcol;
689
690 for ( ; curcol < upcol; curcol++)
691 print_col(out, Ac_mtx, typerow, curcol, rused, vused, dointeger, dobinary);
692
693 /* 0 1 2 3 4 *
694 * 1234 234567890123456789012345678901234567 */
695 FPRINTF(out," E%07d 'MARKER' 'SETEND'\n", sosnum++);
696
697 }
698
699 /* loop rest of all columns, not in a SOS */
700 for( ; curcol < vused; curcol++)
701 print_col(out, Ac_mtx, typerow, curcol, rused, vused, dointeger, dobinary);
702
703 }
704
705
706
707 void do_rhs(FILE *out, /* file */
708 real64 bcol[], /* array of data */
709 char relopcol[], /* is it incident? */
710 int32 rused, /* size of array */
711 int32 vused) /* number RHS column vused+1 */
712
713 /***
714 *** Prints out the right hand side data
715 ***/
716 {
717 int i;
718
719 FPRINTF(out,"RHS\n"); /* section header */
720
721 for(i = 0; i < rused; i++) /* loop over all rows */
722 if (relopcol[i] != rel_TOK_nonincident) /* if it is incident, nonfixed */
723 print_col_element(out, vused , i, bcol[i]); /* then print out stuff */
724
725 print_col_element(out, -1 , 0, 0.0); /* clean up newline */
726
727 }
728
729 void do_bounds(FILE *out, /* file */
730 real64 lbrow[], /* array of data */
731 real64 ubrow[], /* array of data */
732 char typerow[], /* array of data */
733 int32 rused, /* size of arrays */
734 int nonneg, /* allow nonneg vars (no FR or MI) ? */
735 int binary_flag, /* allow BV vars ? */
736 int integer_flag, /* allow UI vars ? */
737 int semi_flag, /* allow SC vars ? */
738 double pinf, /* any UB>=pinf is set to + infinity */
739 double minf) /* any LB<=minf is set to - infinity */
740
741 /*** This routine creates the BOUNDS section of the MPS file.
742 *** It checks the following flags:
743 ***
744 *** iarray[SP6_NONNEG] 0->solver handles free vars
745 *** 1->solver requires that all vars have LB=0,
746 UB=infinity, no FR or MI
747 *** iarray[SP6_BINARY] 0->solver supports binary variables using INTORG
748 *** 1->solver supports binary variables with
749 BV option in BOUNDS
750 *** 2->no support
751 *** iarray[SP6_INTEGER] 0->solver defines integer vars using INTORG
752 *** 1->solver defines integer vars using UI in BOUNDS
753 *** 2->no support for integer vars
754 *** iarray[SP6_SEMI] 0->no support
755 *** 1->solver supports SCICONIC style semi-
756 continuous vars
757 *** rarray[SP6_PINF] any UB >= pinf is set to + infinity
758 *** rarray[SP6_MINF] any LB <= minf is set to - infinity
759 **
760 *** The following formats are defined:
761 ***
762 *** LO Lower bound bj <= xj ( <= pinfinity)
763 *** UP Upper bound (0 <= ) xj < bj
764 *** FX Fixed variable xj = bj
765 *** FR Free variable minfinity < xj < pinfinity
766 *** MI Lower bound minfinity minfinity < xj ( <= 0)
767 *** PL Upper bound pinfinity (0 <= ) xj <= pinfinity
768 ***
769 *** Where default bounds of 0 or infinity are shown in ()
770 *** A default of PL is assumed for all variables, so it is not
771 *** explicitly writen to the file
772 ***/
773 {
774 int i;
775
776 FPRINTF(out,"BOUNDS\n"); /* section header */
777
778 for(i = 0; i < rused; i++) /* loop over all rows */
779 {
780 if ((typerow[i] == SOLVER_BINARY) && (binary_flag == 1)) /* do BV */
781 FPRINTF(out," BV B%07d C%07d\n",i,i);
782 else if ((typerow[i] == SOLVER_INT) && (integer_flag == 1)) /* do UI */
783 {
784 FPRINTF(out," UI B%07d C%07d %12.6G\n",i,i,ubrow[i]);
785 if (lbrow[i] != 0.0) /* LB of 0 is assumed, so don't need to add it */
786 FPRINTF(out," LO B%07d C%07d %12.6G\n",i,i,lbrow[i]);
787 }
788 else if ((typerow[i] == SOLVER_SEMI) && (semi_flag == 1)) /* do SC, upper bound is value */
789
790 FPRINTF(out," SC B%07d C%07d %12.6G\n",i,i,ubrow[i]);
791
792 else if ((ubrow[i] >= pinf) && (lbrow[i] <= minf) && (nonneg == 0)) /* do FR */
793
794 FPRINTF(out," FR B%07d C%07d\n",i,i);
795
796 else if ((ubrow[i] <= pinf) && (lbrow[i] <= minf) && (nonneg == 0)) /* do MI */
797 {
798 FPRINTF(out," MI B%07d C%07d\n",i,i,ubrow[i]);
799 if (ubrow[i] != 0.0) /* UB of 0 is assumed, so don't need to add it */
800 FPRINTF(out," UP B%07d C%07d %12.6G\n",i,i,ubrow[i]);
801 }
802 else if (ubrow[i] == lbrow[i]) /* do FX */
803
804 FPRINTF(out," FX B%07d C%07d %12.6G\n",i,i,ubrow[i]);
805
806 else if ((ubrow[i] >= pinf) && (lbrow[i] == 0.0)) /* do PL */
807
808 continue; /* are default limits, no bound necessary */
809
810 else /* do normal UB and LB */
811 {
812 if (lbrow[i] != 0.0) /* LB of 0 is assumed, so don't need to add it */
813 FPRINTF(out," LO B%07d C%07d %12.6G\n",i,i,lbrow[i]);
814
815 if (ubrow[i] <= pinf) /* UB of + infinity is assumed, so don't need to add it */
816 FPRINTF(out," UP B%07d C%07d %12.6G\n",i,i,ubrow[i]);
817 }
818
819 }
820
821 }
822
823
824 /* _________________________________________________________________________ */
825
826 /* writes out an MPS file */
827
828 extern boolean write_MPS(const char *name, /* filename for output */
829 mps_data_t mps, /* the main chunk of data for the problem */
830 int iarray[slv6_IA_SIZE], /* Integer subparameters */
831 double rarray[slv6_RA_SIZE]) /* Real subparameters */
832 {
833 FILE *out;
834 int32 sosvar; /* number of variables used in SOS's */
835 int32 sosrel; /* number of relations defining SOS's */
836 int i; /* temporary counter */
837
838 if (name == NULL) { /* got a bad pointer */
839 FPRINTF(stderr,"ERROR: (MPS) write_MPS\n");
840 FPRINTF(stderr," Routine was passed a NULL pointer!\n");
841 return FALSE;
842 }
843
844 out = open_write(name);
845 if (out == NULL) return FALSE;
846
847 /* create header */
848 do_name(out, /* file */
849 iarray[SP6_OBJ], /* how does it know to max/min */
850 iarray[SP6_BO], /* QOMILP style cutoff */
851 iarray[SP6_EPS], /* QOMILP style termination criteria */
852 rarray[SP6_BOVAL], /* value of cutoff */
853 rarray[SP6_EPSVAL]); /* value of termination criteria */
854
855 do_rows(out, /* file */
856 mps.relopcol, /* need type of constraint <=, >=, = */
857 mps.rinc); /* number of incident relations */
858
859 upgrade_vars(out, /* file */
860 mps.typerow, /* array of variable type data */
861 mps.ubrow, /* change ub on int -> bin conversion */
862 mps.vused, /* number of vars */
863 iarray[SP6_RELAXED], /* should the relaxed problem be solved */
864 iarray[SP6_INTEGER], /* supports integer vars */
865 iarray[SP6_BINARY], /* supports binary vars */
866 iarray[SP6_SEMI]); /* supports semi-continuous vars */
867
868 if ((iarray[SP6_SOS1] == 1) || (iarray[SP6_SOS3] == 1)) /* look for SOS's, reorder matrix */
869 scan_SOS(mps.Ac_mtx, /* Matrix representation of problem */
870 mps.relopcol, /* array of relational operator data */
871 mps.bcol, /* array of RHS data */
872 mps.typerow, /* array of variable type data */
873 mps.rinc, /* size of incident relations */
874 mps.vinc, /* number of vars */
875 &sosvar, /* output: number of variables used in SOS's */
876 &sosrel); /* output: number of relations defining SOS's */
877 else {
878 sosvar = 0; /* set for use in do_columns */
879 sosrel = 0;
880 }
881
882 if (iarray[SP6_SOS2] == 1) { /* don't support SOS2 yet */
883 FPRINTF(stderr,"WARNING: (MPS) write_MPS\n");
884 FPRINTF(stderr," SOS2 are not currently supported in ASCEND!\n");
885 }
886
887 do_columns(out, /* file */
888 mps.Ac_mtx, /* Matrix representation of problem */
889 mps.typerow, /* array of variable type data */
890 mps.rused, /* number of relations */
891 mps.vused, /* number of vars */
892 sosvar, /* number of variables used in SOS's */
893 sosrel, /* number of SOS's */
894 iarray[SP6_INTEGER], /* supports integer vars */
895 iarray[SP6_BINARY]); /* supports binary vars */
896
897 do_rhs(out, /* file */
898 mps.bcol,
899 mps.relopcol,
900 mps.rinc,
901 mps.vinc);
902
903 do_bounds(out, /* file */
904 mps.lbrow, /* array of data */
905 mps.ubrow, /* array of data */
906 mps.typerow, /* array of data */
907 mps.rused, /* size of arrays */
908 iarray[SP6_NONNEG], /* allow nonneg vars (no FR or MI) ? */
909 iarray[SP6_BINARY], /* allow BV vars ? */
910 iarray[SP6_INTEGER], /* allow UI vars ? */
911 iarray[SP6_SEMI], /* allow SC vars ? */
912 rarray[SP6_PINF], /* any UB>=pinf is set to + infinity */
913 rarray[SP6_MINF]); /* any LB<=minf is set to - infinity */
914
915 FPRINTF(out, "ENDATA\n"); /* finish up the file */
916
917 return close_file(out);
918 }
919
920 #endif
921
922

Properties

Name Value
svn:executable *

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