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