Scippy

SCIP

Solving Constraint Integer Programs

reader_osil.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2014 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file reader_osil.c
17  * @brief OS instance language (OSiL) format file reader
18  * @author Stefan Vigerske
19  * @author Ingmar Vierhaus
20  */
21 
22 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23 
24 #include <assert.h>
25 #include <string.h>
26 #include <math.h>
27 
28 #include "scip/reader_osil.h"
29 #include "scip/scip.h"
31 #include "scip/cons_linear.h"
32 #include "scip/cons_quadratic.h"
33 #include "scip/cons_nonlinear.h"
34 #include "scip/cons_sos1.h"
35 #include "scip/cons_sos2.h"
36 #include "xml/xml.h"
37 
38 
39 #define READER_NAME "osilreader"
40 #define READER_DESC "file reader for OS instance language (OSiL) format"
41 #define READER_EXTENSION "osil"
42 
43 #ifndef M_PI
44 #define M_PI 3.141592653589793238462643
45 #endif
46 
47 #ifndef M_E
48 #define M_E 2.7182818284590452354
49 #endif
50 
51 
52 /*
53  * Data structures
54  */
55 
56 /** type of constraint */
57 typedef enum
58 {
59  LINEAR, /**< linear constraint */
60  QUADRATIC, /**< quadratic constraint */
61  NONLINEAR /**< general nonlinear constraint */
62 } CONSTYPE;
63 
64 
65 /*
66  * Local methods
67  */
68 
69 /** create variables with bounds and type according to xml data */
70 static
72  SCIP* scip, /**< SCIP data structure */
73  const XML_NODE* datanode, /**< XML root node for instance data */
74  SCIP_VAR*** vars, /**< buffer to store pointer to variable array */
75  int* nvars, /**< buffer to store number of variables */
76  SCIP_Bool initialconss, /**< should model constraints be marked as initial? */
77  SCIP_Bool dynamicconss, /**< should model constraints be subject to aging? */
78  SCIP_Bool dynamiccols, /**< should columns be added and removed dynamically to the LP? */
79  SCIP_Bool dynamicrows, /**< should rows be added and removed dynamically to the LP? */
80  SCIP_Bool* doingfine /**< buffer to indicate whether no errors occured */
81  )
82 {
83  const XML_NODE* variables;
84  const XML_NODE* varnode;
85  const char* attrval;
86  int varssize;
87 
88  assert(scip != NULL);
89  assert(datanode != NULL);
90  assert(vars != NULL);
91  assert(nvars != NULL);
92  assert(doingfine != NULL);
93 
94  *vars = NULL;
95  *nvars = 0;
96 
97  variables = xmlFindNodeMaxdepth(datanode, "variables", 0, 1);
98 
99  if( variables == NULL )
100  {
101  /* no variables: strange but ok so far */
102  return SCIP_OKAY;
103  }
104 
105  /* get number of variables */
106  attrval = xmlGetAttrval(variables, "numberOfVariables");
107  if( attrval == NULL )
108  {
109  SCIPerrorMessage("Attribute \"numberOfVariables\" not found in <variables> node.\n");
110  *doingfine = FALSE;
111  return SCIP_OKAY;
112  }
113 
114  varssize = (int)strtol(attrval, (char**)&attrval, 10);
115  if( *attrval != '\0' || varssize < 0 )
116  {
117  SCIPerrorMessage("Invalid value '%s' for \"numberOfVariables\" attribute.\n", xmlGetAttrval(variables, "numberOfVariables"));
118  *doingfine = FALSE;
119  return SCIP_OKAY;
120  }
121  assert(varssize >= 0);
122 
123  SCIP_CALL( SCIPallocBufferArray(scip, vars, varssize) );
124 
125  /* parse variable nodes, create SCIP vars and add to problem
126  * create bounddisjunction constraints for semicontinuous/semiinteger variables
127  */
128  for( varnode = xmlFirstChild(variables); varnode != NULL; varnode = xmlNextSibl(varnode) )
129  {
130  const char* varname;
131  SCIP_VARTYPE vartype;
132  SCIP_Real varlb;
133  SCIP_Real varub;
134  SCIP_Real semibound;
135 
136  if( varssize == *nvars )
137  {
138  SCIPerrorMessage("Expected %d variables, got at least %d many.\n", varssize, *nvars+1);
139  *doingfine = FALSE;
140  return SCIP_OKAY;
141  }
142 
143  /* find variable name */
144  varname = xmlGetAttrval(varnode, "name");
145 
146  /* find variable lower bound (default is 0.0 !) */
147  attrval = xmlGetAttrval(varnode, "lb");
148  if( attrval == NULL )
149  varlb = 0.0;
150  else if( strcmp(attrval, "-INF") == 0 )
151  varlb = -SCIPinfinity(scip);
152  else if( strcmp(attrval, "INF") == 0 )
153  varlb = SCIPinfinity(scip);
154  else
155  {
156  varlb = strtod(attrval, (char**)&attrval);
157  if( *attrval != '\0' )
158  {
159  SCIPerrorMessage("Error parsing variable lower bound '%s' for variable <%s>\n", attrval, varname);
160  *doingfine = FALSE;
161  return SCIP_OKAY;
162  }
163  }
164 
165  /* find variable upper bound (default is infinity) */
166  attrval = xmlGetAttrval(varnode, "ub");
167  if( attrval == NULL )
168  varub = SCIPinfinity(scip);
169  else if( strcmp(attrval, "-INF") == 0 )
170  varub = -SCIPinfinity(scip);
171  else if( strcmp(attrval, "INF") == 0 )
172  varub = SCIPinfinity(scip);
173  else
174  {
175  varub = strtod(attrval, (char**)&attrval);
176  if( *attrval != '\0' )
177  {
178  SCIPerrorMessage("Error parsing variable upper bound '%s' for variable <%s>\n", attrval, varname);
179  *doingfine = FALSE;
180  return SCIP_OKAY;
181  }
182  }
183 
184  semibound = SCIP_INVALID;
185 
186  /* find variable type (default is continuous)
187  * adjust variable lower bound for semicontinuous variables
188  */
189  attrval = xmlGetAttrval(varnode, "type");
190  if( attrval == NULL )
191  vartype = SCIP_VARTYPE_CONTINUOUS;
192  else switch( *attrval )
193  {
194  case 'C':
195  vartype = SCIP_VARTYPE_CONTINUOUS;
196  break;
197  case 'B':
198  vartype = SCIP_VARTYPE_BINARY;
199  if( varub > 1.0 )
200  varub = 1.0;
201  break;
202  case 'I':
203  vartype = SCIP_VARTYPE_INTEGER;
204  break;
205  case 'D':
206  vartype = SCIP_VARTYPE_CONTINUOUS;
207  if( varlb > 0.0 )
208  semibound = varlb;
209  varlb = 0.0;
210  break;
211  case 'J':
212  vartype = SCIP_VARTYPE_INTEGER;
213  if( varlb > 0.0 )
214  semibound = varlb;
215  varlb = 0.0;
216  break;
217  default:
218  SCIPerrorMessage("Unsupported variable type '%s' for variable <%s>\n", attrval, varname);
219  *doingfine = FALSE;
220  return SCIP_OKAY;
221  }
222 
223  if( vartype != SCIP_VARTYPE_CONTINUOUS )
224  {
225  varlb = SCIPceil(scip, varlb);
226  varub = SCIPfloor(scip, varub);
227  }
228 
229  /* create SCIP variable */
230  SCIP_CALL( SCIPcreateVar(scip, &(*vars)[*nvars], varname, varlb, varub, 0.0, vartype, !dynamiccols, dynamiccols, NULL, NULL, NULL, NULL, NULL) );
231  assert((*vars)[*nvars] != NULL);
232 
233  /* add variable to problem */
234  SCIP_CALL( SCIPaddVar(scip, (*vars)[*nvars]) );
235 
236  /* if variable is actually semicontinuous or semiintegral, create bounddisjunction constraint (var <= 0.0 || var >= semibound) */
237  if( semibound != SCIP_INVALID ) /*lint !e777*/
238  {
239  SCIP_CONS* cons;
240  SCIP_VAR* consvars[2];
241  SCIP_BOUNDTYPE boundtypes[2];
242  SCIP_Real bounds[2];
243  char name[SCIP_MAXSTRLEN];
244 
245  consvars[0] = (*vars)[*nvars];
246  consvars[1] = (*vars)[*nvars];
247 
248  boundtypes[0] = SCIP_BOUNDTYPE_UPPER;
249  boundtypes[1] = SCIP_BOUNDTYPE_LOWER;
250 
251  bounds[0] = 0.0;
252  bounds[1] = semibound;
253 
254  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_semibound", SCIPvarGetName((*vars)[*nvars]));
255 
256  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, consvars, boundtypes, bounds,
257  initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows, FALSE) );
258  SCIP_CALL( SCIPaddCons(scip, cons) );
259  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
260  }
261 
262  ++*nvars;
263  }
264  if( *nvars < varssize )
265  {
266  SCIPerrorMessage("Expected %d variables, but got only %d many.\n", varssize, *nvars);
267  *doingfine = FALSE;
268  return SCIP_OKAY;
269  }
270 
271  return SCIP_OKAY;
272 }
273 
274 /** setup linear coefficients and constant of objective and objective sense */
275 static
277  SCIP* scip, /**< SCIP data structure */
278  const XML_NODE* datanode, /**< XML root node for instance data */
279  SCIP_VAR** vars, /**< variables in order of OSiL indices */
280  int nvars, /**< number of variables */
281  SCIP_Bool dynamiccols, /**< should columns be added and removed dynamically to the LP? */
282  SCIP_Bool* doingfine /**< buffer to indicate whether no errors occured */
283  )
284 {
285  const XML_NODE* objective;
286  const XML_NODE* coefnode;
287  const char* attrval;
288 
289  assert(scip != NULL);
290  assert(datanode != NULL);
291  assert(vars != NULL || nvars == 0);
292  assert(doingfine != NULL);
293 
294  /* check for first objective */
295  objective = xmlFindNodeMaxdepth(datanode, "obj", 0, 2);
296 
297  /* if no objective, then nothing to do here */
298  if( objective == NULL )
299  return SCIP_OKAY;
300 
301  /* objective sense */
302  attrval = xmlGetAttrval(objective, "maxOrMin");
303  if( attrval == NULL )
304  {
305  SCIPerrorMessage("Objective sense missing.\n");
306  *doingfine = FALSE;
307  return SCIP_OKAY;
308  }
309  else if( strcmp(attrval, "min") == 0 )
310  {
312  }
313  else if( strcmp(attrval, "max") == 0 )
314  {
316  }
317  else
318  {
319  SCIPerrorMessage("Cannot parse objective sense '%s'.\n", attrval);
320  *doingfine = FALSE;
321  return SCIP_OKAY;
322  }
323 
324  /* objective coefficients */
325  for( coefnode = xmlFirstChild(objective); coefnode != NULL; coefnode = xmlNextSibl(coefnode) )
326  {
327  SCIP_Real val;
328  int idx;
329 
330  /* get variable index */
331  attrval = xmlGetAttrval(coefnode, "idx");
332  if( attrval == NULL )
333  {
334  SCIPerrorMessage("Missing \"idx\" attribute in objective coefficient.\n");
335  *doingfine = FALSE;
336  return SCIP_OKAY;
337  }
338  idx = (int)strtol(attrval, (char**)&attrval, 10);
339  if( *attrval != '\0' )
340  {
341  SCIPerrorMessage("Error parsing variable index '%s' of objective coefficient.\n", xmlGetAttrval(coefnode, "idx"));
342  *doingfine = FALSE;
343  return SCIP_OKAY;
344  }
345 
346  if( idx < 0 || idx >= nvars )
347  {
348  SCIPerrorMessage("Invalid variable index '%d' of objective coefficient.\n", idx);
349  *doingfine = FALSE;
350  return SCIP_OKAY;
351  }
352 
353  /* get coefficient value */
354  if( xmlFirstChild(coefnode) == NULL || xmlGetData(xmlFirstChild(coefnode)) == NULL )
355  {
356  SCIPerrorMessage("No objective coefficient stored for %d'th variable (<%s>).\n", idx, SCIPvarGetName(vars[idx])); /*lint !e613*/
357  *doingfine = FALSE;
358  return SCIP_OKAY;
359  }
360 
361  attrval = xmlGetData(xmlFirstChild(coefnode));
362  val = strtod(attrval, (char**)&attrval);
363  if( *attrval != '\0' )
364  {
365  SCIPerrorMessage("Error parsing objective coefficient value '%s' for %d'th variable (<%s>).\n", xmlGetData(xmlFirstChild(coefnode)), idx, SCIPvarGetName(vars[idx])); /*lint !e613*/
366  *doingfine = FALSE;
367  return SCIP_OKAY;
368  }
369 
370  /* change objective coefficient of SCIP variable */
371  SCIP_CALL( SCIPchgVarObj(scip, vars[idx], val) ); /*lint !e613*/
372  }
373 
374  /* objective constant: model as fixed variable, if nonzero */
375  attrval = xmlGetAttrval(objective, "constant");
376  if( attrval != NULL )
377  {
378  SCIP_Real objconst;
379 
380  objconst = strtod(attrval, (char**)&attrval);
381  if( *attrval != '\0' )
382  {
383  SCIPerrorMessage("Error parsing objective constant '%s'\n", xmlGetAttrval(objective, "constant"));
384  *doingfine = FALSE;
385  return SCIP_OKAY;
386  }
387 
388  if( objconst != 0.0 )
389  {
390  SCIP_VAR* objconstvar;
391 
392  SCIP_CALL( SCIPcreateVar(scip, &objconstvar, "objconstvar", objconst, objconst, 1.0, SCIP_VARTYPE_CONTINUOUS, !dynamiccols, dynamiccols, NULL, NULL, NULL, NULL, NULL) );
393  SCIP_CALL( SCIPaddVar(scip, objconstvar) );
394  SCIP_CALL( SCIPreleaseVar(scip, &objconstvar) );
395  }
396  }
397 
398  if( xmlNextSibl(objective) != NULL )
399  {
400  SCIPerrorMessage("Multiple objectives not supported by SCIP.\n");
401  *doingfine = FALSE;
402  return SCIP_OKAY;
403  }
404 
405  return SCIP_OKAY;
406 }
407 
408 /** setup constraint sides as linear constraints
409  *
410  * constraints are not added to the problem yet
411  */
412 static
414  SCIP* scip, /**< SCIP data structure */
415  const XML_NODE* datanode, /**< XML root node for instance data */
416  SCIP_CONS*** conss, /**< buffer to store array of (linear) constraints */
417  CONSTYPE** constypes, /**< buffer to store type of constraints (will be all LINEAR) */
418  int* nconss, /**< buffer to store number of constraints */
419  SCIP_Bool initialconss, /**< should model constraints be marked as initial? */
420  SCIP_Bool dynamicconss, /**< should model constraints be subject to aging? */
421  SCIP_Bool dynamicrows, /**< should rows be added and removed dynamically to the LP? */
422  SCIP_Bool* doingfine /**< buffer to indicate whether no errors occured */
423  )
424 {
425  const XML_NODE* constraints;
426  const XML_NODE* consnode;
427  const char* attrval;
428  int consssize;
429  char name[20];
430 
431  assert(scip != NULL);
432  assert(datanode != NULL);
433  assert(conss != NULL);
434  assert(constypes != NULL);
435  assert(nconss != NULL);
436  assert(doingfine != NULL);
437 
438  *conss = NULL;
439  *constypes = NULL;
440  *nconss = 0;
441 
442  constraints = xmlFindNodeMaxdepth(datanode, "constraints", 0, 1);
443 
444  /* if no constraints, then nothing to do here */
445  if( constraints == NULL )
446  return SCIP_OKAY;
447 
448  /* read number of constraints */
449  attrval = xmlGetAttrval(constraints, "numberOfConstraints");
450  if( attrval == NULL )
451  {
452  SCIPerrorMessage("Attribute \"numberOfConstraints\" not found in <constraints> node.\n");
453  *doingfine = FALSE;
454  return SCIP_OKAY;
455  }
456 
457  consssize = (int)strtol(attrval, (char**)&attrval, 10);
458  if( *attrval != '\0' || consssize < 0 )
459  {
460  SCIPerrorMessage("Invalid value '%s' for \"numberOfConstraints\" attribute.\n", xmlGetAttrval(constraints, "numberOfConstraints"));
461  *doingfine = FALSE;
462  return SCIP_OKAY;
463  }
464  assert(consssize >= 0);
465 
466  SCIP_CALL( SCIPallocBufferArray(scip, conss, consssize) );
467  SCIP_CALL( SCIPallocBufferArray(scip, constypes, consssize) );
468 
469  /* read constraint names, lhs, rhs, constant */
470  for( consnode = xmlFirstChild(constraints); consnode != NULL; consnode = xmlNextSibl(consnode) )
471  {
472  const char* consname;
473  SCIP_Real conslhs;
474  SCIP_Real consrhs;
475 
476  if( consssize == *nconss )
477  {
478  SCIPerrorMessage("Expected %d constraints, but got at least %d many.\n", consssize, *nconss+1);
479  *doingfine = FALSE;
480  return SCIP_OKAY;
481  }
482 
483  /* find constraint name */
484  consname = xmlGetAttrval(consnode, "name");
485  if( consname == NULL )
486  {
487  (void) SCIPsnprintf(name, 20, "cons%d", *nconss);
488  consname = name;
489  }
490 
491  /* find constraint lower bound (=lhs) (default is -infinity) */
492  attrval = xmlGetAttrval(consnode, "lb");
493  if( attrval == NULL )
494  conslhs = -SCIPinfinity(scip);
495  else if( strcmp(attrval, "-INF") == 0 )
496  conslhs = -SCIPinfinity(scip);
497  else if( strcmp(attrval, "INF") == 0 )
498  conslhs = SCIPinfinity(scip);
499  else
500  {
501  conslhs = strtod(attrval, (char**)&attrval);
502  if( *attrval != '\0' )
503  {
504  SCIPerrorMessage("Error parsing constraint lower bound '%s' for constraint <%s>.\n", attrval, consname);
505  *doingfine = FALSE;
506  return SCIP_OKAY;
507  }
508  }
509 
510  /* find constraint upper bound (=rhs) (default is +infinity) */
511  attrval = xmlGetAttrval(consnode, "ub");
512  if( attrval == NULL )
513  consrhs = SCIPinfinity(scip);
514  else if( strcmp(attrval, "-INF") == 0 )
515  consrhs = -SCIPinfinity(scip);
516  else if( strcmp(attrval, "INF") == 0 )
517  consrhs = SCIPinfinity(scip);
518  else
519  {
520  consrhs = strtod(attrval, (char**)&attrval);
521  if( *attrval != '\0' )
522  {
523  SCIPerrorMessage("Error parsing constraint upper bound '%s' for constraint <%s>.\n", attrval, consname);
524  *doingfine = FALSE;
525  return SCIP_OKAY;
526  }
527  }
528 
529  /* find constraint constant (default is 0.0) and substract from lhs/rhs */
530  attrval = xmlGetAttrval(consnode, "constant");
531  if( attrval != NULL )
532  {
533  SCIP_Real consconstant;
534 
535  consconstant = strtod(attrval, (char**)&attrval);
536  if( *attrval != '\0' )
537  {
538  SCIPerrorMessage("Error parsing constraint constant '%s' for constraint <%s>.\n", attrval, consname);
539  *doingfine = FALSE;
540  return SCIP_OKAY;
541  }
542  if( conslhs > -SCIPinfinity(scip) )
543  conslhs -= consconstant;
544  if( consrhs < SCIPinfinity(scip) )
545  consrhs -= consconstant;
546  }
547 
548  /* create SCIP linear constraint */
549  SCIP_CALL( SCIPcreateConsLinear(scip, &(*conss)[*nconss], consname, 0, NULL, NULL, conslhs, consrhs,
550  initialconss, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, dynamicconss, dynamicrows, FALSE) );
551  assert((*conss)[*nconss] != NULL);
552 
553  (*constypes)[*nconss] = LINEAR;
554 
555  ++*nconss;
556  }
557 
558  if( *nconss < consssize )
559  {
560  SCIPerrorMessage("Got %d constraints, but expected %d many.\n", *nconss, consssize);
561  *doingfine = FALSE;
562  return SCIP_OKAY;
563  }
564 
565  return SCIP_OKAY;
566 }
567 
568 /** reads mult and incr attributes of an OSiL node
569  *
570  * if mult attribute is not present, then returns mult=1
571  * if incr attribute is not present, then returns incrint=0 and incrreal=0
572  */
573 static
575  const XML_NODE* node, /**< XML node to read attributes from */
576  int* mult, /**< buffer to store mult */
577  int* incrint, /**< buffer to store incr as int, or NULL if no int expected */
578  SCIP_Real* incrreal, /**< buffer to store incr as real, or NULL if no real expected */
579  SCIP_Bool* doingfine /**< buffer to indicate whether no errors occured */
580  )
581 {
582  const char* attrval;
583 
584  assert(node != NULL);
585  assert(mult != NULL);
586  assert(doingfine != NULL);
587 
588  *mult = 1;
589  if( incrint != NULL )
590  *incrint = 0;
591  if( incrreal != NULL )
592  *incrreal = 0.0;
593 
594  attrval = xmlGetAttrval(node, "mult");
595  if( attrval == NULL )
596  return;
597 
598  /* read "mult" attribute */
599  *mult = (int)strtol(attrval, (char**)&attrval, 10);
600  if( *attrval != '\0' || *mult < 1 )
601  {
602  SCIPerrorMessage("Invalid value '%s' in \"mult\" attribute of node.\n", xmlGetAttrval(node, "mult"));
603  *doingfine = FALSE;
604  return;
605  }
606 
607  if( *mult == 1 )
608  return;
609 
610  /* read "incr" attribute */
611  attrval = xmlGetAttrval(node, "incr");
612  if( attrval == NULL )
613  return;
614 
615  if( incrint != NULL )
616  {
617  *incrint = (int)strtol(attrval, (char**)&attrval, 10);
618  if( *attrval != '\0' )
619  {
620  SCIPerrorMessage("Invalid value '%s' in \"incr\" attribute of node.\n", xmlGetAttrval(node, "incr"));
621  *doingfine = FALSE;
622  return;
623  }
624  }
625 
626  if( incrreal != NULL )
627  {
628  *incrreal = strtod(attrval, (char**)&attrval);
629  if( *attrval != '\0' || !SCIPisFinite(*incrreal) )
630  {
631  SCIPerrorMessage("Invalid value '%s' in \"incr\" attribute of node.\n", xmlGetAttrval(node, "incr"));
632  *doingfine = FALSE;
633  return;
634  }
635  }
636 }
637 
638 /** parse linear coefficients of constraints */
639 static
641  SCIP* scip, /**< SCIP data structure */
642  const XML_NODE* datanode, /**< XML root node for instance data */
643  SCIP_VAR** vars, /**< variables in order of OSiL indices */
644  int nvars, /**< number of variables */
645  SCIP_CONS** conss, /**< constraints in order of OSiL indices */
646  CONSTYPE* constypes, /**< type of constraints (assumed to be LINEAR) */
647  int nconss, /**< number of constraints */
648  SCIP_Bool* doingfine /**< buffer to indicate whether no errors occured */
649  )
650 {
651  const XML_NODE* lincoef;
652  const XML_NODE* startnode;
653  const XML_NODE* idxnode;
654  const XML_NODE* valnode;
655  const XML_NODE* elnode;
656  const char* attrval;
657  SCIP_Bool rowmajor;
658  int* start;
659  int* idx;
660  SCIP_Real* val;
661  int nnz;
662  int count;
663  int mult;
664  int incrint;
665  SCIP_Real incrreal;
666 
667  assert(scip != NULL);
668  assert(datanode != NULL);
669  assert(vars != NULL || nvars == 0);
670  assert(conss != NULL || nconss == 0);
671  assert(constypes != NULL || nconss == 0);
672  assert(doingfine != NULL);
673 
674  lincoef = xmlFindNodeMaxdepth(datanode, "linearConstraintCoefficients", 0, 1);
675 
676  if( lincoef == NULL )
677  return SCIP_OKAY;
678 
679  /* get number of linear constraint coefficients */
680  attrval = xmlGetAttrval(lincoef, "numberOfValues");
681  if( attrval == NULL )
682  {
683  SCIPerrorMessage("Attribute \"numberOfValues\" not found for <linearConstraintCoefficients> node.\n");
684  *doingfine = FALSE;
685  return SCIP_OKAY;
686  }
687 
688  nnz = (int)strtol(attrval, (char**)&attrval, 10);
689  if( *attrval != '\0' || nnz < 0 )
690  {
691  SCIPerrorMessage("Invalid value '%s' for \"numberOfValues\" attribute in <linearConstraintCoefficients> node.\n", xmlGetAttrval(lincoef, "numberOfValues"));
692  *doingfine = FALSE;
693  return SCIP_OKAY;
694  }
695  assert(nnz >= 0);
696 
697  /* check for start, rowIdx, colIdx, and value nodes */
698  startnode = xmlFindNodeMaxdepth(lincoef, "start", 0, 1);
699  if( startnode == NULL )
700  {
701  SCIPerrorMessage("Node <start> not found inside <linearConstraintCoefficients> node.\n");
702  *doingfine = FALSE;
703  return SCIP_OKAY;
704  }
705 
706  idxnode = xmlFindNodeMaxdepth(lincoef, "rowIdx", 0, 1);
707  if( idxnode != NULL )
708  {
709  if( xmlFindNodeMaxdepth(lincoef, "colIdx", 0, 1) != NULL )
710  {
711  SCIPerrorMessage("Both <rowIdx> and <colIdx> found under <linearConstraintCoefficients> node.\n");
712  *doingfine = FALSE;
713  return SCIP_OKAY;
714  }
715  rowmajor = FALSE;
716  }
717  else
718  {
719  idxnode = xmlFindNodeMaxdepth(lincoef, "colIdx", 0, 1);
720  if( idxnode == NULL )
721  {
722  SCIPerrorMessage("Both <rowIdx> and <colIdx> not found under <linearConstraintCoefficients> node.\n");
723  *doingfine = FALSE;
724  return SCIP_OKAY;
725  }
726  rowmajor = TRUE;
727  }
728 
729  valnode = xmlFindNodeMaxdepth(lincoef, "value", 0, 1);
730  if( valnode == NULL )
731  {
732  SCIPerrorMessage("<value> node not found under <linearConstraintCoefficients> node.\n");
733  *doingfine = FALSE;
734  return SCIP_OKAY;
735  }
736 
737  start = NULL;
738  idx = NULL;
739  val = NULL;
740 
741  /* read row or column start indices */
742  SCIP_CALL( SCIPallocBufferArray(scip, &start, (rowmajor ? nconss : nvars) + 1) );
743 
744  count = 0;
745  for( elnode = xmlFirstChild(startnode); elnode != NULL; elnode = xmlNextSibl(elnode), ++count )
746  {
747  /* check for <el> node and read it's data */
748  if( strcmp(xmlGetName(elnode), "el") != 0 )
749  {
750  SCIPerrorMessage("Expected <el> node under <start> node in <linearConstraintCoefficients>, but got '%s'.\n", xmlGetName(elnode));
751  *doingfine = FALSE;
752  goto CLEANUP;
753  }
754  if( count >= (rowmajor ? nconss : nvars) + 1 )
755  {
756  SCIPerrorMessage("Too many elements under <start> node in <linearConstraintCoefficients>, expected %d many, got at least %d.\n", (rowmajor ? nconss : nvars) + 1, count + 1);
757  *doingfine = FALSE;
758  goto CLEANUP;
759  }
760  if( xmlFirstChild(elnode) == NULL || xmlGetData(xmlFirstChild(elnode)) == NULL )
761  {
762  SCIPerrorMessage("No data in <el> node in <linearConstraintCoefficients>.\n");
763  *doingfine = FALSE;
764  goto CLEANUP;
765  }
766 
767  start[count] = (int)strtol(xmlGetData(xmlFirstChild(elnode)), (char**)&attrval, 10);
768 
769  if( *attrval != '\0' || start[count] < 0 || (start[count] > nnz) )
770  {
771  SCIPerrorMessage("Invalid value '%s' in <el> node under <start> node in <linearConstraintCoefficients>.\n", xmlGetData(elnode));
772  *doingfine = FALSE;
773  goto CLEANUP;
774  }
775 
776  /* add additional start-indices according to mult and incr attributes */
777  readMultIncr(elnode, &mult, &incrint, NULL, doingfine);
778  if( !*doingfine )
779  goto CLEANUP;
780 
781  for( --mult; mult > 0; --mult )
782  {
783  ++count;
784  if( count >= (rowmajor ? nconss : nvars) + 1 )
785  {
786  SCIPerrorMessage("Too many elements under <start> node in <linearConstraintCoefficients>, expected %d many, got at least %d.\n", (rowmajor ? nconss : nvars) + 1, count + 1);
787  *doingfine = FALSE;
788  goto CLEANUP;
789  }
790  start[count] = start[count-1] + incrint;
791  }
792  }
793  if( count != (rowmajor ? nconss : nvars) + 1 )
794  {
795  SCIPerrorMessage("Got only %d <start> entries in <linearConstraintCoefficients>, but expected %d many.\n", count, (rowmajor ? nconss : nvars) + 1);
796  *doingfine = FALSE;
797  goto CLEANUP;
798  }
799 
800  /* read row or column indices */
801  SCIP_CALL( SCIPallocBufferArray(scip, &idx, nnz) );
802 
803  count = 0;
804  for( elnode = xmlFirstChild(idxnode); elnode != NULL; elnode = xmlNextSibl(elnode), ++count )
805  {
806  /* check for <el> node and read it's data */
807  if( strcmp(xmlGetName(elnode), "el") != 0 )
808  {
809  SCIPerrorMessage("Expected <el> node under <%s> node in <linearConstraintCoefficients>, but got '%s'.\n", rowmajor ? "colIdx" : "rowIdx", xmlGetName(elnode));
810  *doingfine = FALSE;
811  goto CLEANUP;
812  }
813  if( count >= nnz )
814  {
815  SCIPerrorMessage("Too many elements under <%s> node in <linearConstraintCoefficients>, expected %d many, but got at least %d.\n", rowmajor ? "colIdx" : "rowIdx", nnz, count + 1);
816  *doingfine = FALSE;
817  goto CLEANUP;
818  }
819  if( xmlFirstChild(elnode) == NULL || xmlGetData(xmlFirstChild(elnode)) == NULL )
820  {
821  SCIPerrorMessage("No data in <el> node under <%s> node in <linearConstraintCoefficients>.\n", rowmajor ? "colIdx" : "rowIdx");
822  *doingfine = FALSE;
823  goto CLEANUP;
824  }
825 
826  idx[count] = (int)strtol(xmlGetData(xmlFirstChild(elnode)), (char**)&attrval, 10);
827 
828  if( *attrval != '\0' || idx[count] < 0 || (idx[count] >= (rowmajor ? nvars : nconss)) )
829  {
830  SCIPerrorMessage("Invalid value '%s' in <el> node under <%s> node in <linearConstraintCoefficients>.\n", xmlGetData(elnode), rowmajor ? "colIdx" : "rowIdx");
831  *doingfine = FALSE;
832  goto CLEANUP;
833  }
834 
835  /* add additional indices according to mult and incr attributes */
836  readMultIncr(elnode, &mult, &incrint, NULL, doingfine);
837  if( !*doingfine )
838  goto CLEANUP;
839 
840  for( --mult; mult > 0; --mult )
841  {
842  ++count;
843  if( count >= nnz )
844  {
845  SCIPerrorMessage("Too many elements under <%s> node in <linearConstraintCoefficients>, expected %d many, got at least %d.\n", rowmajor ? "colIdx" : "rowIdx", nnz, count + 1);
846  *doingfine = FALSE;
847  goto CLEANUP;
848  }
849  idx[count] = idx[count-1] + incrint;
850  }
851  }
852  if( count != nnz )
853  {
854  SCIPerrorMessage("Got only %d entries in <%s> node in <linearConstraintCoefficients>, expected %d many.\n", count, rowmajor ? "colIdx" : "rowIdx", nnz);
855  *doingfine = FALSE;
856  goto CLEANUP;
857  }
858 
859  /* read coefficient values */
860  SCIP_CALL( SCIPallocBufferArray(scip, &val, nnz) );
861 
862  count = 0;
863  for( elnode = xmlFirstChild(valnode); elnode != NULL; elnode = xmlNextSibl(elnode), ++count )
864  {
865  /* check for <el> node and read it's data */
866  if( strcmp(xmlGetName(elnode), "el") != 0 )
867  {
868  SCIPerrorMessage("Expected <el> node under <value> node in <linearConstraintCoefficients>, but got '%s'.\n", xmlGetName(elnode));
869  *doingfine = FALSE;
870  goto CLEANUP;
871  }
872  if( count >= nnz )
873  {
874  SCIPerrorMessage("Too many elements under <value> node in <linearConstraintCoefficients>, expected %d many, got at least %d.\n", nnz, count + 1);
875  *doingfine = FALSE;
876  goto CLEANUP;
877  }
878  if( xmlFirstChild(elnode) == NULL || xmlGetData(xmlFirstChild(elnode)) == NULL )
879  {
880  SCIPerrorMessage("No data in <el> node under <value> node in <linearConstraintCoefficients>.\n");
881  *doingfine = FALSE;
882  goto CLEANUP;
883  }
884 
885  val[count] = strtod(xmlGetData(xmlFirstChild(elnode)), (char**)&attrval);
886 
887  if( *attrval != '\0' || !SCIPisFinite(val[count]) )
888  {
889  SCIPerrorMessage("Invalid value '%s' in <el> node under <value> node in <linearConstraintCoefficients>.\n", xmlGetData(elnode));
890  *doingfine = FALSE;
891  goto CLEANUP;
892  }
893 
894  /* add additional values according to mult and incr attributes */
895  readMultIncr(elnode, &mult, NULL, &incrreal, doingfine);
896  if( !*doingfine )
897  goto CLEANUP;
898 
899  for( --mult; mult > 0; --mult )
900  {
901  ++count;
902  if( count >= nnz )
903  {
904  SCIPerrorMessage("Too many elements under <value> node in <linearConstraintCoefficients>, expected %d many, got at least %d.\n", nnz, count + 1);
905  *doingfine = FALSE;
906  goto CLEANUP;
907  }
908  val[count] = val[count-1] + incrreal;
909  }
910  }
911  if( count != nnz )
912  {
913  SCIPerrorMessage("Got only %d entries under <value> node in <linearConstraintCoefficients>, expected %d many.\n", count, nnz);
914  *doingfine = FALSE;
915  goto CLEANUP;
916  }
917 
918  /* add coefficients to linear constraints */
919  if( rowmajor )
920  {
921  int row;
922  int pos;
923  for( row = 0; row < nconss; ++row )
924  {
925  /* these asserts were checked above */
926  assert(start[row] >= 0);
927  assert(start[row+1] >= 0);
928  assert(start[row] < nnz);
929  assert(start[row+1] <= nnz);
930  for( pos = start[row]; pos < start[row+1]; ++pos )
931  {
932  /* these asserts were checked above */
933  assert(pos >= 0);
934  assert(pos < nnz);
935  assert(idx[pos] >= 0);
936  assert(idx[pos] < nvars);
937 
938  assert(constypes[row] == LINEAR); /*lint !e613*/
939 
940  SCIP_CALL( SCIPaddCoefLinear(scip, conss[row], vars[idx[pos]], val[pos]) ); /*lint !e613*/
941  }
942  }
943  }
944  else
945  {
946  int col;
947  int pos;
948  for( col = 0; col < nvars; ++col )
949  {
950  /* these asserts were checked above */
951  assert(start[col] >= 0);
952  assert(start[col+1] >= 0);
953  assert(start[col] <= nnz);
954  assert(start[col+1] <= nnz);
955  for( pos = start[col]; pos < start[col+1]; ++pos )
956  {
957  /* these asserts were checked above */
958  assert(pos >= 0);
959  assert(pos < nnz);
960  assert(idx[pos] >= 0);
961  assert(idx[pos] < nconss);
962 
963  assert(constypes[idx[pos]] == LINEAR); /*lint !e613*/
964 
965  SCIP_CALL( SCIPaddCoefLinear(scip, conss[idx[pos]], vars[col], val[pos]) ); /*lint !e613*/
966  }
967  }
968  }
969 
970  CLEANUP:
971  SCIPfreeBufferArrayNull(scip, &start);
972  SCIPfreeBufferArrayNull(scip, &idx);
973  SCIPfreeBufferArrayNull(scip, &val);
974 
975  return SCIP_OKAY;
976 }
977 
978 /** read quadratic coefficients of constraints and objective */
979 static
981  SCIP* scip, /**< SCIP data structure */
982  const XML_NODE* datanode, /**< XML root node for instance data */
983  SCIP_VAR** vars, /**< variables in order of OSiL indices */
984  int nvars, /**< number of variables */
985  SCIP_CONS** conss, /**< constraints in order of OSiL indices */
986  CONSTYPE* constypes, /**< type of constraints (assumed to be LINEAR) */
987  int nconss, /**< number of constraints */
988  SCIP_CONS** objcons, /**< buffer to store constraint for nonlinear part of objective function, or to add to if already existing */
989  CONSTYPE* objconstype, /**< buffer to store type of objective constraint, if created (should be QUADRATIC) */
990  SCIP_Bool* doingfine /**< buffer to indicate whether no errors occured */
991  )
992 {
993  const XML_NODE* quadcoef;
994  const XML_NODE* qterm;
995  const char* attrval;
996  SCIP_CONS* cons;
997  int nqterms;
998  int count;
999  int considx;
1000  int varidx1;
1001  int varidx2;
1002  SCIP_Real coef;
1003 
1004  assert(scip != NULL);
1005  assert(datanode != NULL);
1006  assert(vars != NULL || nvars == 0);
1007  assert(conss != NULL || nconss == 0);
1008  assert(constypes != NULL || nconss == 0);
1009  assert(objcons != NULL);
1010  assert(doingfine != NULL);
1011 
1012  quadcoef = xmlFindNodeMaxdepth(datanode, "quadraticCoefficients", 0, 1);
1013 
1014  if( quadcoef == NULL )
1015  return SCIP_OKAY;
1016 
1017  /* read number of quadratic terms */
1018  attrval = xmlGetAttrval(quadcoef, "numberOfQuadraticTerms");
1019  if( attrval == NULL )
1020  {
1021  SCIPerrorMessage("Attribute \"numberOfQuadraticTerms\" not found for <quadraticCoefficients> node.\n");
1022  *doingfine = FALSE;
1023  return SCIP_OKAY;
1024  }
1025 
1026  nqterms = (int)strtol(attrval, (char**)&attrval, 10);
1027  if( *attrval != '\0' || nqterms < 0 )
1028  {
1029  SCIPerrorMessage("Invalid value '%s' for \"numberOfQuadraticTerms\" attribute of <quadraticCoefficients> node.\n", xmlGetAttrval(quadcoef, "numberOfQuadraticTerms"));
1030  *doingfine = FALSE;
1031  return SCIP_OKAY;
1032  }
1033  assert(nqterms >= 0);
1034 
1035  count = 0;
1036  for( qterm = xmlFirstChild(quadcoef); qterm != NULL; qterm = xmlNextSibl(qterm), ++count )
1037  {
1038  /* check for qterm node */
1039  if( strcmp(xmlGetName(qterm), "qTerm") != 0 )
1040  {
1041  SCIPerrorMessage("Expected <qTerm> node under <quadraticCoefficients> node, but got <%s>\n", xmlGetName(qterm));
1042  *doingfine = FALSE;
1043  return SCIP_OKAY;
1044  }
1045  if( count >= nqterms )
1046  {
1047  SCIPerrorMessage("Too many quadratic terms under <quadraticCoefficients> node, expected %d many, but got at least %d.\n", nqterms, count + 1);
1048  *doingfine = FALSE;
1049  return SCIP_OKAY;
1050  }
1051 
1052  /* get constraint index, or -1 for objective */
1053  attrval = xmlGetAttrval(qterm, "idx");
1054  if( attrval == NULL )
1055  {
1056  SCIPerrorMessage("Missing \"idx\" attribute in %d'th <qTerm> node under <quadraticCoefficients> node.\n", count);
1057  *doingfine = FALSE;
1058  return SCIP_OKAY;
1059  }
1060 
1061  considx = (int)strtol(attrval, (char**)&attrval, 10);
1062  if( *attrval != '\0' || considx < -1 || considx >= nconss )
1063  {
1064  SCIPerrorMessage("Invalid value '%s' in \"idx\" attribute of %d'th <qTerm> node under <quadraticCoefficients> node.\n", xmlGetAttrval(qterm, "idx"), count);
1065  *doingfine = FALSE;
1066  return SCIP_OKAY;
1067  }
1068 
1069  /* get index of first variable */
1070  attrval = xmlGetAttrval(qterm, "idxOne");
1071  if( attrval == NULL )
1072  {
1073  SCIPerrorMessage("Missing \"idxOne\" attribute in %d'th <qTerm> node under <quadraticCoefficients> node.\n", count);
1074  *doingfine = FALSE;
1075  return SCIP_OKAY;
1076  }
1077 
1078  varidx1 = (int)strtol(attrval, (char**)&attrval, 10);
1079  if( *attrval != '\0' || varidx1 < 0 || varidx1 >= nvars )
1080  {
1081  SCIPerrorMessage("Invalid value '%s' in \"idxOne\" attribute of %d'th <qTerm> node under <quadraticCoefficients> node.\n", xmlGetAttrval(qterm, "idxOne"), count);
1082  *doingfine = FALSE;
1083  return SCIP_OKAY;
1084  }
1085 
1086  /* get index of second variable */
1087  attrval = xmlGetAttrval(qterm, "idxTwo");
1088  if( attrval == NULL )
1089  {
1090  SCIPerrorMessage("Missing \"idxTwo\" attribute in %d'th <qTerm> node under <quadraticCoefficients> node.\n", count);
1091  *doingfine = FALSE;
1092  return SCIP_OKAY;
1093  }
1094 
1095  varidx2 = (int)strtol(attrval, (char**)&attrval, 10);
1096  if( *attrval != '\0' || varidx2 < 0 || varidx2 >= nvars )
1097  {
1098  SCIPerrorMessage("Invalid value '%s' in \"idxTwo\" attribute of %d'th <qTerm> node under <quadraticCoefficients> node.\n", xmlGetAttrval(qterm, "idxTwo"), count);
1099  *doingfine = FALSE;
1100  return SCIP_OKAY;
1101  }
1102 
1103  /* get (optional) coefficient of quadratic term */
1104  attrval = xmlGetAttrval(qterm, "coef");
1105  if( attrval != NULL )
1106  {
1107  coef = strtod(attrval, (char**)&attrval);
1108  if( *attrval != '\0' || (coef != coef) ) /*lint !e777*/
1109  {
1110  SCIPerrorMessage("Invalid value '%s' in \"coef\" attribute of %d'th <qTerm> node under <quadraticCoefficients> node.\n", xmlGetAttrval(qterm, "coef"), count);
1111  *doingfine = FALSE;
1112  return SCIP_OKAY;
1113  }
1114  }
1115  else
1116  {
1117  /* default is 1.0 according to specification */
1118  coef = 1.0;
1119  }
1120 
1121  /* skip zero coefficients */
1122  if( coef == 0.0 )
1123  continue;
1124 
1125  if( considx == -1 )
1126  {
1127  if( *objcons == NULL )
1128  {
1129  /* create constraint to hold quadratic part of objective; note that
1130  * reading/{initialconss,dynamicconss,dynamicrows,dynamiccols} apply only to model constraints and
1131  * variables, not to an auxiliary objective constraint (otherwise it can happen that an auxiliary objective
1132  * variable is loose with infinite best bound, triggering the problem that an LP that is unbounded because
1133  * of loose variables with infinite best bound cannot be solved)
1134  */
1135 
1136  SCIP_VAR* objvar;
1137  SCIP_Real minusone;
1138 
1139  SCIP_CALL( SCIPcreateVar(scip, &objvar, "objvar", -SCIPinfinity(scip), SCIPinfinity(scip), 1.0,
1141  SCIP_CALL( SCIPaddVar(scip, objvar) );
1142 
1143  minusone = -1.0;
1144  SCIP_CALL( SCIPcreateConsQuadratic(scip, objcons, "objcons", 1, &objvar, &minusone, 0, NULL, NULL, NULL,
1145  SCIPgetObjsense(scip) == SCIP_OBJSENSE_MINIMIZE ? -SCIPinfinity(scip) : 0.0,
1146  SCIPgetObjsense(scip) == SCIP_OBJSENSE_MAXIMIZE ? SCIPinfinity(scip) : 0.0,
1147  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
1148  *objconstype = QUADRATIC;
1149 
1150  SCIP_CALL( SCIPreleaseVar(scip, &objvar) );
1151  }
1152  cons = *objcons;
1153  assert(*objconstype == QUADRATIC);
1154  }
1155  else if( constypes[considx] == LINEAR ) /*lint !e613*/
1156  {
1157  /* replace linear constraint by quadratic constraint */
1158  cons = conss[considx]; /*lint !e613*/
1159 
1161  SCIPgetNVarsLinear(scip, cons), SCIPgetVarsLinear(scip, cons), SCIPgetValsLinear(scip, cons),
1162  0, NULL, NULL, NULL,
1163  SCIPgetLhsLinear(scip, cons), SCIPgetRhsLinear(scip, cons),
1167 
1168  SCIP_CALL( SCIPreleaseCons(scip, &conss[considx]) ); /*lint !e613*/
1169 
1170  conss[considx] = cons; /*lint !e613*/
1171  constypes[considx] = QUADRATIC; /*lint !e613*/
1172  }
1173  else
1174  {
1175  cons = conss[considx]; /*lint !e613*/
1176  assert(constypes[considx] == QUADRATIC); /*lint !e613*/
1177  }
1178 
1179  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, cons, vars[varidx1], vars[varidx2], coef) ); /*lint !e613*/
1180  }
1181 
1182  if( count != nqterms )
1183  {
1184  SCIPerrorMessage("Got only %d quadratic terms under <quadraticCoefficients> node, but expected %d many.\n", count, nqterms);
1185  *doingfine = FALSE;
1186  return SCIP_OKAY;
1187  }
1188 
1189  return SCIP_OKAY;
1190 }
1191 
1192 /** transforms OSnL expression tree into SCIP expression */
1193 static
1195  SCIP* scip, /**< SCIP data structure */
1196  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
1197  const XML_NODE* node, /**< root node of expression to be read */
1198  int* exprvaridx, /**< array with index of problem variables in expression graph */
1199  int* nexprvars, /**< number of variables in currently processed expression so far */
1200  int nvars, /**< total number of variables in problem (and length of exprvaridx array) */
1201  SCIP_Bool* doingfine /**< buffer to indicate whether no errors occurred */
1202  )
1203 {
1204  const char* exprname;
1205 
1206  assert(scip != NULL);
1207  assert(expr != NULL);
1208  assert(node != NULL);
1209  assert(exprvaridx != NULL || nvars == 0);
1210  assert(nexprvars != NULL);
1211  assert(doingfine != NULL);
1212 
1213  exprname = xmlGetName(node);
1214  assert(exprname != NULL);
1215 
1216  *expr = NULL;
1217 
1218  /* zero argument operands */
1219  if( strcmp(exprname, "variable") == 0 )
1220  {
1221  const char* attrval;
1222  SCIP_Real coef;
1223  int idx;
1224 
1225  /* read variable index */
1226  attrval = xmlGetAttrval(node, "idx");
1227  if( attrval == NULL )
1228  {
1229  SCIPerrorMessage("Attribute \"idx\" required for <variable> node in nonlinear expression\n");
1230  *doingfine = FALSE;
1231  return SCIP_OKAY;
1232  }
1233 
1234  idx = (int)strtol(attrval, (char**)&attrval, 10);
1235  if( *attrval != '\0' || idx < 0 || idx >= nvars )
1236  {
1237  SCIPerrorMessage("Invalid value '%s' in \"idx\" attribute of <variable> node in nonlinear expression.\n", xmlGetAttrval(node, "idx"));
1238  *doingfine = FALSE;
1239  return SCIP_OKAY;
1240  }
1241 
1242  /* read variable coefficient */
1243  attrval = xmlGetAttrval(node, "coef");
1244  if( attrval != NULL )
1245  {
1246  coef = strtod(attrval, (char**)&attrval);
1247  if( *attrval != '\0' || !SCIPisFinite(coef) )
1248  {
1249  SCIPerrorMessage("Invalid value '%s' in \"coef\" attribute of <variable> node in nonlinear expression.\n", xmlGetAttrval(node, "coef"));
1250  *doingfine = FALSE;
1251  return SCIP_OKAY;
1252  }
1253  }
1254  else
1255  {
1256  coef = 1.0;
1257  }
1258 
1259  /* assign index to variable, if we see it the first time */
1260  if( exprvaridx[idx] == -1 ) /*lint !e613*/
1261  {
1262  exprvaridx[idx] = *nexprvars; /*lint !e613*/
1263  ++*nexprvars;
1264  }
1265 
1266  /* create VARIDX expression, put into LINEAR expression if we have coefficient != 1 */
1267  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_VARIDX, exprvaridx[idx]) ); /*lint !e613*/
1268  if( coef != 1.0 )
1269  {
1270  SCIP_CALL( SCIPexprCreateLinear(SCIPblkmem(scip), expr, 1, expr, &coef, 0.0) );
1271  }
1272 
1273  return SCIP_OKAY;
1274  }
1275 
1276  if( strcmp(exprname, "number") == 0 )
1277  {
1278  const char* attrval;
1279  SCIP_Real val;
1280 
1281  attrval = xmlGetAttrval(node, "type");
1282  if( attrval != NULL && (strcmp(attrval, "real") != 0) )
1283  {
1284  SCIPerrorMessage("Type '%s' for <number> node in nonlinear expression not supported.\n", attrval);
1285  *doingfine = FALSE;
1286  return SCIP_OKAY;
1287  }
1288 
1289  attrval = xmlGetAttrval(node, "value");
1290  if( attrval != NULL )
1291  {
1292  val = strtod(attrval, (char**)&attrval);
1293  if( *attrval != '\0' || !SCIPisFinite(val) )
1294  {
1295  SCIPerrorMessage("Invalid value '%s' in \"value\" attribute of <number> node in nonlinear expression.\n", xmlGetAttrval(node, "value"));
1296  *doingfine = FALSE;
1297  return SCIP_OKAY;
1298  }
1299  }
1300  else
1301  {
1302  /* according to OSnL.xsd, the value attribute is optional
1303  * I guess the default is the empty string, which should correspond to 0.0
1304  */
1305  val = 0.0;
1306  }
1307 
1308  /* create CONST expression */
1309  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_CONST, val) );
1310 
1311  return SCIP_OKAY;
1312  }
1313 
1314  if( strcmp(exprname, "PI") == 0 )
1315  {
1316  /* create CONST expression with PI value*/
1318 
1319  return SCIP_OKAY;
1320  }
1321 
1322  if( strcmp(exprname, "E") == 0 )
1323  {
1324  /* create CONST expression with E value*/
1326 
1327  return SCIP_OKAY;
1328  }
1329 
1330 
1331  /* single argument operands */
1332  if( strcmp(exprname, "negate") == 0 ||
1333  strcmp(exprname, "abs") == 0 ||
1334  strcmp(exprname, "squareRoot") == 0 ||
1335  strcmp(exprname, "sqrt") == 0 ||
1336  strcmp(exprname, "square") == 0 ||
1337  strcmp(exprname, "exp") == 0 ||
1338  strcmp(exprname, "ln") == 0 ||
1339  strcmp(exprname, "log10") == 0
1340  )
1341  {
1342  SCIP_EXPR* arg;
1343 
1344  /* check number of children */
1345  if( xmlFirstChild(node) == NULL || xmlNextSibl(xmlFirstChild(node)) != NULL )
1346  {
1347  SCIPerrorMessage("Expected exactly one child in <%s> node in nonlinear expression\n", exprname);
1348  *doingfine = FALSE;
1349  return SCIP_OKAY;
1350  }
1351 
1352  /* read child expression */
1353  SCIP_CALL( readExpression(scip, &arg, xmlFirstChild(node), exprvaridx, nexprvars, nvars, doingfine) );
1354  if( !*doingfine )
1355  return SCIP_OKAY;
1356 
1357  /* create SCIP expression according to expression name */
1358  if( strcmp(exprname, "negate") == 0 )
1359  {
1360  SCIP_Real minusone;
1361 
1362  minusone = -1.0;
1363  SCIP_CALL( SCIPexprCreateLinear(SCIPblkmem(scip), expr, 1, &arg, &minusone, 0.0) );
1364  }
1365  else if( strcmp(exprname, "abs") == 0 )
1366  {
1367  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_ABS, arg) );
1368  }
1369  else if( strcmp(exprname, "squareRoot") == 0 || strcmp(exprname, "sqrt") == 0 )
1370  {
1371  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_SQRT, arg) );
1372  }
1373  else if( strcmp(exprname, "square") == 0 )
1374  {
1375  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_SQUARE, arg) );
1376  }
1377  else if( strcmp(exprname, "exp") == 0 )
1378  {
1379  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_EXP, arg) );
1380  }
1381  else if( strcmp(exprname, "ln") == 0 )
1382  {
1383  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_LOG, arg) );
1384  }
1385  else /* if( strcmp(exprname, "log10") == 0 ) */
1386  {
1387  /* log10(expr) = ln(expr)*1/ln(10) */
1388  SCIP_EXPR* tmp;
1389 
1390  assert(strcmp(exprname, "log10") == 0);
1391 
1392  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0/log(10.0)) );
1393  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &arg, SCIP_EXPR_LOG, arg) );
1394  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_MUL, arg, tmp) );
1395  }
1396 
1397  return SCIP_OKAY;
1398  }
1399 
1400  /* two argument operands */
1401  if( strcmp(exprname, "plus") == 0 ||
1402  strcmp(exprname, "minus") == 0 ||
1403  strcmp(exprname, "times") == 0 ||
1404  strcmp(exprname, "divide") == 0 ||
1405  strcmp(exprname, "power") == 0 ||
1406  strcmp(exprname, "log") == 0
1407  )
1408  {
1409  SCIP_EXPR* arg1;
1410  SCIP_EXPR* arg2;
1411 
1412  /* check number of children */
1413  if( xmlFirstChild(node) == NULL ||
1414  xmlNextSibl(xmlFirstChild(node)) == NULL ||
1416  {
1417  SCIPerrorMessage("Expected exactly two children in <%s> node in nonlinear expression.\n", exprname);
1418  *doingfine = FALSE;
1419  return SCIP_OKAY;
1420  }
1421 
1422  /* read first child expression */
1423  SCIP_CALL( readExpression(scip, &arg1, xmlFirstChild(node), exprvaridx, nexprvars, nvars, doingfine) );
1424  if( !*doingfine )
1425  return SCIP_OKAY;
1426 
1427  /* read second child expression */
1428  SCIP_CALL( readExpression(scip, &arg2, xmlNextSibl(xmlFirstChild(node)), exprvaridx, nexprvars, nvars, doingfine) );
1429  if( !*doingfine )
1430  {
1431  SCIPexprFreeDeep(SCIPblkmem(scip), &arg1);
1432  return SCIP_OKAY;
1433  }
1434 
1435  if( strcmp(exprname, "plus") == 0 )
1436  {
1437  SCIP_CALL( SCIPexprAdd(SCIPblkmem(scip), expr, 1.0, arg1, 1.0, arg2, 0.0) );
1438  /* SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_PLUS, arg1, arg2) ); */
1439  }
1440  else if( strcmp(exprname, "minus") == 0 )
1441  {
1442  SCIP_CALL( SCIPexprAdd(SCIPblkmem(scip), expr, 1.0, arg1, -1.0, arg2, 0.0) );
1443  /* SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_MINUS, arg1, arg2) ); */
1444  }
1445  else if( strcmp(exprname, "times") == 0 )
1446  {
1447  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
1448  {
1449  SCIP_CALL( SCIPexprMulConstant(SCIPblkmem(scip), expr, arg2, SCIPexprGetOpReal(arg1)) );
1450  }
1451  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
1452  {
1453  SCIP_CALL( SCIPexprMulConstant(SCIPblkmem(scip), expr, arg1, SCIPexprGetOpReal(arg2)) );
1454  }
1455  else
1456  {
1457  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_MUL, arg1, arg2) );
1458  }
1459  }
1460  else if( strcmp(exprname, "divide") == 0 )
1461  {
1462  if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
1463  {
1464  assert(SCIPexprGetOpReal(arg2) != 0.0);
1465  SCIP_CALL( SCIPexprMulConstant(SCIPblkmem(scip), expr, arg1, 1.0/SCIPexprGetOpReal(arg2)) );
1466  }
1467  else
1468  {
1469  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_DIV, arg1, arg2) );
1470  }
1471  }
1472  else if( strcmp(exprname, "power") == 0 )
1473  {
1474  if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
1475  {
1476  /* expr^number is intpower or realpower */
1477  if( SCIPisIntegral(scip, SCIPexprGetOpReal(arg2)) )
1478  {
1479  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_INTPOWER, arg1, (int)SCIPround(scip, SCIPexprGetOpReal(arg2))) );
1480  }
1481  else
1482  {
1484  }
1485  }
1486  else if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
1487  {
1488  /* number^arg2 is exp(arg2 * ln(number)) */
1489  if( SCIPexprGetOpReal(arg1) < 0.0 )
1490  {
1491  SCIPerrorMessage("Negative base in <power> node with nonconstant exponent not allowed in nonlinear expression.\n");
1492  SCIPexprFreeDeep(SCIPblkmem(scip), &arg1);
1493  SCIPexprFreeDeep(SCIPblkmem(scip), &arg2);
1494  *doingfine = FALSE;
1495  return SCIP_OKAY;
1496  }
1497  else
1498  {
1499  SCIP_EXPR* tmp;
1500 
1502  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_MUL, tmp, arg2) );
1503  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_EXP, tmp) );
1504  }
1505  }
1506  else
1507  {
1508  /* arg1^arg2 is exp(arg2 * ln(arg1)) */
1509  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &arg1, SCIP_EXPR_LOG, arg1) );
1510  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &arg2, SCIP_EXPR_MUL, arg1, arg2) );
1511  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_EXP, arg2) );
1512  }
1513  }
1514  else if( strcmp(exprname, "log") == 0 )
1515  {
1516  /* logarithm of arg2 w.r.t. base arg1 = ln(arg2) / ln(arg1) */
1517  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &arg1, SCIP_EXPR_LOG, arg1) );
1518  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &arg2, SCIP_EXPR_LOG, arg2) );
1519  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_DIV, arg2, arg1) );
1520  }
1521  else if( strcmp(exprname, "min") == 0 )
1522  {
1523  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_MIN, arg1, arg2) );
1524  }
1525  else /* if( strcmp(exprname, "max") == 0 ) */
1526  {
1527  assert(strcmp(exprname, "max") == 0);
1528 
1529  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_MAX, arg1, arg2) );
1530  }
1531 
1532  return SCIP_OKAY;
1533  }
1534 
1535  /* arbitrary argument operands */
1536  if( strcmp(exprname, "sum") == 0 || strcmp(exprname, "product") == 0 )
1537  {
1538  const XML_NODE* argnode;
1539  SCIP_EXPR** args;
1540  int nargs;
1541  int argssize;
1542 
1543  /* a sum or product w.r.t. 0 arguments is constant */
1544  if( xmlFirstChild(node) == NULL )
1545  {
1546  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_CONST, (strcmp(exprname, "sum") == 0) ? 0.0 : 1.0) );
1547 
1548  return SCIP_OKAY;
1549  }
1550 
1551  /* read all child expressions */
1552  argssize = 5;
1553  SCIP_CALL( SCIPallocBufferArray(scip, &args, argssize) );
1554 
1555  nargs = 0;
1556  for( argnode = xmlFirstChild(node); argnode != NULL; argnode = xmlNextSibl(argnode), ++nargs )
1557  {
1558  if( nargs >= argssize )
1559  {
1560  argssize = SCIPcalcMemGrowSize(scip, nargs + 1);
1561  SCIP_CALL( SCIPreallocBufferArray(scip, &args, argssize) );
1562  }
1563  assert(nargs < argssize);
1564 
1565  SCIP_CALL( readExpression(scip, &args[nargs], argnode, exprvaridx, nexprvars, nvars, doingfine) );
1566  if( !*doingfine )
1567  {
1568  assert(args[nargs] == NULL);
1569  break;
1570  }
1571  }
1572 
1573  if( *doingfine )
1574  {
1575  switch( nargs )
1576  {
1577  case 0:
1578  {
1579  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_CONST, (strcmp(exprname, "sum") == 0) ? 0.0 : 1.0) );
1580  break;
1581  }
1582  case 1:
1583  {
1584  *expr = args[0];
1585  break;
1586  }
1587  case 2:
1588  {
1589  if( strcmp(exprname, "sum") == 0 )
1590  {
1591  SCIP_CALL( SCIPexprAdd(SCIPblkmem(scip), expr, 1.0, args[0], 1.0, args[1], 0.0) );
1592  }
1593  else
1594  {
1595  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, SCIP_EXPR_MUL, args[0], args[1]) );
1596  }
1597  break;
1598  }
1599  default:
1600  {
1601  /* create sum or product expression */
1602  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, (strcmp(exprname, "sum") == 0) ? SCIP_EXPR_SUM : SCIP_EXPR_PRODUCT, nargs, args) );
1603  break;
1604  }
1605  }
1606  }
1607  else
1608  {
1609  /* cleanup if parsing error */
1610  for( ; nargs > 0; --nargs )
1611  SCIPexprFreeDeep(SCIPblkmem(scip), &args[nargs-1]);
1612  }
1613 
1614  SCIPfreeBufferArray(scip, &args);
1615 
1616  return SCIP_OKAY;
1617  }
1618 
1619  if( strcmp(exprname, "min") == 0 || strcmp(exprname, "max") == 0 )
1620  {
1621  const XML_NODE* argnode;
1622  SCIP_EXPROP exprop;
1623  SCIP_EXPR* arg2;
1624 
1625  /* check that we have children */
1626  if( xmlFirstChild(node) == NULL )
1627  {
1628  SCIPerrorMessage("Expected at least one child in <%s> node of nonlinear expression.\n", exprname);
1629  *doingfine = FALSE;
1630  return SCIP_OKAY;
1631  }
1632 
1633  /* read expression corresponding to first child and store in expr */
1634  argnode = xmlFirstChild(node);
1635  SCIP_CALL( readExpression(scip, expr, argnode, exprvaridx, nexprvars, nvars, doingfine) );
1636  if( !*doingfine )
1637  {
1638  assert(*expr == NULL);
1639  return SCIP_OKAY;
1640  }
1641  arg2 = NULL;
1642 
1643  exprop = (strcmp(exprname, "min") == 0) ? SCIP_EXPR_MIN : SCIP_EXPR_MAX;
1644 
1645  /* read expressions corresponding to other children in arg and store exprop(expr, arg) in expr */
1646  for( argnode = xmlNextSibl(argnode); argnode != NULL; argnode = xmlNextSibl(argnode) )
1647  {
1648  assert(arg2 == NULL);
1649  SCIP_CALL( readExpression(scip, &arg2, argnode, exprvaridx, nexprvars, nvars, doingfine) );
1650  if( !*doingfine )
1651  {
1652  assert(arg2 == NULL);
1653  break;
1654  }
1655 
1656  assert(*expr != NULL);
1657  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), expr, exprop, *expr, arg2) );
1658  arg2 = NULL;
1659  }
1660 
1661  if( !*doingfine )
1662  {
1663  /* cleanup if failure */
1664  SCIPexprFreeDeep(SCIPblkmem(scip), expr);
1665  }
1666  assert(arg2 == NULL);
1667 
1668  return SCIP_OKAY;
1669  }
1670 
1671  if( strcmp(exprname, "quadratic") == 0 )
1672  {
1673  const char* attrval;
1674  const XML_NODE* qterm;
1675  SCIP_QUADELEM* quadelems;
1676  int nquadelems;
1677  int quadelemssize;
1678  int* quadvarsidxs;
1679  int nquadvars;
1680  int i;
1681 
1682  quadelemssize = 5;
1683  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, quadelemssize) );
1684  nquadelems = 0;
1685 
1686  SCIP_CALL( SCIPallocBufferArray(scip, &quadvarsidxs, nvars) );
1687  for( i = 0; i < nvars; ++i )
1688  quadvarsidxs[i] = -1;
1689  nquadvars = 0;
1690 
1691  /* read quadratic terms */
1692  for( qterm = xmlFirstChild(node); qterm != NULL; qterm = xmlNextSibl(qterm), ++nquadelems )
1693  {
1694  /* check for qpTerm node */
1695  if( strcmp(xmlGetName(qterm), "qpTerm") != 0 )
1696  {
1697  SCIPerrorMessage("Unexpected <%s> node under <quadratic> node in nonlinear expression, expected <qpTerm>.\n", xmlGetName(qterm));
1698  *doingfine = FALSE;
1699  break;
1700  }
1701 
1702  if( nquadelems >= quadelemssize )
1703  {
1704  quadelemssize = SCIPcalcMemGrowSize(scip, nquadelems + 1);
1705  SCIP_CALL( SCIPreallocBufferArray(scip, &quadelems, quadelemssize) );
1706  }
1707  assert(quadelemssize > nquadelems);
1708 
1709  /* get index of first variable */
1710  attrval = xmlGetAttrval(qterm, "idxOne");
1711  if( attrval == NULL )
1712  {
1713  SCIPerrorMessage("Missing \"idxOne\" attribute in %d'th <qpTerm> node under <quadratic> node in nonlinear expression.\n", nquadelems);
1714  *doingfine = FALSE;
1715  break;
1716  }
1717 
1718  quadelems[nquadelems].idx1 = (int)strtol(attrval, (char**)&attrval, 10);
1719  if( *attrval != '\0' || quadelems[nquadelems].idx1 < 0 || quadelems[nquadelems].idx1 >= nvars )
1720  {
1721  SCIPerrorMessage("Invalid value '%s' for \"idxOne\" attribute of %d'th <qpTerm> node under <quadratic> node in nonlinear expression.\n", xmlGetAttrval(qterm, "idxOne"), nquadelems);
1722  *doingfine = FALSE;
1723  break;
1724  }
1725 
1726  /* get index of second variable */
1727  attrval = xmlGetAttrval(qterm, "idxTwo");
1728  if( attrval == NULL )
1729  {
1730  SCIPerrorMessage("Missing \"idxTwo\" attribute in %d'th <qpTerm> node under <quadratic> node in nonlinear expression.\n", nquadelems);
1731  *doingfine = FALSE;
1732  break;
1733  }
1734 
1735  quadelems[nquadelems].idx2 = (int)strtol(attrval, (char**)&attrval, 10);
1736  if( *attrval != '\0' || quadelems[nquadelems].idx2 < 0 || quadelems[nquadelems].idx2 >= nvars )
1737  {
1738  SCIPerrorMessage("Invalid value '%s' for \"idxTwo\" attribute of %d'th <qpTerm> node under <quadratic> node in nonlinear expression.\n", xmlGetAttrval(qterm, "idxTwo"), nquadelems);
1739  *doingfine = FALSE;
1740  break;
1741  }
1742 
1743  /* get coefficient */
1744  attrval = xmlGetAttrval(qterm, "coef");
1745  if( attrval != NULL )
1746  {
1747  quadelems[nquadelems].coef = strtod(attrval, (char**)&attrval);
1748  if( *attrval != '\0' || (quadelems[nquadelems].coef != quadelems[nquadelems].coef) ) /*lint !e777*/
1749  {
1750  SCIPerrorMessage("Invalid value '%s' for \"coef\" attribute of %d'th <qpTerm> node under <quadratic> node in nonlinear expression.\n", xmlGetAttrval(qterm, "coef"), nquadelems);
1751  *doingfine = FALSE;
1752  break;
1753  }
1754  }
1755  else
1756  {
1757  quadelems[nquadelems].coef = 1.0;
1758  }
1759 
1760  /* get index for first variable in quadratic element */
1761  if( quadvarsidxs[quadelems[nquadelems].idx1] < 0 )
1762  {
1763  quadvarsidxs[quadelems[nquadelems].idx1] = nquadvars;
1764  quadelems[nquadelems].idx1 = nquadvars;
1765 
1766  ++nquadvars;
1767  }
1768  else
1769  {
1770  quadelems[nquadelems].idx1 = quadvarsidxs[quadelems[nquadelems].idx1];
1771  }
1772 
1773  /* get index for second variable in quadratic element */
1774  if( quadvarsidxs[quadelems[nquadelems].idx2] < 0 )
1775  {
1776  quadvarsidxs[quadelems[nquadelems].idx2] = nquadvars;
1777  quadelems[nquadelems].idx2 = nquadvars;
1778 
1779  ++nquadvars;
1780  }
1781  else
1782  {
1783  quadelems[nquadelems].idx2 = quadvarsidxs[quadelems[nquadelems].idx2];
1784  }
1785 
1786  /* swap indices if in wrong order */
1787  if( quadelems[nquadelems].idx1 > quadelems[nquadelems].idx2 )
1788  {
1789  int tmp;
1790 
1791  tmp = quadelems[nquadelems].idx1;
1792  quadelems[nquadelems].idx1 = quadelems[nquadelems].idx2;
1793  quadelems[nquadelems].idx2 = tmp;
1794  }
1795  }
1796 
1797  if( *doingfine )
1798  {
1799  SCIP_EXPR** children;
1800 
1801  /* setup array with children expressions corresponding to variables */
1802  SCIP_CALL( SCIPallocBufferArray(scip, &children, nquadvars) );
1803  for( i = 0; i < nvars; ++i )
1804  {
1805  if( quadvarsidxs[i] == -1 )
1806  continue;
1807 
1808  /* assign new index to variable, if we see it the first time in this exprtree */
1809  if( exprvaridx[i] == -1 ) /*lint !e613*/
1810  {
1811  exprvaridx[i] = *nexprvars; /*lint !e613*/
1812  ++*nexprvars;
1813  }
1814 
1815  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &children[quadvarsidxs[i]], SCIP_EXPR_VARIDX, exprvaridx[i]) ); /*lint !e613*/
1816  }
1817 
1818  /* create quadratic expression */
1819  SCIP_CALL( SCIPexprCreateQuadratic(SCIPblkmem(scip), expr, nquadvars, children, 0.0, NULL, nquadelems, quadelems) );
1820 
1821  SCIPfreeBufferArray(scip, &children);
1822  }
1823 
1824  SCIPfreeBufferArray(scip, &quadelems);
1825  SCIPfreeBufferArray(scip, &quadvarsidxs);
1826  }
1827 
1828 
1829  SCIPerrorMessage("Expression operand <%s> in nonlinear expression not supported by SCIP so far.\n", exprname);
1830  *doingfine = FALSE;
1831 
1832  return SCIP_OKAY;
1833 }
1834 
1835 
1836 /** read nonlinear expressions of constraints and objective */
1837 static
1839  SCIP* scip, /**< SCIP data structure */
1840  const XML_NODE* datanode, /**< XML root node for instance data */
1841  SCIP_VAR** vars, /**< variables in order of OSiL indices */
1842  int nvars, /**< number of variables */
1843  SCIP_CONS** conss, /**< constraints in order of OSiL indices */
1844  CONSTYPE* constypes, /**< type of constraints (assumed to be LINEAR) */
1845  int nconss, /**< number of constraints */
1846  SCIP_CONS** objcons, /**< buffer to store constraint for nonlinear part of objective function, or to add to if already existing */
1847  CONSTYPE* objconstype, /**< buffer to store type of objective constraint, if created (should be QUADRATIC) */
1848  SCIP_Bool* doingfine /**< buffer to indicate whether no errors occurred */
1849  )
1850 {
1851  const XML_NODE* nlexprs;
1852  const XML_NODE* nlexpr;
1853  const char* attrval;
1854  SCIP_EXPRTREE* exprtree;
1855  SCIP_EXPR* expr;
1856  SCIP_VAR** exprvars;
1857  int* exprvaridx;
1858  int nexprvars;
1859  int nnlexprs;
1860  int count;
1861  int considx;
1862  int i;
1863 
1864  assert(scip != NULL);
1865  assert(datanode != NULL);
1866  assert(vars != NULL || nvars == 0);
1867  assert(conss != NULL || nconss == 0);
1868  assert(constypes != NULL || nconss == 0);
1869  assert(objcons != NULL);
1870  assert(doingfine != NULL);
1871 
1872  nlexprs = xmlFindNodeMaxdepth(datanode, "nonlinearExpressions", 0, 1);
1873 
1874  if( nlexprs == NULL )
1875  return SCIP_OKAY;
1876 
1877  /* get number of nonlinear expressions */
1878  attrval = xmlGetAttrval(nlexprs, "numberOfNonlinearExpressions");
1879  if( attrval == NULL )
1880  {
1881  SCIPerrorMessage("Attribute \"numberOfNonlinearExpressions\" in <nonlinearExpressions> node not found.\n");
1882  *doingfine = FALSE;
1883  return SCIP_OKAY;
1884  }
1885 
1886  nnlexprs = (int)strtol(attrval, (char**)&attrval, 10);
1887  if( *attrval != '\0' || nnlexprs < 0 )
1888  {
1889  SCIPerrorMessage("Invalid value '%s' for \"numberOfNonlinearExpressions\" attribute in <nonlinearExpressions>.\n", xmlGetAttrval(nlexprs, "numberOfNonlinearExpressions"));
1890  *doingfine = FALSE;
1891  return SCIP_OKAY;
1892  }
1893  assert(nnlexprs >= 0);
1894 
1895  /* buffer array to store index of variable in expression graph, or -1 if not present */
1896  SCIP_CALL( SCIPallocBufferArray(scip, &exprvaridx, nvars) );
1897  SCIP_CALL( SCIPallocBufferArray(scip, &exprvars, nvars) );
1898 
1899  /* read nonlinear expressions and store in constraints */
1900  count = 0;
1901  for( nlexpr = xmlFirstChild(nlexprs); nlexpr != NULL; nlexpr = xmlNextSibl(nlexpr), ++count )
1902  {
1903  if( strcmp(xmlGetName(nlexpr), "nl") != 0 )
1904  {
1905  SCIPerrorMessage("Expected <nl> node under <nonlinearExpressions> node, but got '%s'.\n", xmlGetName(nlexpr));
1906  *doingfine = FALSE;
1907  break;
1908  }
1909  if( count >= nnlexprs )
1910  {
1911  SCIPerrorMessage("Too many nonlinear expressions under <nonlinearExpressions> node, expected %d many, but got at least %d.\n", nnlexprs, count + 1);
1912  *doingfine = FALSE;
1913  break;
1914  }
1915 
1916  /* treat empty expression as 0.0 and continue */
1917  if( xmlFirstChild(nlexprs) == NULL )
1918  continue;
1919 
1920  /* get constraint index, or -1 for objective */
1921  attrval = xmlGetAttrval(nlexpr, "idx");
1922  if( attrval == NULL )
1923  {
1924  SCIPerrorMessage("Missing \"idx\" attribute in %d'th <nl> node under <nonlinearExpressions> node.\n", count);
1925  *doingfine = FALSE;
1926  break;
1927  }
1928 
1929  considx = (int)strtol(attrval, (char**)&attrval, 10);
1930  if( *attrval != '\0' || considx < -1 || considx >= nconss )
1931  {
1932  SCIPerrorMessage("Invalid value '%s' in \"idx\" attribute of %d'th <nl> node under <nonlinearExpressions> node.\n", xmlGetAttrval(nlexpr, "idx"), count);
1933  *doingfine = FALSE;
1934  break;
1935  }
1936 
1937  expr = NULL;
1938  nexprvars = 0;
1939  for( i = 0; i < nvars; ++i )
1940  exprvaridx[i] = -1;
1941 
1942  /* turn OSiL expression into SCIP expression and assign indices to variables */
1943  SCIP_CALL( readExpression(scip, &expr, xmlFirstChild(nlexpr), exprvaridx, &nexprvars, nvars, doingfine) );
1944  if( !*doingfine )
1945  {
1946  assert(expr == NULL);
1947  break;
1948  }
1949 
1950  /* assemble array with SCIP_VAR*'s */
1951  for( i = 0; i < nvars; ++i )
1952  {
1953  assert(exprvaridx[i] < nexprvars );
1954 
1955  if( exprvaridx[i] >= 0 )
1956  exprvars[exprvaridx[i]] = vars[i]; /*lint !e613*/
1957  }
1958 
1959  /* create expression tree */
1960  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &exprtree, expr, nexprvars, 0, NULL) );
1961  SCIP_CALL( SCIPexprtreeSetVars(exprtree, nexprvars, exprvars) );
1962 
1963  /* add expression tree to objective or constraint */
1964  if( considx == -1 && *objcons == NULL )
1965  {
1966  /* create constraint to hold nonlinear part of objective; note that
1967  * reading/{initialconss,dynamicconss,dynamicrows,dynamiccols} apply only to model constraints and variables,
1968  * not to an auxiliary objective constraint (otherwise it can happen that an auxiliary objective variable is
1969  * loose with infinite best bound, triggering the problem that an LP that is unbounded because of loose
1970  * variables with infinite best bound cannot be solved)
1971  */
1972 
1973  SCIP_VAR* objvar;
1974  SCIP_Real minusone;
1975  SCIP_Real one;
1976 
1977  SCIP_CALL( SCIPcreateVar(scip, &objvar, "objvar", -SCIPinfinity(scip), SCIPinfinity(scip), 1.0,
1979  SCIP_CALL( SCIPaddVar(scip, objvar) );
1980 
1981  minusone = -1.0;
1982  one = 1.0;
1983  SCIP_CALL( SCIPcreateConsNonlinear(scip, objcons, "objcons", 1, &objvar, &minusone, 1, &exprtree, &one,
1984  SCIPgetObjsense(scip) == SCIP_OBJSENSE_MINIMIZE ? -SCIPinfinity(scip) : 0.0,
1985  SCIPgetObjsense(scip) == SCIP_OBJSENSE_MAXIMIZE ? SCIPinfinity(scip) : 0.0,
1986  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
1987  *objconstype = NONLINEAR;
1988 
1989  SCIP_CALL( SCIPreleaseVar(scip, &objvar) );
1990  }
1991  else
1992  {
1993  SCIP_CONS** cons;
1994  SCIP_CONS* oldcons;
1995  CONSTYPE* constype;
1996 
1997  if( considx == -1 )
1998  {
1999  cons = objcons;
2000  constype = objconstype;
2001  }
2002  else
2003  {
2004  cons = &conss[considx]; /*lint !e613*/
2005  constype = &constypes[considx]; /*lint !e613*/
2006  }
2007  oldcons = *cons;
2008 
2009  /* replace cons by nonlinear constraint or add to already existing nonlinear constraint */
2010  switch( *constype )
2011  {
2012  case LINEAR:
2013  {
2014  SCIP_Real one;
2015 
2016  one = 1.0;
2018  SCIPgetNVarsLinear(scip, *cons), SCIPgetVarsLinear(scip, *cons), SCIPgetValsLinear(scip, *cons),
2019  1, &exprtree, &one,
2020  SCIPgetLhsLinear(scip, *cons), SCIPgetRhsLinear(scip, *cons),
2024 
2025  SCIP_CALL( SCIPreleaseCons(scip, &oldcons) );
2026 
2027  break;
2028  }
2029 
2030  case QUADRATIC:
2031  {
2032  SCIP_EXPRTREE* exprtrees[2];
2033  SCIP_Real exprcoefs[2];
2034 
2035  SCIP_EXPR* quadexpr;
2036  SCIP_QUADELEM* quadelems;
2037  SCIP_Real* lincoefs;
2038  SCIP_EXPR** children;
2039  SCIP_QUADVARTERM* quadvarterms;
2040  SCIP_BILINTERM* bilinterms;
2041  int nquadelems;
2042  int nquadvars;
2043  int nbilin;
2044  int j;
2045 
2046  exprtrees[0] = exprtree;
2047  exprcoefs[0] = 1.0;
2048 
2049  /* turn quadratic part into expression tree */
2050  SCIP_CALL( SCIPsortQuadVarTermsQuadratic(scip, *cons) );
2051 
2052  quadvarterms = SCIPgetQuadVarTermsQuadratic(scip, *cons);
2053  nquadvars = SCIPgetNQuadVarTermsQuadratic(scip, *cons);
2054  bilinterms = SCIPgetBilinTermsQuadratic(scip, *cons);
2055  nbilin = SCIPgetNBilinTermsQuadratic(scip, *cons);
2056 
2057  SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nquadvars) );
2058  SCIP_CALL( SCIPallocBufferArray(scip, &children, nquadvars) );
2059  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nbilin + nquadvars) );
2060  nquadelems = 0;
2061 
2062  for( i = 0; i < nquadvars; ++i )
2063  {
2064  lincoefs[i] = quadvarterms[i].lincoef;
2065  exprvars[i] = quadvarterms[i].var;
2066 
2067  if( quadvarterms[i].sqrcoef != 0.0 )
2068  {
2069  quadelems[nquadelems].idx1 = i;
2070  quadelems[nquadelems].idx2 = i;
2071  quadelems[nquadelems].coef = quadvarterms[i].sqrcoef;
2072  ++nquadelems;
2073  }
2074 
2075  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &children[i], SCIP_EXPR_VARIDX, i) );
2076 
2077  for( j = 0; j < quadvarterms[i].nadjbilin; ++j )
2078  {
2079  if( bilinterms[quadvarterms[i].adjbilin[j]].var1 == quadvarterms[i].var )
2080  {
2081  int otheridx;
2082 
2083  assert(bilinterms[quadvarterms[i].adjbilin[j]].var2 != quadvarterms[i].var);
2084 
2085  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, bilinterms[quadvarterms[i].adjbilin[j]].var2, &otheridx) );
2086  assert(otheridx >= 0);
2087  assert(otheridx < nquadvars);
2088 
2089  quadelems[nquadelems].idx1 = MIN(i, otheridx);
2090  quadelems[nquadelems].idx2 = MAX(i, otheridx);
2091  quadelems[nquadelems].coef = bilinterms[quadvarterms[i].adjbilin[j]].coef;
2092  ++nquadelems;
2093  }
2094  }
2095  }
2096 
2097  SCIP_CALL( SCIPexprCreateQuadratic(SCIPblkmem(scip), &quadexpr, nquadvars, children, 0.0, lincoefs, nquadelems, quadelems) );
2098  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &exprtrees[1], quadexpr, nquadvars, 0, NULL) );
2099  SCIP_CALL( SCIPexprtreeSetVars(exprtrees[1], nquadvars, exprvars) );
2100  exprcoefs[1] = 1.0;
2101 
2102  SCIPfreeBufferArray(scip, &lincoefs);
2103  SCIPfreeBufferArray(scip, &children);
2104  SCIPfreeBufferArray(scip, &quadelems);
2105 
2108  2, exprtrees, exprcoefs,
2109  SCIPgetLhsNonlinear(scip, *cons), SCIPgetRhsNonlinear(scip, *cons),
2113 
2114  SCIP_CALL( SCIPreleaseCons(scip, &oldcons) );
2115 
2116  break;
2117  }
2118 
2119  case NONLINEAR:
2120  {
2121  SCIP_Real one;
2122 
2123  one = 1.0;
2124  SCIP_CALL( SCIPaddExprtreesNonlinear(scip, *cons, 1, &exprtree, &one) );
2125  break;
2126  }
2127  }
2128 
2129  *constype = NONLINEAR;
2130  }
2131 
2132  SCIP_CALL( SCIPexprtreeFree(&exprtree) );
2133  }
2134 
2135  SCIPfreeBufferArray(scip, &exprvars);
2136  SCIPfreeBufferArray(scip, &exprvaridx);
2137 
2138  return SCIP_OKAY;
2139 }
2140 
2141 
2142 /** read sos1 and sos2 constraints
2143  *
2144  * sos constraints are expected to be given as a node of <instanceData> in the following way:
2145  * @code
2146  * <specialOrderedSets numberOfSpecialOrderedSets="1">
2147  * <sos numberOfVar="2" order="2">
2148  * <var idx="1"></var>
2149  * <var idx="2"></var>
2150  * </sos>
2151  * </specialOrderedSets>
2152  * @endcode
2153  * Weights are determined by the order in which the variables are given
2154  *
2155  */
2156 static
2158  SCIP* scip, /**< SCIP data structure */
2159  const XML_NODE* datanode, /**< XML root node for instance data */
2160  SCIP_VAR** vars, /**< variables in order of OSiL indices */
2161  int nvars, /**< number of variables */
2162  SCIP_Bool initialconss, /**< should model constraints be marked as initial? */
2163  SCIP_Bool dynamicconss, /**< should model constraints be subject to aging? */
2164  SCIP_Bool dynamicrows, /**< should rows be added and removed dynamically to the LP? */
2165  SCIP_Bool* doingfine /**< buffer to indicate whether no errors occurred */
2166  )
2167 {
2168  const XML_NODE* soscons;
2169  const XML_NODE* sosvar;
2170  const char* attrval;
2171  int nsoscons;
2172  int nsosvars;
2173  int sosorder;
2174  int type;
2175  int count;
2176  int varcount;
2177  int idx;
2178  SCIP_Bool initial;
2179  SCIP_Bool separate;
2180  SCIP_Bool enforce;
2181  SCIP_Bool check;
2182  SCIP_Bool propagate;
2183  SCIP_Bool local;
2184  SCIP_Bool modifiable;
2185  SCIP_Bool dynamic;
2186  SCIP_Bool removable;
2187  char name[SCIP_MAXSTRLEN];
2188 
2189  /* standard settings for SOS constraints: */
2190  initial = initialconss;
2191  separate = FALSE;
2192  enforce = TRUE;
2193  check = TRUE;
2194  propagate = TRUE;
2195  local = FALSE;
2196  modifiable = FALSE;
2197  dynamic = dynamicconss;
2198  removable = dynamicrows;
2199 
2200  soscons= xmlFindNodeMaxdepth(datanode, "specialOrderedSets", 0, 1);
2201 
2202  if( soscons== NULL )
2203  return SCIP_OKAY;
2204 
2205  /* get number of sos constraints */
2206  attrval = xmlGetAttrval(soscons, "numberOfSOS");
2207  if( attrval == NULL )
2208  {
2209  SCIPerrorMessage("Attribute \"numberOfSOS in <specialOrderedSets> node not found.\n");
2210  *doingfine = FALSE;
2211  return SCIP_OKAY;
2212  }
2213 
2214  nsoscons = (int)strtol(attrval, (char**)&attrval, 10);
2215  if( *attrval != '\0' || nsoscons < 0 )
2216  {
2217  SCIPerrorMessage("Invalid value '%s' for \"numberOfSOS\" attribute in <specialOrderedSets>.\n", xmlGetAttrval(soscons, "numberOfSOS"));
2218  *doingfine = FALSE;
2219  return SCIP_OKAY;
2220  }
2221  assert(nsoscons >= 0);
2222 
2223  /* read sos constraints and create corresponding constraint */
2224  count = 0;
2225  for( soscons = xmlFirstChild(soscons); soscons != NULL; soscons = xmlNextSibl(soscons), ++count )
2226  {
2227  SCIP_CONS* cons;
2228 
2229  /* Make sure we get a sos node and not more then announced*/
2230  if( strcmp(xmlGetName(soscons), "sos") != 0 )
2231  {
2232  SCIPerrorMessage("Expected <sos> node under <specialOrderedSet> node, but got '%s'.\n", xmlGetName(soscons));
2233  *doingfine = FALSE;
2234  break;
2235  }
2236 
2237  if( count >= nsoscons)
2238  {
2239  SCIPerrorMessage("Too many sos under <specialOrderedSets> node, expected %d many, but got at least %d.\n", nsoscons, count + 1);
2240  *doingfine = FALSE;
2241  break;
2242  }
2243 
2244  /* get number of variables in this sos constraint */
2245  attrval = xmlGetAttrval(soscons, "numberOfVar");
2246  if( attrval == NULL )
2247  {
2248  SCIPerrorMessage("Attribute \"numberOfVar in <sos> node not found.\n");
2249  *doingfine = FALSE;
2250  return SCIP_OKAY;
2251  }
2252 
2253  nsosvars = (int)strtol(attrval, (char**)&attrval, 10);
2254  if( *attrval != '\0' || nsosvars < 0 )
2255  {
2256  SCIPerrorMessage("Invalid value '%s' for \"numberOfVar\" attribute in <sos>.\n", xmlGetAttrval(soscons, "numberOfVar"));
2257  *doingfine = FALSE;
2258  return SCIP_OKAY;
2259  }
2260  assert(nsosvars >= 0);
2261 
2262  /* get order of this sos constraint */
2263  attrval = xmlGetAttrval(soscons, "type");
2264  if( attrval == NULL )
2265  {
2266  SCIPerrorMessage("Attribute \"order\" in <sos> node not found.\n");
2267  *doingfine = FALSE;
2268  return SCIP_OKAY;
2269  }
2270 
2271  sosorder = (int)strtol(attrval, (char**)&attrval, 10);
2272  if( *attrval != '\0' || sosorder < 0 || sosorder > 2 )
2273  {
2274  SCIPerrorMessage("Invalid/unsupported value '%s' for \"order\" attribute in <sos>.\n", xmlGetAttrval(soscons, "order"));
2275  *doingfine = FALSE;
2276  return SCIP_OKAY;
2277  }
2278  assert(sosorder == 1 || sosorder == 2);
2279  type = sosorder;
2280 
2281  /* set artificial name for sos constraint*/
2282  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "SOS%d_%d", type, count);
2283 
2284  /* Create sos constraint */
2285  switch( type )
2286  {
2287  case 1:
2288  SCIP_CALL( SCIPcreateConsSOS1(scip, &cons, name, 0, NULL, NULL, initial, separate, enforce, check, propagate,
2289  local, modifiable, dynamic, removable) );
2290  break;
2291  case 2:
2292  SCIP_CALL( SCIPcreateConsSOS2(scip, &cons, name, 0, NULL, NULL, initial, separate, enforce, check, propagate,
2293  local, modifiable, dynamic, removable) );
2294  break;
2295  default:
2296  SCIPerrorMessage("unknown SOS type: <%d>\n", type); /* should not happen */
2297  SCIPABORT();
2298  return SCIP_INVALIDDATA; /*lint !e527*/
2299  }
2300 
2301  varcount = 0;
2302  for( sosvar = xmlFirstChild(soscons); sosvar!= NULL; sosvar = xmlNextSibl(sosvar), ++varcount )
2303  {
2304  /* get variable id*/
2305  attrval = xmlGetAttrval(sosvar, "idx");
2306  if( attrval == NULL )
2307  {
2308  SCIPerrorMessage("Attribute \"idx\" in <var> node below <specialOrderedSets> node not found.\n");
2309  *doingfine = FALSE;
2310  return SCIP_OKAY;
2311  }
2312 
2313  idx = (int)strtol(attrval, (char**)&attrval, 10);
2314  if( *attrval != '\0' || idx < 0 || idx > nvars - 1 )
2315  {
2316  SCIPerrorMessage("Invalid value '%s' for \"idx\" attribute in <var>.\n", xmlGetAttrval(sosvar, "idx"));
2317  *doingfine = FALSE;
2318  return SCIP_OKAY;
2319  }
2320  assert(idx >= 0);
2321 
2322  /* we now know that we have a variable/weight pair -> add variable*/
2323  switch( type )
2324  {
2325  case 1:
2326  SCIP_CALL( SCIPaddVarSOS1(scip, cons, vars[idx], (SCIP_Real) (nsosvars - varcount)) );
2327  break;
2328  case 2:
2329  SCIP_CALL( SCIPaddVarSOS2(scip, cons, vars[idx], (SCIP_Real) (nsosvars - varcount)) );
2330  break;
2331  default:
2332  SCIPerrorMessage("unknown SOS type: <%d>\n", type); /* should not happen */
2333  SCIPABORT();
2334  return SCIP_INVALIDDATA; /*lint !e527*/
2335  }
2336  } /* Close loop over variables in sos constraint */
2337 
2338  /* add the SOS constraint */
2339  SCIP_CALL( SCIPaddCons(scip, cons) );
2340  }
2341 
2342  return SCIP_OKAY;
2343 }
2344 
2345  /*
2346  * Callback methods of reader
2347  */
2348 
2349 
2350 /** copy method for reader plugins (called when SCIP copies plugins) */
2351 static
2352 SCIP_DECL_READERCOPY(readerCopyOsil)
2353 { /*lint --e{715}*/
2354  assert(scip != NULL);
2355 
2357 
2358  return SCIP_OKAY;
2359 }
2360 
2361 /** problem reading method of reader */
2362 static
2363 SCIP_DECL_READERREAD(readerReadOsil)
2364 { /*lint --e{715}*/
2365  const char* name;
2366  XML_NODE* start;
2367  const XML_NODE* header;
2368  const XML_NODE* data;
2369  SCIP_RETCODE retcode;
2370  SCIP_Bool doingfine;
2371  SCIP_Bool initialconss;
2372  SCIP_Bool dynamicconss;
2373  SCIP_Bool dynamiccols;
2374  SCIP_Bool dynamicrows;
2375  SCIP_VAR** vars;
2376  int nvars;
2377  SCIP_CONS** conss;
2378  CONSTYPE* constypes;
2379  int nconss;
2380  SCIP_CONS* objcons;
2381  CONSTYPE objconstype;
2382  int i;
2383 
2384  assert(scip != NULL);
2385  assert(reader != NULL);
2386  assert(result != NULL);
2387  assert(filename != NULL);
2388 
2389  *result = SCIP_DIDNOTRUN;
2390  retcode = SCIP_READERROR;
2391  doingfine = TRUE;
2392  vars = NULL;
2393  nvars = 0;
2394  conss = NULL;
2395  constypes = NULL;
2396  nconss = 0;
2397  objcons = NULL;
2398 
2399  /* read OSiL xml file */
2400  start = xmlProcess(filename);
2401 
2402  if( start == NULL )
2403  {
2404  SCIPerrorMessage("Some error occurred when parsing the OSiL XML file '%s'.\n", filename);
2405  goto CLEANUP;
2406  }
2407 
2408  SCIPdebug( xmlShowNode(start) );
2409 
2410  /* parse header to get problem name */
2411  name = filename;
2412  header = xmlFindNodeMaxdepth(start, "instanceHeader", 0, 2);
2413  if( header != NULL )
2414  {
2415  const XML_NODE* namenode;
2416 
2417  namenode = xmlFindNodeMaxdepth(header, "name", 0, 2);
2418 
2419  if( namenode != NULL && xmlFirstChild(namenode) != NULL )
2420  name = xmlGetData(xmlFirstChild(namenode));
2421  else
2422  {
2423  namenode = xmlFindNodeMaxdepth(header, "description", 0, 2);
2424 
2425  if( namenode != NULL && xmlFirstChild(namenode) != NULL )
2426  name = xmlGetData(xmlFirstChild(namenode));
2427  }
2428  }
2429 
2430  /* create SCIP problem */
2431  SCIP_CALL( SCIPcreateProb(scip, name, NULL, NULL, NULL, NULL, NULL, NULL, NULL) );
2432 
2433  /* process instance data */
2434  data = xmlFindNodeMaxdepth(start, "instanceData", 0, 2);
2435  if( data == NULL )
2436  {
2437  SCIPerrorMessage("Node <instanceData> not found.\n");
2438  goto CLEANUP;
2439  }
2440 
2441  SCIP_CALL( SCIPgetBoolParam(scip, "reading/initialconss", &initialconss) );
2442  SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicconss", &dynamicconss) );
2443  SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamiccols", &dynamiccols) );
2444  SCIP_CALL( SCIPgetBoolParam(scip, "reading/dynamicrows", &dynamicrows) );
2445 
2446  /* read variables */
2447  SCIP_CALL( readVariables(scip, data, &vars, &nvars, initialconss, dynamicconss, dynamiccols, dynamicrows, &doingfine) );
2448  if( !doingfine )
2449  goto CLEANUP;
2450  assert(vars != NULL || nvars == 0);
2451 
2452  /* read objective sense, coefficient, and constant */
2453  SCIP_CALL( readObjective(scip, data, vars, nvars, dynamiccols, &doingfine) );
2454  if( !doingfine )
2455  goto CLEANUP;
2456 
2457  /* read constraint data (names, constants, lhs/rhs) */
2458  SCIP_CALL( readConstraints(scip, data, &conss, &constypes, &nconss, initialconss, dynamicconss, dynamicrows, &doingfine) );
2459  if( !doingfine )
2460  goto CLEANUP;
2461  assert(conss != NULL || nconss == 0);
2462 
2463  /* read linear coefficients matrix */
2464  SCIP_CALL( readLinearCoefs(scip, data, vars, nvars, conss, constypes, nconss, &doingfine) );
2465  if( !doingfine )
2466  goto CLEANUP;
2467 
2468  /* read quadratic coefficients (turns linear constraints into quadratic ones, may create objcons) */
2469  SCIP_CALL( readQuadraticCoefs(scip, data, vars, nvars, conss, constypes, nconss, &objcons, &objconstype, &doingfine) );
2470  if( !doingfine )
2471  goto CLEANUP;
2472 
2473  /* read nonlinear expressions (turns constraints into nonlinear ones, may create objcons) */
2474  SCIP_CALL( readNonlinearExprs(scip, data, vars, nvars, conss, constypes, nconss, &objcons, &objconstype, &doingfine) );
2475  if( !doingfine )
2476  goto CLEANUP;
2477 
2478  /* add constraints to problem */
2479  for( i = 0; i < nconss; ++i )
2480  {
2481  assert(conss[i] != NULL); /*lint !e613*/
2482  SCIP_CALL( SCIPaddCons(scip, conss[i]) ); /*lint !e613*/
2483  }
2484  if( objcons != NULL )
2485  {
2486  SCIP_CALL( SCIPaddCons(scip, objcons) );
2487  }
2488 
2489  /* read sos2 constraints and add to problem*/
2490  SCIP_CALL( readSOScons(scip, data, vars, nvars, initialconss, dynamicconss, dynamicrows, &doingfine) );
2491  if( !doingfine )
2492  goto CLEANUP;
2493 
2494 
2495  *result = SCIP_SUCCESS;
2496  retcode = SCIP_OKAY;
2497 
2498 CLEANUP:
2499  /* free xml data */
2500  if( start != NULL )
2501  xmlFreeNode(start);
2502 
2503  /* free variables */
2504  for( i = 0; i < nvars; ++i )
2505  {
2506  SCIP_CALL( SCIPreleaseVar(scip, &vars[i]) ); /*lint !e613*/
2507  }
2508  SCIPfreeBufferArrayNull(scip, &vars);
2509 
2510  /* free constraints */
2511  for( i = 0; i < nconss; ++i )
2512  {
2513  SCIP_CALL( SCIPreleaseCons(scip, &conss[i]) ); /*lint !e613*/
2514  }
2515  SCIPfreeBufferArrayNull(scip, &conss);
2516  SCIPfreeBufferArrayNull(scip, &constypes);
2517 
2518  if( objcons != NULL )
2519  {
2520  SCIP_CALL( SCIPreleaseCons(scip, &objcons) );
2521  }
2522 
2523  return retcode;
2524 }
2525 
2526 /*
2527  * reader specific interface methods
2528  */
2529 
2530 /** includes the osil file reader in SCIP */
2532  SCIP* scip /**< SCIP data structure */
2533  )
2534 {
2535  SCIP_READER* reader;
2536 
2537  /* include osil reader */
2539 
2540  SCIP_CALL( SCIPsetReaderCopy(scip, reader, readerCopyOsil) );
2541  SCIP_CALL( SCIPsetReaderRead(scip, reader, readerReadOsil) );
2542 
2543  return SCIP_OKAY;
2544 }
2545