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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2397 - (hide 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 johnpye 1183 /* 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 aw0a 1
8 johnpye 1183 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 aw0a 1 *** 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 johnpye 1183 *//*
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 aw0a 1
60 johnpye 1183 #include "mps.h"
61 jpye 2378 #include "slv6.h"
62 johnpye 1183
63 aw0a 1 #include <time.h>
64     #include <errno.h>
65 johnpye 1210
66 jpye 2322 #include <ascend/general/ascMalloc.h>
67 jpye 2018 #include <ascend/general/list.h>
68     #include <ascend/utilities/set.h>
69     #include <ascend/general/tm_time.h>
70 jpye 2322 #include <ascend/general/mem.h>
71 jpye 2379 #include <ascend/compiler/instance_io.h>
72 johnpye 1183
73 aw0a 1 /* _________________________________________________________________________ */
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 jpye 2378 if (coltype != MPS_FIXED) { /* only bother with incident, nonfixed variables */
237 aw0a 1
238     /* do an INTORG marker if start of binary/integer var */
239 jpye 2378 if ((! inBinInt) && (((coltype == MPS_BINARY) && (dobinary == 0)) ||
240     ((coltype == MPS_INT) && (dointeger == 0)))) {
241 aw0a 1 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 jpye 2378 (inBinInt && ((nexttype != MPS_BINARY) && (nexttype != MPS_INT )))) {
263 aw0a 1
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 jpye 2379 //int i;
287 aw0a 1
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 jpye 2378 if (typerow[orgcol] != MPS_FIXED) { /* only bother with incident variables */
454 aw0a 1
455 jpye 2378 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 aw0a 1 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 jpye 2378 if ((typerow[orgcol] == MPS_BINARY) && (dointeger != 2) && (dobinary == 2)) {
464     typerow[orgcol] = MPS_INT;
465 aw0a 1 }
466 jpye 2378 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 aw0a 1 FPRINTF(stderr," Upper bound was set to 1.0.\n");
470 jpye 2378 typerow[orgcol] = MPS_BINARY;
471 aw0a 1 ubrow[orgcol] = 1.0; /* note: changed bound */
472     }
473 jpye 2378 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 aw0a 1 FPRINTF(stderr," The solution found may not be correct for your model.\n");
477 jpye 2378 typerow[orgcol] = MPS_VAR;
478 aw0a 1 }
479 jpye 2378 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 aw0a 1 }
484 jpye 2378 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 aw0a 1 }
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 jpye 2378 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 aw0a 1 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 jpye 2378 if ((typerow[i] == MPS_BINARY) && (binary_flag == 1)) /* do BV */
758 aw0a 1 FPRINTF(out," BV B%07d C%07d\n",i,i);
759 jpye 2378 else if ((typerow[i] == MPS_INT) && (integer_flag == 1)) /* do UI */
760 aw0a 1 {
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 jpye 2378 else if ((typerow[i] == MPS_SEMI) && (semi_flag == 1)) /* do SC, upper bound is value */
766 aw0a 1
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 jpye 2397 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 aw0a 1 FILE *out;
811     int32 sosvar; /* number of variables used in SOS's */
812     int32 sosrel; /* number of relations defining SOS's */
813 jpye 2379 // int i; /* temporary counter */
814 aw0a 1
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 jpye 2397 #else
896     return 0;
897     #endif
898 aw0a 1 }
899    
900    

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