1 | // Copyright (C) 2007, Lou Hafer and others. All Rights Reserved. |
2 | // This code is licensed under the terms of the Eclipse Public License (EPL). |
3 | |
4 | #if defined(_MSC_VER) |
5 | // Turn off compiler warning about long names |
6 | # pragma warning(disable:4786) |
7 | #endif |
8 | |
9 | #include <sstream> |
10 | #include <iomanip> |
11 | |
12 | #include "OsiSolverInterface.hpp" |
13 | #include "CoinLpIO.hpp" |
14 | #include "CoinMpsIO.hpp" |
15 | #include "CoinModel.hpp" |
16 | |
17 | /* |
18 | These routines support three name disciplines: |
19 | |
20 | 0: No names: No name information is retained. rowNames_ and colNames_ are |
21 | always vectors of length 0. Requests for individual names will return |
22 | a name of the form RowNNN or ColNNN, generated on request. |
23 | |
24 | 1: Lazy names: Name information supplied by the client is retained. |
25 | rowNames_ and colNames_ are sized to be large enough to hold names |
26 | supplied by the client, and no larger. If the client has left holes, |
27 | those entries will contain a null string. Requests for individual names |
28 | will return the name supplied by the client, or a generated name. |
29 | Requests for a vector of names will return a reference to rowNames_ or |
30 | colNames_, with no modification. |
31 | |
32 | This mode is intended for applications like branch-and-cut, where the |
33 | client is only interested in the original constraint system and could |
34 | care less about names for generated constraints and variables. The |
35 | various read[Mps,GMPL,Lp] routines capture the names that are part of |
36 | the input format. If the client is building from scratch, they'll need |
37 | to supply the names as they install constraints and variables. |
38 | |
39 | 2: Full names: From the client's point of view, this looks exactly like |
40 | lazy names, except that when a vector of names is requested, the vector |
41 | is always sized to match the constraint system and all entries have |
42 | names (either supplied or generated). Internally, full names looks just |
43 | like lazy names, with the exception that if the client requests one of |
44 | the name vectors, we generate the full version on the spot and keep it |
45 | around for further use. |
46 | |
47 | This approach sidesteps some ugly implementation issues. The base |
48 | routines to add a row or column, or load a problem from matrices, are |
49 | pure virtual. There's just no way to guarantee we can keep the name |
50 | vectors up-to-date with each modification. Nor do we want to be in the |
51 | business of generating a name as soon as the row or column appears, only |
52 | to have our generated name immediately overridden by the client. |
53 | |
54 | Arguably these magic numbers should be an enum, but that's not the current |
55 | OSI style. |
56 | */ |
57 | |
58 | namespace { |
59 | |
60 | /* |
61 | Generate a `name' that's really an error message. A separate routine |
62 | strictly for standardisation and ease of use. |
63 | |
64 | The 'u' code is intended to be used when a routine is expecting one of 'r' or |
65 | 'c' and saw something else. |
66 | */ |
67 | std::string invRowColName (char rcd, int ndx) |
68 | |
69 | { std::ostringstream buildName ; |
70 | |
71 | buildName << "!!invalid " ; |
72 | switch (rcd) |
73 | { case 'r': |
74 | { buildName << "Row " << ndx << "!!" ; |
75 | break ; } |
76 | case 'c': |
77 | { buildName << "Col " << ndx << "!!" ; |
78 | break ; } |
79 | case 'd': |
80 | { buildName << "Discipline " << ndx << "!!" ; |
81 | break ; } |
82 | case 'u': |
83 | { buildName << "Row/Col " << ndx << "!!" ; |
84 | break ; } |
85 | default: |
86 | { buildName << "!!Internal Confusion!!" ; |
87 | break ; } } |
88 | |
89 | return (buildName.str()) ; } |
90 | |
91 | /* |
92 | Adjust the allocated capacity of the name vectors, if they're sufficiently |
93 | far off (more than 1000 elements). Use this routine only if you don't need |
94 | the current contents of the vectors. The `assignment & swap' bit is a trick |
95 | lifted from Stroustrop 16.3.8 to make sure we really give back some space. |
96 | */ |
97 | void reallocRowColNames (OsiSolverInterface::OsiNameVec &rowNames, int m, |
98 | OsiSolverInterface::OsiNameVec &colNames, int n) |
99 | |
100 | { int rowCap = static_cast<int>(rowNames.capacity()) ; |
101 | int colCap = static_cast<int>(colNames.capacity()) ; |
102 | |
103 | if (rowCap-m > 1000) |
104 | { rowNames.resize(m) ; |
105 | OsiSolverInterface::OsiNameVec tmp = rowNames ; |
106 | rowNames.swap(tmp) ; } |
107 | else |
108 | if (rowCap < m) |
109 | { rowNames.reserve(m) ; } |
110 | assert(rowNames.capacity() >= static_cast<unsigned>(m)) ; |
111 | |
112 | if (colCap-n > 1000) |
113 | { colNames.resize(n) ; |
114 | OsiSolverInterface::OsiNameVec tmp = colNames ; |
115 | colNames.swap(tmp) ; } |
116 | else |
117 | if (colCap < n) |
118 | { colNames.reserve(n) ; } |
119 | assert(colNames.capacity() >= static_cast<unsigned>(n)) ; |
120 | |
121 | return ; } |
122 | |
123 | |
124 | /* |
125 | It's handy to have a 0-length name vector hanging around to use as a return |
126 | value when the name discipline = auto. Then we don't have to worry |
127 | about what's actually occupying rowNames_ or colNames_. |
128 | */ |
129 | |
130 | const OsiSolverInterface::OsiNameVec zeroLengthNameVec(0) ; |
131 | |
132 | } |
133 | |
134 | /* |
135 | Generate the default RNNNNNNN/CNNNNNNN. This is a separate routine so that |
136 | it's available to generate names for new rows and columns. If digits is |
137 | nonzero, it's used, otherwise the default is 7 digits after the initial R |
138 | or C. |
139 | |
140 | If rc = 'o', return the default name for the objective function. Yes, it's |
141 | true that ndx = m is (by definition) supposed to refer to the objective |
142 | function. But ... we're often calling this routine to get a name *before* |
143 | installing the row. Unless you want all your rows to be named OBJECTIVE, |
144 | something different is needed here. |
145 | */ |
146 | |
147 | std::string |
148 | OsiSolverInterface::dfltRowColName (char rc, int ndx, unsigned digits) const |
149 | |
150 | { std::ostringstream buildName ; |
151 | |
152 | if (!(rc == 'r' || rc == 'c' || rc == 'o')) |
153 | { return (invRowColName('u',ndx)) ; } |
154 | if (ndx < 0) |
155 | { return (invRowColName(rc,ndx)) ; } |
156 | |
157 | if (digits <= 0) |
158 | { digits = 7 ; } |
159 | |
160 | if (rc == 'o') |
161 | { std::string dfltObjName = "OBJECTIVE" ; |
162 | buildName << dfltObjName.substr(0,digits+1) ; } |
163 | else |
164 | { buildName << ((rc == 'r')?"R" :"C" ) ; |
165 | buildName << std::setw(digits) << std::setfill('0') ; |
166 | buildName << ndx ; } |
167 | |
168 | return buildName.str() ; } |
169 | |
170 | /* |
171 | Return the name of the objective function. |
172 | */ |
173 | std::string OsiSolverInterface::getObjName (unsigned maxLen) const |
174 | { std::string name ; |
175 | |
176 | if (objName_.length() == 0) |
177 | { name = dfltRowColName('o',0,maxLen) ; } |
178 | else |
179 | { name = objName_.substr(0,maxLen) ; } |
180 | |
181 | return (name) ; } |
182 | |
183 | /* |
184 | Return a row name, according to the current name discipline, truncated if |
185 | necessary. If the row index is out of range, the name becomes an error |
186 | message. By definition, ndx = getNumRows() (i.e., one greater than the |
187 | largest valid row index) is the objective function. |
188 | */ |
189 | std::string OsiSolverInterface::getRowName (int ndx, unsigned maxLen) const |
190 | |
191 | { int nameDiscipline ; |
192 | std::string name ; |
193 | /* |
194 | Check for valid row index. |
195 | */ |
196 | int m = getNumRows() ; |
197 | if (ndx < 0 || ndx > m) |
198 | { name = invRowColName('r',ndx) ; |
199 | return (name) ; } |
200 | /* |
201 | The objective is kept separately, so we don't always have an entry at |
202 | index m in the names vector. If no name is set, return the default. |
203 | */ |
204 | if (ndx == m) |
205 | { return (getObjName(maxLen)) ; } |
206 | /* |
207 | Determine how we're handling names. It's possible that the underlying solver |
208 | has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that |
209 | case, we want to default to auto names |
210 | */ |
211 | bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ; |
212 | if (recognisesOsiNames == false) |
213 | { nameDiscipline = 0 ; } |
214 | /* |
215 | Find/generate the proper name, based on discipline. |
216 | */ |
217 | switch (nameDiscipline) |
218 | { case 0: |
219 | { name = dfltRowColName('r',ndx) ; |
220 | break ; } |
221 | case 1: |
222 | case 2: |
223 | { name = "" ; |
224 | if (static_cast<unsigned>(ndx) < rowNames_.size()) |
225 | name = rowNames_[ndx] ; |
226 | if (name.length() == 0) |
227 | name = dfltRowColName('r',ndx) ; |
228 | break ; } |
229 | default: |
230 | { name = invRowColName('d',nameDiscipline) ; |
231 | return (name) ; } } |
232 | /* |
233 | Return the (possibly truncated) substring. The default for maxLen is npos |
234 | (no truncation). |
235 | */ |
236 | return (name.substr(0,maxLen)) ; } |
237 | |
238 | |
239 | /* |
240 | Return the vector of row names. The vector we need depends on the name |
241 | discipline: |
242 | 0: return a vector of length 0 |
243 | 1: return rowNames_, no tweaking required |
244 | 2: Check that rowNames_ is complete. Generate a complete vector on |
245 | the spot if we need it. |
246 | */ |
247 | const OsiSolverInterface::OsiNameVec &OsiSolverInterface::getRowNames () |
248 | |
249 | { int nameDiscipline ; |
250 | /* |
251 | Determine how we're handling names. It's possible that the underlying solver |
252 | has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that |
253 | case, we want to default to auto names |
254 | */ |
255 | bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ; |
256 | if (recognisesOsiNames == false) |
257 | { nameDiscipline = 0 ; } |
258 | /* |
259 | Return the proper vector, as described at the head of the routine. If we |
260 | need to generate a full vector, resize the existing vector and scan, filling |
261 | in entries as required. |
262 | */ |
263 | switch (nameDiscipline) |
264 | { case 0: |
265 | { return (zeroLengthNameVec) ; } |
266 | case 1: |
267 | { return (rowNames_) ; } |
268 | case 2: |
269 | { int m = getNumRows() ; |
270 | if (rowNames_.size() < static_cast<unsigned>(m+1)) |
271 | { rowNames_.resize(m+1) ; } |
272 | for (int i = 0 ; i < m ; i++) |
273 | { if (rowNames_[i].length() == 0) |
274 | { rowNames_[i] = dfltRowColName('r',i) ; } } |
275 | if (rowNames_[m].length() == 0) |
276 | { rowNames_[m] = getObjName() ; } |
277 | return (rowNames_) ; } |
278 | default: |
279 | { /* quietly fail */ |
280 | return (zeroLengthNameVec) ; } } |
281 | /* |
282 | We should never reach here. |
283 | */ |
284 | assert(false) ; |
285 | |
286 | return (zeroLengthNameVec) ; } |
287 | |
288 | |
289 | /* |
290 | Return a column name, according to the current name discipline, truncated if |
291 | necessary. If the column index is out of range, the name becomes an error |
292 | message. |
293 | */ |
294 | std::string OsiSolverInterface::getColName (int ndx, unsigned maxLen) const |
295 | |
296 | { int nameDiscipline ; |
297 | std::string name ; |
298 | /* |
299 | Check for valid column index. |
300 | */ |
301 | if (ndx < 0 || ndx >= getNumCols()) |
302 | { name = invRowColName('c',ndx) ; |
303 | return (name) ; } |
304 | /* |
305 | Determine how we're handling names. It's possible that the underlying solver |
306 | has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that |
307 | case, we want to default to auto names |
308 | */ |
309 | bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ; |
310 | if (recognisesOsiNames == false) |
311 | { nameDiscipline = 0 ; } |
312 | /* |
313 | Find/generate the proper name, based on discipline. |
314 | */ |
315 | switch (nameDiscipline) |
316 | { case 0: |
317 | { name = dfltRowColName('c',ndx) ; |
318 | break ; } |
319 | case 1: |
320 | case 2: |
321 | { name = "" ; |
322 | if (static_cast<unsigned>(ndx) < colNames_.size()) |
323 | name = colNames_[ndx] ; |
324 | if (name.length() == 0) |
325 | name = dfltRowColName('c',ndx) ; |
326 | break ; } |
327 | default: |
328 | { name = invRowColName('d',nameDiscipline) ; |
329 | return (name) ; } } |
330 | /* |
331 | Return the (possibly truncated) substring. The default for maxLen is npos |
332 | (no truncation). |
333 | */ |
334 | return (name.substr(0,maxLen)) ; } |
335 | |
336 | |
337 | /* |
338 | Return the vector of column names. The vector we need depends on the name |
339 | discipline: |
340 | 0: return a vector of length 0 |
341 | 1: return colNames_, no tweaking required |
342 | 2: Check that colNames_ is complete. Generate a complete vector on |
343 | the spot if we need it. |
344 | */ |
345 | const OsiSolverInterface::OsiNameVec &OsiSolverInterface::getColNames () |
346 | |
347 | { int nameDiscipline ; |
348 | /* |
349 | Determine how we're handling names. It's possible that the underlying solver |
350 | has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that |
351 | case, we want to default to auto names |
352 | */ |
353 | bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ; |
354 | if (recognisesOsiNames == false) |
355 | { nameDiscipline = 0 ; } |
356 | /* |
357 | Return the proper vector, as described at the head of the routine. If we |
358 | need to generate a full vector, resize the existing vector and scan, filling |
359 | in entries as required. |
360 | */ |
361 | switch (nameDiscipline) |
362 | { case 0: |
363 | { return (zeroLengthNameVec) ; } |
364 | case 1: |
365 | { return (colNames_) ; } |
366 | case 2: |
367 | { int n = getNumCols() ; |
368 | if (colNames_.size() < static_cast<unsigned>(n)) |
369 | { colNames_.resize(n) ; } |
370 | for (int j = 0 ; j < n ; j++) |
371 | { if (colNames_[j].length() == 0) |
372 | { colNames_[j] = dfltRowColName('c',j) ; } } |
373 | return (colNames_) ; } |
374 | default: |
375 | { /* quietly fail */ |
376 | return (zeroLengthNameVec) ; } } |
377 | /* |
378 | We should never reach here. |
379 | */ |
380 | assert(false) ; |
381 | |
382 | return (zeroLengthNameVec) ; } |
383 | |
384 | |
385 | /* |
386 | Set a single row name. Quietly does nothing if the index or name discipline |
387 | is invalid. |
388 | */ |
389 | void OsiSolverInterface::setRowName (int ndx, std::string name) |
390 | |
391 | { int nameDiscipline ; |
392 | /* |
393 | Quietly do nothing if the index is out of bounds. This should be changed, |
394 | but what's our error convention, eh? There's no precedent in |
395 | OsiSolverInterface.cpp. |
396 | */ |
397 | if (ndx < 0 || ndx >= getNumRows()) |
398 | { return ; } |
399 | /* |
400 | Determine how we're handling names. It's possible that the underlying solver |
401 | has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that |
402 | case, we want to default to auto names |
403 | */ |
404 | bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ; |
405 | if (recognisesOsiNames == false) |
406 | { nameDiscipline = 0 ; } |
407 | /* |
408 | Do the right thing, according to the discipline. |
409 | */ |
410 | switch (nameDiscipline) |
411 | { case 0: |
412 | { break ; } |
413 | case 1: |
414 | case 2: |
415 | { if (static_cast<unsigned>(ndx) > rowNames_.capacity()) |
416 | { rowNames_.resize(ndx+1) ; } |
417 | else |
418 | if (static_cast<unsigned>(ndx) >= rowNames_.size()) |
419 | { rowNames_.resize(ndx+1) ; } |
420 | rowNames_[ndx] = name ; |
421 | break ; } |
422 | default: |
423 | { break ; } } |
424 | |
425 | return ; } |
426 | |
427 | /* |
428 | Set a run of row names. Quietly fail if the specified indices are invalid. |
429 | |
430 | On the target side, [tgtStart, tgtStart+len-1] must be in the range |
431 | [0,m-1], where m is the number of rows. On the source side, srcStart must |
432 | be zero or greater. If we run off the end of srcNames, we just generate |
433 | default names. |
434 | */ |
435 | void OsiSolverInterface::setRowNames (OsiNameVec &srcNames, |
436 | int srcStart, int len, int tgtStart) |
437 | |
438 | { int nameDiscipline ; |
439 | /* |
440 | Determine how we're handling names. It's possible that the underlying solver |
441 | has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that |
442 | case, we want to default to auto names |
443 | */ |
444 | bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ; |
445 | if (recognisesOsiNames == false) |
446 | { nameDiscipline = 0 ; } |
447 | /* |
448 | If the name discipline is auto, we're already done. |
449 | */ |
450 | if (nameDiscipline == 0) |
451 | { return ; } |
452 | /* |
453 | A little self-protection. Check that we're within [0,m-1] on the target side, |
454 | and that srcStart is zero or greater. Quietly fail if the indices don't fit. |
455 | */ |
456 | int m = getNumRows() ; |
457 | if (tgtStart < 0 || tgtStart+len > m) |
458 | { return ; } |
459 | if (srcStart < 0) |
460 | { return ; } |
461 | int srcLen = static_cast<int>(srcNames.size()) ; |
462 | /* |
463 | Load 'em up. |
464 | */ |
465 | int srcNdx = srcStart ; |
466 | int tgtNdx = tgtStart ; |
467 | for ( ; tgtNdx < tgtStart+len ; srcNdx++,tgtNdx++) |
468 | { if (srcNdx < srcLen) |
469 | { setRowName(tgtNdx,srcNames[srcNdx]) ; } |
470 | else |
471 | { setRowName(tgtNdx,dfltRowColName('r',tgtNdx)) ; } } |
472 | |
473 | return ; } |
474 | |
475 | /* |
476 | Delete one or more row names. |
477 | */ |
478 | void OsiSolverInterface::deleteRowNames (int tgtStart, int len) |
479 | |
480 | { int nameDiscipline ; |
481 | /* |
482 | Determine how we're handling names. It's possible that the underlying solver |
483 | has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that |
484 | case, we want to default to auto names |
485 | */ |
486 | bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ; |
487 | if (recognisesOsiNames == false) |
488 | { nameDiscipline = 0 ; } |
489 | /* |
490 | If the name discipline is auto, we're done. |
491 | */ |
492 | if (nameDiscipline == 0) |
493 | { return ; } |
494 | /* |
495 | Trim the range to names that exist in the name vector. If we're doing lazy |
496 | names, it's quite likely that we don't need to do any work. |
497 | */ |
498 | int lastNdx = static_cast<int>(rowNames_.size()) ; |
499 | if (tgtStart < 0 || tgtStart >= lastNdx) |
500 | { return ; } |
501 | if (tgtStart+len > lastNdx) |
502 | { len = lastNdx-tgtStart ; } |
503 | /* |
504 | Erase the names. |
505 | */ |
506 | OsiNameVec::iterator firstIter,lastIter ; |
507 | firstIter = rowNames_.begin()+tgtStart ; |
508 | lastIter = firstIter+len ; |
509 | rowNames_.erase(firstIter,lastIter) ; |
510 | |
511 | return ; } |
512 | |
513 | |
514 | /* |
515 | Set a single column name. Quietly does nothing if the index or name |
516 | discipline is invalid. |
517 | */ |
518 | void OsiSolverInterface::setColName (int ndx, std::string name) |
519 | |
520 | { int nameDiscipline ; |
521 | /* |
522 | Quietly do nothing if the index is out of bounds. This should be changed, |
523 | but what's our error convention, eh? There's no precedent in |
524 | OsiSolverInterface.cpp. |
525 | */ |
526 | if (ndx < 0 || ndx >= getNumCols()) |
527 | { return ; } |
528 | /* |
529 | Determine how we're handling names. It's possible that the underlying solver |
530 | has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that |
531 | case, we want to default to auto names |
532 | */ |
533 | bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ; |
534 | if (recognisesOsiNames == false) |
535 | { nameDiscipline = 0 ; } |
536 | /* |
537 | Do the right thing, according to the discipline. |
538 | */ |
539 | switch (nameDiscipline) |
540 | { case 0: |
541 | { break ; } |
542 | case 1: |
543 | case 2: |
544 | { if (static_cast<unsigned>(ndx) > colNames_.capacity()) |
545 | { colNames_.resize(ndx+1) ; } |
546 | else |
547 | if (static_cast<unsigned>(ndx) >= colNames_.size()) |
548 | { colNames_.resize(ndx+1) ; } |
549 | colNames_[ndx] = name ; |
550 | break ; } |
551 | default: |
552 | { break ; } } |
553 | |
554 | return ; } |
555 | |
556 | /* |
557 | Set a run of column names. Quietly fail if the specified indices are |
558 | invalid. |
559 | |
560 | On the target side, [tgtStart, tgtStart+len-1] must be in the range |
561 | [0,n-1], where n is the number of columns. On the source side, srcStart |
562 | must be zero or greater. If we run off the end of srcNames, we just |
563 | generate default names. |
564 | */ |
565 | void OsiSolverInterface::setColNames (OsiNameVec &srcNames, |
566 | int srcStart, int len, int tgtStart) |
567 | |
568 | { int nameDiscipline ; |
569 | /* |
570 | Determine how we're handling names. It's possible that the underlying solver |
571 | has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that |
572 | case, we want to default to auto names |
573 | */ |
574 | bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ; |
575 | if (recognisesOsiNames == false) |
576 | { nameDiscipline = 0 ; } |
577 | /* |
578 | If the name discipline is auto, we're already done. |
579 | */ |
580 | if (nameDiscipline == 0) |
581 | { return ; } |
582 | /* |
583 | A little self-protection. Check that we're within [0,m-1] on the target side, |
584 | and that srcStart is zero or greater. Quietly fail if the indices don't fit. |
585 | */ |
586 | int n = getNumCols() ; |
587 | if (tgtStart < 0 || tgtStart+len > n) |
588 | { return ; } |
589 | if (srcStart < 0) |
590 | { return ; } |
591 | int srcLen = static_cast<int>(srcNames.size()) ; |
592 | /* |
593 | Load 'em up. |
594 | */ |
595 | int srcNdx = srcStart ; |
596 | int tgtNdx = tgtStart ; |
597 | for ( ; tgtNdx < tgtStart+len ; srcNdx++,tgtNdx++) |
598 | { if (srcNdx < srcLen) |
599 | { setColName(tgtNdx,srcNames[srcNdx]) ; } |
600 | else |
601 | { setColName(tgtNdx,dfltRowColName('c',tgtNdx)) ; } } |
602 | |
603 | return ; } |
604 | |
605 | /* |
606 | Delete one or more column names. Quietly fail if firstNdx is less than zero |
607 | or if firstNdx+len is greater than the number of columns. |
608 | */ |
609 | void OsiSolverInterface::deleteColNames (int tgtStart, int len) |
610 | |
611 | { int nameDiscipline ; |
612 | /* |
613 | Determine how we're handling names. It's possible that the underlying solver |
614 | has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that |
615 | case, we want to default to auto names |
616 | */ |
617 | bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ; |
618 | if (recognisesOsiNames == false) |
619 | { nameDiscipline = 0 ; } |
620 | /* |
621 | If the name discipline is auto, we're done. |
622 | */ |
623 | if (nameDiscipline == 0) |
624 | { return ; } |
625 | /* |
626 | Trim the range to names that exist in the name vector. If we're doing lazy |
627 | names, it's quite likely that we don't need to do any work. |
628 | */ |
629 | int lastNdx = static_cast<int>(colNames_.size()) ; |
630 | if (tgtStart < 0 || tgtStart >= lastNdx) |
631 | { return ; } |
632 | if (tgtStart+len > lastNdx) |
633 | { len = lastNdx-tgtStart ; } |
634 | /* |
635 | Erase the names. |
636 | */ |
637 | OsiNameVec::iterator firstIter,lastIter ; |
638 | firstIter = colNames_.begin()+tgtStart ; |
639 | lastIter = firstIter+len ; |
640 | colNames_.erase(firstIter,lastIter) ; |
641 | |
642 | return ; } |
643 | |
644 | /* |
645 | Install the name information from a CoinMpsIO object. |
646 | */ |
647 | void OsiSolverInterface::setRowColNames (const CoinMpsIO &mps) |
648 | |
649 | { int nameDiscipline,m,n ; |
650 | /* |
651 | Determine how we're handling names. It's possible that the underlying solver |
652 | has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that |
653 | case, we want to default to auto names |
654 | */ |
655 | bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ; |
656 | if (recognisesOsiNames == false) |
657 | { nameDiscipline = 0 ; } |
658 | /* |
659 | Whatever happens, we're about to clean out the current name vectors. Decide |
660 | on an appropriate size and call reallocRowColNames to adjust capacity. |
661 | */ |
662 | if (nameDiscipline == 0) |
663 | { m = 0 ; |
664 | n = 0 ; } |
665 | else |
666 | { m = mps.getNumRows() ; |
667 | n = mps.getNumCols() ; } |
668 | reallocRowColNames(rowNames_,m,colNames_,n) ; |
669 | /* |
670 | If name discipline is auto, we're done already. Otherwise, load 'em |
671 | up. If I understand MPS correctly, names are required. |
672 | */ |
673 | if (nameDiscipline != 0) |
674 | { rowNames_.resize(m) ; |
675 | for (int i = 0 ; i < m ; i++) |
676 | { rowNames_[i] = mps.rowName(i) ; } |
677 | objName_ = mps.getObjectiveName() ; |
678 | colNames_.resize(n) ; |
679 | for (int j = 0 ; j < n ; j++) |
680 | { colNames_[j] = mps.columnName(j) ; } } |
681 | |
682 | return ; } |
683 | |
684 | |
685 | /* |
686 | Install the name information from a CoinModel object. CoinModel does not |
687 | maintain a name for the objective function (in fact, it has no concept of |
688 | objective function). |
689 | */ |
690 | void OsiSolverInterface::setRowColNames (CoinModel &mod) |
691 | |
692 | { int nameDiscipline,m,n ; |
693 | /* |
694 | Determine how we're handling names. It's possible that the underlying solver |
695 | has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that |
696 | case, we want to default to auto names |
697 | */ |
698 | bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ; |
699 | if (recognisesOsiNames == false) |
700 | { nameDiscipline = 0 ; } |
701 | /* |
702 | Whatever happens, we're about to clean out the current name vectors. Decide |
703 | on an appropriate size and call reallocRowColNames to adjust capacity. |
704 | */ |
705 | if (nameDiscipline == 0) |
706 | { m = 0 ; |
707 | n = 0 ; } |
708 | else |
709 | { m = mod.rowNames()->numberItems() ; |
710 | n = mod.columnNames()->numberItems() ; } |
711 | reallocRowColNames(rowNames_,m,colNames_,n) ; |
712 | /* |
713 | If name discipline is auto, we're done already. Otherwise, load 'em |
714 | up. As best I can see, there's no guarantee that we'll have names for all |
715 | rows and columns, so we need to pay attention. |
716 | */ |
717 | if (nameDiscipline != 0) |
718 | { int maxRowNdx=-1, maxColNdx=-1 ; |
719 | const char *const *names = mod.rowNames()->names() ; |
720 | rowNames_.resize(m) ; |
721 | for (int i = 0 ; i < m ; i++) |
722 | { std::string nme = names[i] ; |
723 | if (nme.length() == 0) |
724 | { if (nameDiscipline == 2) |
725 | { nme = dfltRowColName('r',i) ; } } |
726 | if (nme.length() > 0) |
727 | { maxRowNdx = i ; } |
728 | rowNames_[i] = nme ; } |
729 | rowNames_.resize(maxRowNdx+1) ; |
730 | names = mod.columnNames()->names() ; |
731 | colNames_.resize(n) ; |
732 | for (int j = 0 ; j < n ; j++) |
733 | { std::string nme = names[j] ; |
734 | if (nme.length() == 0) |
735 | { if (nameDiscipline == 2) |
736 | { nme = dfltRowColName('c',j) ; } } |
737 | if (nme.length() > 0) |
738 | { maxColNdx = j ; } |
739 | colNames_[j] = nme ; } |
740 | colNames_.resize(maxColNdx+1) ; } |
741 | /* |
742 | And we're done. |
743 | */ |
744 | return ; } |
745 | |
746 | |
747 | |
748 | /* |
749 | Install the name information from a CoinLpIO object. Nearly identical to the |
750 | previous routine, but we start from a different object. |
751 | */ |
752 | void OsiSolverInterface::setRowColNames (CoinLpIO &mod) |
753 | |
754 | { int nameDiscipline,m,n ; |
755 | /* |
756 | Determine how we're handling names. It's possible that the underlying solver |
757 | has overridden getIntParam, but doesn't recognise OsiNameDiscipline. In that |
758 | case, we want to default to auto names |
759 | */ |
760 | bool recognisesOsiNames = getIntParam(OsiNameDiscipline,nameDiscipline) ; |
761 | if (recognisesOsiNames == false) |
762 | { nameDiscipline = 0 ; } |
763 | /* |
764 | Whatever happens, we're about to clean out the current name vectors. Decide |
765 | on an appropriate size and call reallocRowColNames to adjust capacity. |
766 | */ |
767 | if (nameDiscipline == 0) |
768 | { m = 0 ; |
769 | n = 0 ; } |
770 | else |
771 | { m = mod.getNumRows() ; |
772 | n = mod.getNumCols() ; } |
773 | reallocRowColNames(rowNames_,m,colNames_,n) ; |
774 | /* |
775 | If name discipline is auto, we're done already. Otherwise, load 'em |
776 | up. I have no idea whether we can guarantee valid names for all rows and |
777 | columns, so we need to pay attention. |
778 | */ |
779 | if (nameDiscipline != 0) |
780 | { int maxRowNdx=-1, maxColNdx=-1 ; |
781 | const char *const *names = mod.getRowNames() ; |
782 | rowNames_.resize(m) ; |
783 | for (int i = 0 ; i < m ; i++) |
784 | { std::string nme = names[i] ; |
785 | if (nme.length() == 0) |
786 | { if (nameDiscipline == 2) |
787 | { nme = dfltRowColName('r',i) ; } } |
788 | if (nme.length() > 0) |
789 | { maxRowNdx = i ; } |
790 | rowNames_[i] = nme ; } |
791 | rowNames_.resize(maxRowNdx+1) ; |
792 | objName_ = mod.getObjName() ; |
793 | names = mod.getColNames() ; |
794 | colNames_.resize(n) ; |
795 | for (int j = 0 ; j < n ; j++) |
796 | { std::string nme = names[j] ; |
797 | if (nme.length() == 0) |
798 | { if (nameDiscipline == 2) |
799 | { nme = dfltRowColName('c',j) ; } } |
800 | if (nme.length() > 0) |
801 | { maxColNdx = j ; } |
802 | colNames_[j] = nme ; } |
803 | colNames_.resize(maxColNdx+1) ; } |
804 | /* |
805 | And we're done. |
806 | */ |
807 | return ; } |
808 | |