/[ascend]/trunk/solvers/makemps/mps.c
ViewVC logotype

Contents of /trunk/solvers/makemps/mps.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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