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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations) (download) (as text)
Fri Oct 29 20:54:12 2004 UTC (17 years, 8 months ago) by aw0a
File MIME type: text/x-csrc
File size: 37084 byte(s)
Setting up web subdirectory in repository
1 aw0a 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