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
58namespace {
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*/
67std::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*/
97void 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
130const 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
147std::string
148OsiSolverInterface::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*/
173std::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*/
189std::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*/
247const 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*/
294std::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*/
345const 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*/
389void 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*/
435void 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*/
478void 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*/
518void 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*/
565void 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*/
609void 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*/
647void 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*/
690void 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*/
752void 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