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