Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #undef LANGUAGE_NONE
30 : : #define WINAPI __stdcall
31 : : #define LoadInverseLib FALSE
32 : : #define LoadLanguageLib FALSE
33 : : #include <lpsolve/lp_lib.h>
34 : : #undef LANGUAGE_NONE
35 : :
36 : : #include "solver.hxx"
37 : : #include "solver.hrc"
38 : :
39 : : #include <com/sun/star/beans/XPropertySet.hpp>
40 : : #include <com/sun/star/container/XIndexAccess.hpp>
41 : : #include <com/sun/star/frame/XModel.hpp>
42 : : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
43 : : #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
44 : : #include <com/sun/star/sheet/XSpreadsheet.hpp>
45 : : #include <com/sun/star/table/CellAddress.hpp>
46 : : #include <com/sun/star/table/CellRangeAddress.hpp>
47 : : #include <com/sun/star/text/XTextRange.hpp>
48 : :
49 : : #include <rtl/math.hxx>
50 : : #include <rtl/ustrbuf.hxx>
51 : : #include <cppuhelper/factory.hxx>
52 : : #include <vector>
53 : : #include <boost/unordered_map.hpp>
54 : :
55 : : #include <tools/resmgr.hxx>
56 : :
57 : : using namespace com::sun::star;
58 : :
59 : : using ::rtl::OUString;
60 : :
61 : : #define C2U(constAsciiStr) (::rtl::OUString( constAsciiStr ))
62 : :
63 : : #define STR_NONNEGATIVE "NonNegative"
64 : : #define STR_INTEGER "Integer"
65 : : #define STR_TIMEOUT "Timeout"
66 : : #define STR_EPSILONLEVEL "EpsilonLevel"
67 : : #define STR_LIMITBBDEPTH "LimitBBDepth"
68 : :
69 : : // -----------------------------------------------------------------------
70 : : // Resources from tools are used for translated strings
71 : :
72 : : static ResMgr* pSolverResMgr = NULL;
73 : :
74 : 0 : OUString lcl_GetResourceString( sal_uInt32 nId )
75 : : {
76 : 0 : if (!pSolverResMgr)
77 : 0 : pSolverResMgr = ResMgr::CreateResMgr("solver");
78 : :
79 : 0 : return String( ResId( nId, *pSolverResMgr ) );
80 : : }
81 : :
82 : : // -----------------------------------------------------------------------
83 : :
84 : : namespace
85 : : {
86 : : enum
87 : : {
88 : : PROP_NONNEGATIVE,
89 : : PROP_INTEGER,
90 : : PROP_TIMEOUT,
91 : : PROP_EPSILONLEVEL,
92 : : PROP_LIMITBBDEPTH
93 : : };
94 : : }
95 : :
96 : : // -----------------------------------------------------------------------
97 : :
98 : : // hash map for the coefficients of a dependent cell (objective or constraint)
99 : : // The size of each vector is the number of columns (variable cells) plus one, first entry is initial value.
100 : :
101 : : struct ScSolverCellHash
102 : : {
103 : 0 : size_t operator()( const table::CellAddress& rAddress ) const
104 : : {
105 : 0 : return ( rAddress.Sheet << 24 ) | ( rAddress.Column << 16 ) | rAddress.Row;
106 : : }
107 : : };
108 : :
109 : 0 : inline bool AddressEqual( const table::CellAddress& rAddr1, const table::CellAddress& rAddr2 )
110 : : {
111 : 0 : return rAddr1.Sheet == rAddr2.Sheet && rAddr1.Column == rAddr2.Column && rAddr1.Row == rAddr2.Row;
112 : : }
113 : :
114 : : struct ScSolverCellEqual
115 : : {
116 : 0 : bool operator()( const table::CellAddress& rAddr1, const table::CellAddress& rAddr2 ) const
117 : : {
118 : 0 : return AddressEqual( rAddr1, rAddr2 );
119 : : }
120 : : };
121 : :
122 : : typedef boost::unordered_map< table::CellAddress, std::vector<double>, ScSolverCellHash, ScSolverCellEqual > ScSolverCellHashMap;
123 : :
124 : : // -----------------------------------------------------------------------
125 : :
126 : 0 : uno::Reference<table::XCell> lcl_GetCell( const uno::Reference<sheet::XSpreadsheetDocument>& xDoc,
127 : : const table::CellAddress& rPos )
128 : : {
129 : 0 : uno::Reference<container::XIndexAccess> xSheets( xDoc->getSheets(), uno::UNO_QUERY );
130 : 0 : uno::Reference<sheet::XSpreadsheet> xSheet( xSheets->getByIndex( rPos.Sheet ), uno::UNO_QUERY );
131 : 0 : return xSheet->getCellByPosition( rPos.Column, rPos.Row );
132 : : }
133 : :
134 : 0 : void lcl_SetValue( const uno::Reference<sheet::XSpreadsheetDocument>& xDoc,
135 : : const table::CellAddress& rPos, double fValue )
136 : : {
137 : 0 : lcl_GetCell( xDoc, rPos )->setValue( fValue );
138 : 0 : }
139 : :
140 : 0 : double lcl_GetValue( const uno::Reference<sheet::XSpreadsheetDocument>& xDoc,
141 : : const table::CellAddress& rPos )
142 : : {
143 : 0 : return lcl_GetCell( xDoc, rPos )->getValue();
144 : : }
145 : :
146 : : // -------------------------------------------------------------------------
147 : :
148 : 0 : SolverComponent::SolverComponent( const uno::Reference<uno::XComponentContext>& /* rSMgr */ ) :
149 : 0 : OPropertyContainer( GetBroadcastHelper() ),
150 : : mbMaximize( sal_True ),
151 : : mbNonNegative( sal_False ),
152 : : mbInteger( sal_False ),
153 : : mnTimeout( 100 ),
154 : : mnEpsilonLevel( 0 ),
155 : : mbLimitBBDepth( sal_True ),
156 : : mbSuccess( sal_False ),
157 : 0 : mfResultValue( 0.0 )
158 : : {
159 : : // for XPropertySet implementation:
160 : 0 : registerProperty( C2U(STR_NONNEGATIVE), PROP_NONNEGATIVE, 0, &mbNonNegative, getCppuType( &mbNonNegative ) );
161 : 0 : registerProperty( C2U(STR_INTEGER), PROP_INTEGER, 0, &mbInteger, getCppuType( &mbInteger ) );
162 : 0 : registerProperty( C2U(STR_TIMEOUT), PROP_TIMEOUT, 0, &mnTimeout, getCppuType( &mnTimeout ) );
163 : 0 : registerProperty( C2U(STR_EPSILONLEVEL), PROP_EPSILONLEVEL, 0, &mnEpsilonLevel, getCppuType( &mnEpsilonLevel ) );
164 : 0 : registerProperty( C2U(STR_LIMITBBDEPTH), PROP_LIMITBBDEPTH, 0, &mbLimitBBDepth, getCppuType( &mbLimitBBDepth ) );
165 : 0 : }
166 : :
167 : 0 : SolverComponent::~SolverComponent()
168 : : {
169 : 0 : }
170 : :
171 : 0 : IMPLEMENT_FORWARD_XINTERFACE2( SolverComponent, SolverComponent_Base, OPropertyContainer )
172 : 0 : IMPLEMENT_FORWARD_XTYPEPROVIDER2( SolverComponent, SolverComponent_Base, OPropertyContainer )
173 : :
174 : 0 : cppu::IPropertyArrayHelper* SolverComponent::createArrayHelper() const
175 : : {
176 : 0 : uno::Sequence<beans::Property> aProps;
177 : 0 : describeProperties( aProps );
178 : 0 : return new cppu::OPropertyArrayHelper( aProps );
179 : : }
180 : :
181 : 0 : cppu::IPropertyArrayHelper& SAL_CALL SolverComponent::getInfoHelper()
182 : : {
183 : 0 : return *getArrayHelper();
184 : : }
185 : :
186 : 0 : uno::Reference<beans::XPropertySetInfo> SAL_CALL SolverComponent::getPropertySetInfo() throw(uno::RuntimeException)
187 : : {
188 : 0 : return createPropertySetInfo( getInfoHelper() );
189 : : }
190 : :
191 : : // XSolverDescription
192 : :
193 : 0 : OUString SAL_CALL SolverComponent::getComponentDescription() throw (uno::RuntimeException)
194 : : {
195 : 0 : return lcl_GetResourceString( RID_SOLVER_COMPONENT );
196 : : }
197 : :
198 : 0 : OUString SAL_CALL SolverComponent::getStatusDescription() throw (uno::RuntimeException)
199 : : {
200 : 0 : return maStatus;
201 : : }
202 : :
203 : 0 : OUString SAL_CALL SolverComponent::getPropertyDescription( const OUString& rPropertyName ) throw (uno::RuntimeException)
204 : : {
205 : 0 : sal_uInt32 nResId = 0;
206 : 0 : sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName );
207 : 0 : switch (nHandle)
208 : : {
209 : : case PROP_NONNEGATIVE:
210 : 0 : nResId = RID_PROPERTY_NONNEGATIVE;
211 : 0 : break;
212 : : case PROP_INTEGER:
213 : 0 : nResId = RID_PROPERTY_INTEGER;
214 : 0 : break;
215 : : case PROP_TIMEOUT:
216 : 0 : nResId = RID_PROPERTY_TIMEOUT;
217 : 0 : break;
218 : : case PROP_EPSILONLEVEL:
219 : 0 : nResId = RID_PROPERTY_EPSILONLEVEL;
220 : 0 : break;
221 : : case PROP_LIMITBBDEPTH:
222 : 0 : nResId = RID_PROPERTY_LIMITBBDEPTH;
223 : 0 : break;
224 : : default:
225 : : {
226 : : // unknown - leave empty
227 : : }
228 : : }
229 : 0 : OUString aRet;
230 : 0 : if ( nResId )
231 : 0 : aRet = lcl_GetResourceString( nResId );
232 : 0 : return aRet;
233 : : }
234 : :
235 : : // XSolver: settings
236 : :
237 : 0 : uno::Reference<sheet::XSpreadsheetDocument> SAL_CALL SolverComponent::getDocument() throw(uno::RuntimeException)
238 : : {
239 : 0 : return mxDoc;
240 : : }
241 : :
242 : 0 : void SAL_CALL SolverComponent::setDocument( const uno::Reference<sheet::XSpreadsheetDocument>& _document )
243 : : throw(uno::RuntimeException)
244 : : {
245 : 0 : mxDoc = _document;
246 : 0 : }
247 : :
248 : 0 : table::CellAddress SAL_CALL SolverComponent::getObjective() throw(uno::RuntimeException)
249 : : {
250 : 0 : return maObjective;
251 : : }
252 : :
253 : 0 : void SAL_CALL SolverComponent::setObjective( const table::CellAddress& _objective ) throw(uno::RuntimeException)
254 : : {
255 : 0 : maObjective = _objective;
256 : 0 : }
257 : :
258 : 0 : uno::Sequence<table::CellAddress> SAL_CALL SolverComponent::getVariables() throw(uno::RuntimeException)
259 : : {
260 : 0 : return maVariables;
261 : : }
262 : :
263 : 0 : void SAL_CALL SolverComponent::setVariables( const uno::Sequence<table::CellAddress>& _variables )
264 : : throw(uno::RuntimeException)
265 : : {
266 : 0 : maVariables = _variables;
267 : 0 : }
268 : :
269 : 0 : uno::Sequence<sheet::SolverConstraint> SAL_CALL SolverComponent::getConstraints() throw(uno::RuntimeException)
270 : : {
271 : 0 : return maConstraints;
272 : : }
273 : :
274 : 0 : void SAL_CALL SolverComponent::setConstraints( const uno::Sequence<sheet::SolverConstraint>& _constraints )
275 : : throw(uno::RuntimeException)
276 : : {
277 : 0 : maConstraints = _constraints;
278 : 0 : }
279 : :
280 : 0 : sal_Bool SAL_CALL SolverComponent::getMaximize() throw(uno::RuntimeException)
281 : : {
282 : 0 : return mbMaximize;
283 : : }
284 : :
285 : 0 : void SAL_CALL SolverComponent::setMaximize( sal_Bool _maximize ) throw(uno::RuntimeException)
286 : : {
287 : 0 : mbMaximize = _maximize;
288 : 0 : }
289 : :
290 : : // XSolver: get results
291 : :
292 : 0 : sal_Bool SAL_CALL SolverComponent::getSuccess() throw(uno::RuntimeException)
293 : : {
294 : 0 : return mbSuccess;
295 : : }
296 : :
297 : 0 : double SAL_CALL SolverComponent::getResultValue() throw(uno::RuntimeException)
298 : : {
299 : 0 : return mfResultValue;
300 : : }
301 : :
302 : 0 : uno::Sequence<double> SAL_CALL SolverComponent::getSolution() throw(uno::RuntimeException)
303 : : {
304 : 0 : return maSolution;
305 : : }
306 : :
307 : : // -------------------------------------------------------------------------
308 : :
309 : 0 : void SAL_CALL SolverComponent::solve() throw(uno::RuntimeException)
310 : : {
311 : 0 : uno::Reference<frame::XModel> xModel( mxDoc, uno::UNO_QUERY );
312 : 0 : if ( !xModel.is() )
313 : 0 : throw uno::RuntimeException();
314 : :
315 : 0 : maStatus = OUString();
316 : 0 : mbSuccess = false;
317 : :
318 : 0 : if ( mnEpsilonLevel < EPS_TIGHT || mnEpsilonLevel > EPS_BAGGY )
319 : : {
320 : 0 : maStatus = lcl_GetResourceString( RID_ERROR_EPSILONLEVEL );
321 : : return;
322 : : }
323 : :
324 : 0 : xModel->lockControllers();
325 : :
326 : : // collect variables in vector (?)
327 : :
328 : 0 : std::vector<table::CellAddress> aVariableCells;
329 : 0 : for (sal_Int32 nPos=0; nPos<maVariables.getLength(); nPos++)
330 : 0 : aVariableCells.push_back( maVariables[nPos] );
331 : 0 : size_t nVariables = aVariableCells.size();
332 : 0 : size_t nVar = 0;
333 : :
334 : : // collect all dependent cells
335 : :
336 : 0 : ScSolverCellHashMap aCellsHash;
337 : 0 : aCellsHash[maObjective].reserve( nVariables + 1 ); // objective function
338 : :
339 : 0 : for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos)
340 : : {
341 : 0 : table::CellAddress aCellAddr = maConstraints[nConstrPos].Left;
342 : 0 : aCellsHash[aCellAddr].reserve( nVariables + 1 ); // constraints: left hand side
343 : :
344 : 0 : if ( maConstraints[nConstrPos].Right >>= aCellAddr )
345 : 0 : aCellsHash[aCellAddr].reserve( nVariables + 1 ); // constraints: right hand side
346 : : }
347 : :
348 : : // set all variables to zero
349 : : //! store old values?
350 : : //! use old values as initial values?
351 : 0 : std::vector<table::CellAddress>::const_iterator aVarIter;
352 : 0 : for ( aVarIter = aVariableCells.begin(); aVarIter != aVariableCells.end(); ++aVarIter )
353 : : {
354 : 0 : lcl_SetValue( mxDoc, *aVarIter, 0.0 );
355 : : }
356 : :
357 : : // read initial values from all dependent cells
358 : 0 : ScSolverCellHashMap::iterator aCellsIter;
359 : 0 : for ( aCellsIter = aCellsHash.begin(); aCellsIter != aCellsHash.end(); ++aCellsIter )
360 : : {
361 : 0 : double fValue = lcl_GetValue( mxDoc, aCellsIter->first );
362 : 0 : aCellsIter->second.push_back( fValue ); // store as first element, as-is
363 : : }
364 : :
365 : : // loop through variables
366 : 0 : for ( aVarIter = aVariableCells.begin(); aVarIter != aVariableCells.end(); ++aVarIter )
367 : : {
368 : 0 : lcl_SetValue( mxDoc, *aVarIter, 1.0 ); // set to 1 to examine influence
369 : :
370 : : // read value change from all dependent cells
371 : 0 : for ( aCellsIter = aCellsHash.begin(); aCellsIter != aCellsHash.end(); ++aCellsIter )
372 : : {
373 : 0 : double fChanged = lcl_GetValue( mxDoc, aCellsIter->first );
374 : 0 : double fInitial = aCellsIter->second.front();
375 : 0 : aCellsIter->second.push_back( fChanged - fInitial );
376 : : }
377 : :
378 : 0 : lcl_SetValue( mxDoc, *aVarIter, 2.0 ); // minimal test for linearity
379 : :
380 : 0 : for ( aCellsIter = aCellsHash.begin(); aCellsIter != aCellsHash.end(); ++aCellsIter )
381 : : {
382 : 0 : double fInitial = aCellsIter->second.front();
383 : 0 : double fCoeff = aCellsIter->second.back(); // last appended: coefficient for this variable
384 : 0 : double fTwo = lcl_GetValue( mxDoc, aCellsIter->first );
385 : :
386 : 0 : bool bLinear = rtl::math::approxEqual( fTwo, fInitial + 2.0 * fCoeff ) ||
387 : 0 : rtl::math::approxEqual( fInitial, fTwo - 2.0 * fCoeff );
388 : : // second comparison is needed in case fTwo is zero
389 : 0 : if ( !bLinear )
390 : 0 : maStatus = lcl_GetResourceString( RID_ERROR_NONLINEAR );
391 : : }
392 : :
393 : 0 : lcl_SetValue( mxDoc, *aVarIter, 0.0 ); // set back to zero for examining next variable
394 : : }
395 : :
396 : 0 : xModel->unlockControllers();
397 : :
398 : 0 : if ( !maStatus.isEmpty() )
399 : : return;
400 : :
401 : : //
402 : : // build lp_solve model
403 : : //
404 : :
405 : 0 : lprec* lp = make_lp( 0, nVariables );
406 : 0 : if ( !lp )
407 : : return;
408 : :
409 : 0 : set_outputfile( lp, const_cast<char*>( "" ) ); // no output
410 : :
411 : : // set objective function
412 : :
413 : 0 : const std::vector<double>& rObjCoeff = aCellsHash[maObjective];
414 : 0 : REAL* pObjVal = new REAL[nVariables+1];
415 : 0 : pObjVal[0] = 0.0; // ignored
416 : 0 : for (nVar=0; nVar<nVariables; nVar++)
417 : 0 : pObjVal[nVar+1] = rObjCoeff[nVar+1];
418 : 0 : set_obj_fn( lp, pObjVal );
419 : 0 : delete[] pObjVal;
420 : 0 : set_rh( lp, 0, rObjCoeff[0] ); // constant term of objective
421 : :
422 : : // add rows
423 : :
424 : 0 : set_add_rowmode(lp, TRUE);
425 : :
426 : 0 : for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos)
427 : : {
428 : : // integer constraints are set later
429 : 0 : sheet::SolverConstraintOperator eOp = maConstraints[nConstrPos].Operator;
430 : 0 : if ( eOp == sheet::SolverConstraintOperator_LESS_EQUAL ||
431 : : eOp == sheet::SolverConstraintOperator_GREATER_EQUAL ||
432 : : eOp == sheet::SolverConstraintOperator_EQUAL )
433 : : {
434 : 0 : double fDirectValue = 0.0;
435 : 0 : bool bRightCell = false;
436 : 0 : table::CellAddress aRightAddr;
437 : 0 : const uno::Any& rRightAny = maConstraints[nConstrPos].Right;
438 : 0 : if ( rRightAny >>= aRightAddr )
439 : 0 : bRightCell = true; // cell specified as right-hand side
440 : : else
441 : 0 : rRightAny >>= fDirectValue; // constant value
442 : :
443 : 0 : table::CellAddress aLeftAddr = maConstraints[nConstrPos].Left;
444 : :
445 : 0 : const std::vector<double>& rLeftCoeff = aCellsHash[aLeftAddr];
446 : 0 : REAL* pValues = new REAL[nVariables+1];
447 : 0 : pValues[0] = 0.0; // ignored?
448 : 0 : for (nVar=0; nVar<nVariables; nVar++)
449 : 0 : pValues[nVar+1] = rLeftCoeff[nVar+1];
450 : :
451 : : // if left hand cell has a constant term, put into rhs value
452 : 0 : double fRightValue = -rLeftCoeff[0];
453 : :
454 : 0 : if ( bRightCell )
455 : : {
456 : 0 : const std::vector<double>& rRightCoeff = aCellsHash[aRightAddr];
457 : : // modify pValues with rhs coefficients
458 : 0 : for (nVar=0; nVar<nVariables; nVar++)
459 : 0 : pValues[nVar+1] -= rRightCoeff[nVar+1];
460 : :
461 : 0 : fRightValue += rRightCoeff[0]; // constant term
462 : : }
463 : : else
464 : 0 : fRightValue += fDirectValue;
465 : :
466 : 0 : int nConstrType = LE;
467 : 0 : switch ( eOp )
468 : : {
469 : 0 : case sheet::SolverConstraintOperator_LESS_EQUAL: nConstrType = LE; break;
470 : 0 : case sheet::SolverConstraintOperator_GREATER_EQUAL: nConstrType = GE; break;
471 : 0 : case sheet::SolverConstraintOperator_EQUAL: nConstrType = EQ; break;
472 : : default:
473 : : OSL_FAIL( "unexpected enum type" );
474 : : }
475 : 0 : add_constraint( lp, pValues, nConstrType, fRightValue );
476 : :
477 : 0 : delete[] pValues;
478 : : }
479 : : }
480 : :
481 : 0 : set_add_rowmode(lp, FALSE);
482 : :
483 : : // apply settings to all variables
484 : :
485 : 0 : for (nVar=0; nVar<nVariables; nVar++)
486 : : {
487 : 0 : if ( !mbNonNegative )
488 : 0 : set_unbounded(lp, nVar+1); // allow negative (default is non-negative)
489 : : //! collect bounds from constraints?
490 : 0 : if ( mbInteger )
491 : 0 : set_int(lp, nVar+1, TRUE);
492 : : }
493 : :
494 : : // apply single-var integer constraints
495 : :
496 : 0 : for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos)
497 : : {
498 : 0 : sheet::SolverConstraintOperator eOp = maConstraints[nConstrPos].Operator;
499 : 0 : if ( eOp == sheet::SolverConstraintOperator_INTEGER ||
500 : : eOp == sheet::SolverConstraintOperator_BINARY )
501 : : {
502 : 0 : table::CellAddress aLeftAddr = maConstraints[nConstrPos].Left;
503 : : // find variable index for cell
504 : 0 : for (nVar=0; nVar<nVariables; nVar++)
505 : 0 : if ( AddressEqual( aVariableCells[nVar], aLeftAddr ) )
506 : : {
507 : 0 : if ( eOp == sheet::SolverConstraintOperator_INTEGER )
508 : 0 : set_int(lp, nVar+1, TRUE);
509 : : else
510 : 0 : set_binary(lp, nVar+1, TRUE);
511 : : }
512 : : }
513 : : }
514 : :
515 : 0 : if ( mbMaximize )
516 : 0 : set_maxim(lp);
517 : : else
518 : 0 : set_minim(lp);
519 : :
520 : 0 : if ( !mbLimitBBDepth )
521 : 0 : set_bb_depthlimit( lp, 0 );
522 : :
523 : 0 : set_epslevel( lp, mnEpsilonLevel );
524 : 0 : set_timeout( lp, mnTimeout );
525 : :
526 : : // solve model
527 : :
528 : 0 : int nResult = ::solve( lp );
529 : :
530 : 0 : mbSuccess = ( nResult == OPTIMAL );
531 : 0 : if ( mbSuccess )
532 : : {
533 : : // get solution
534 : :
535 : 0 : maSolution.realloc( nVariables );
536 : :
537 : 0 : REAL* pResultVar = NULL;
538 : 0 : get_ptr_variables( lp, &pResultVar );
539 : 0 : for (nVar=0; nVar<nVariables; nVar++)
540 : 0 : maSolution[nVar] = pResultVar[nVar];
541 : :
542 : 0 : mfResultValue = get_objective( lp );
543 : : }
544 : 0 : else if ( nResult == INFEASIBLE )
545 : 0 : maStatus = lcl_GetResourceString( RID_ERROR_INFEASIBLE );
546 : 0 : else if ( nResult == UNBOUNDED )
547 : 0 : maStatus = lcl_GetResourceString( RID_ERROR_UNBOUNDED );
548 : 0 : else if ( nResult == TIMEOUT || nResult == SUBOPTIMAL )
549 : 0 : maStatus = lcl_GetResourceString( RID_ERROR_TIMEOUT );
550 : : // SUBOPTIMAL is assumed to be caused by a timeout, and reported as an error
551 : :
552 : 0 : delete_lp( lp );
553 : : }
554 : :
555 : : // -------------------------------------------------------------------------
556 : :
557 : : // XServiceInfo
558 : :
559 : 0 : uno::Sequence< OUString > SolverComponent_getSupportedServiceNames()
560 : : {
561 : 0 : uno::Sequence< OUString > aServiceNames( 1 );
562 : 0 : aServiceNames[ 0 ] = OUString("com.sun.star.sheet.Solver" );
563 : 0 : return aServiceNames;
564 : : }
565 : :
566 : 0 : OUString SolverComponent_getImplementationName()
567 : : {
568 : 0 : return OUString("com.sun.star.comp.Calc.Solver" );
569 : : }
570 : :
571 : 0 : OUString SAL_CALL SolverComponent::getImplementationName() throw(uno::RuntimeException)
572 : : {
573 : 0 : return SolverComponent_getImplementationName();
574 : : }
575 : :
576 : 0 : sal_Bool SAL_CALL SolverComponent::supportsService( const OUString& rServiceName ) throw(uno::RuntimeException)
577 : : {
578 : 0 : const uno::Sequence< OUString > aServices = SolverComponent_getSupportedServiceNames();
579 : 0 : const OUString* pArray = aServices.getConstArray();
580 : 0 : const OUString* pArrayEnd = pArray + aServices.getLength();
581 : 0 : return ::std::find( pArray, pArrayEnd, rServiceName ) != pArrayEnd;
582 : : }
583 : :
584 : 0 : uno::Sequence<OUString> SAL_CALL SolverComponent::getSupportedServiceNames() throw(uno::RuntimeException)
585 : : {
586 : 0 : return SolverComponent_getSupportedServiceNames();
587 : : }
588 : :
589 : 0 : uno::Reference<uno::XInterface> SolverComponent_createInstance( const uno::Reference<uno::XComponentContext>& rSMgr )
590 : : throw(uno::Exception)
591 : : {
592 : 0 : return (cppu::OWeakObject*) new SolverComponent( rSMgr );
593 : : }
594 : :
595 : : // -------------------------------------------------------------------------
596 : :
597 : : extern "C"
598 : : {
599 : 0 : SAL_DLLPUBLIC_EXPORT void* SAL_CALL solver_component_getFactory( const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ )
600 : : {
601 : 0 : OUString aImplName( OUString::createFromAscii( pImplName ) );
602 : 0 : void* pRet = 0;
603 : :
604 : 0 : if( pServiceManager )
605 : : {
606 : 0 : uno::Reference< lang::XSingleComponentFactory > xFactory;
607 : 0 : if( aImplName.equals( SolverComponent_getImplementationName() ) )
608 : : xFactory = cppu::createSingleComponentFactory(
609 : : SolverComponent_createInstance,
610 : : OUString::createFromAscii( pImplName ),
611 : 0 : SolverComponent_getSupportedServiceNames() );
612 : :
613 : 0 : if( xFactory.is() )
614 : : {
615 : 0 : xFactory->acquire();
616 : 0 : pRet = xFactory.get();
617 : 0 : }
618 : : }
619 : 0 : return pRet;
620 : : }
621 : : }
622 : :
623 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|