1e4f93722SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3e4f93722SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4e4f93722SAndrew Rist * or more contributor license agreements. See the NOTICE file 5e4f93722SAndrew Rist * distributed with this work for additional information 6e4f93722SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7e4f93722SAndrew Rist * to you under the Apache License, Version 2.0 (the 8e4f93722SAndrew Rist * "License"); you may not use this file except in compliance 9e4f93722SAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11e4f93722SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13e4f93722SAndrew Rist * Unless required by applicable law or agreed to in writing, 14e4f93722SAndrew Rist * software distributed under the License is distributed on an 15e4f93722SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16e4f93722SAndrew Rist * KIND, either express or implied. See the License for the 17e4f93722SAndrew Rist * specific language governing permissions and limitations 18e4f93722SAndrew Rist * under the License. 19cdf0e10cSrcweir * 20e4f93722SAndrew Rist *************************************************************/ 21e4f93722SAndrew Rist 22e4f93722SAndrew Rist 23*1f56509eSdamjan #include <CoinMP.h> 24cdf0e10cSrcweir 25cdf0e10cSrcweir #include "solver.hxx" 26cdf0e10cSrcweir #include "solver.hrc" 27cdf0e10cSrcweir 28cdf0e10cSrcweir #include <com/sun/star/beans/XPropertySet.hpp> 29cdf0e10cSrcweir #include <com/sun/star/container/XIndexAccess.hpp> 30cdf0e10cSrcweir #include <com/sun/star/frame/XModel.hpp> 31cdf0e10cSrcweir #include <com/sun/star/lang/XMultiServiceFactory.hpp> 32cdf0e10cSrcweir #include <com/sun/star/sheet/XSpreadsheetDocument.hpp> 33cdf0e10cSrcweir #include <com/sun/star/sheet/XSpreadsheet.hpp> 34cdf0e10cSrcweir #include <com/sun/star/table/CellAddress.hpp> 35cdf0e10cSrcweir #include <com/sun/star/table/CellRangeAddress.hpp> 36cdf0e10cSrcweir #include <com/sun/star/text/XTextRange.hpp> 37cdf0e10cSrcweir 38cdf0e10cSrcweir #include <rtl/math.hxx> 39cdf0e10cSrcweir #include <rtl/ustrbuf.hxx> 40cdf0e10cSrcweir #include <cppuhelper/factory.hxx> 41cdf0e10cSrcweir #include <vector> 42cdf0e10cSrcweir #include <hash_map> 43cdf0e10cSrcweir 44cdf0e10cSrcweir #include <tools/resmgr.hxx> 45cdf0e10cSrcweir 46cdf0e10cSrcweir using namespace com::sun::star; 47cdf0e10cSrcweir 48cdf0e10cSrcweir using ::rtl::OUString; 49cdf0e10cSrcweir 50cdf0e10cSrcweir #define C2U(constAsciiStr) (::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( constAsciiStr ) )) 51cdf0e10cSrcweir 52cdf0e10cSrcweir #define STR_NONNEGATIVE "NonNegative" 53cdf0e10cSrcweir #define STR_INTEGER "Integer" 54cdf0e10cSrcweir #define STR_TIMEOUT "Timeout" 55cdf0e10cSrcweir #define STR_EPSILONLEVEL "EpsilonLevel" 56cdf0e10cSrcweir #define STR_LIMITBBDEPTH "LimitBBDepth" 57b1f1da72SPedro Giffuni #define STR_NONLINEARTEST "NonLinearTest" 58cdf0e10cSrcweir 59cdf0e10cSrcweir // ----------------------------------------------------------------------- 60cdf0e10cSrcweir // Resources from tools are used for translated strings 61cdf0e10cSrcweir 62cdf0e10cSrcweir static ResMgr* pSolverResMgr = NULL; 63cdf0e10cSrcweir 64cdf0e10cSrcweir OUString lcl_GetResourceString( sal_uInt32 nId ) 65cdf0e10cSrcweir { 66cdf0e10cSrcweir if (!pSolverResMgr) 67cdf0e10cSrcweir pSolverResMgr = CREATEVERSIONRESMGR( solver ); 68cdf0e10cSrcweir 69cdf0e10cSrcweir return String( ResId( nId, *pSolverResMgr ) ); 70cdf0e10cSrcweir } 71cdf0e10cSrcweir 72cdf0e10cSrcweir // ----------------------------------------------------------------------- 73cdf0e10cSrcweir 74cdf0e10cSrcweir namespace 75cdf0e10cSrcweir { 76cdf0e10cSrcweir enum 77cdf0e10cSrcweir { 78cdf0e10cSrcweir PROP_NONNEGATIVE, 79cdf0e10cSrcweir PROP_INTEGER, 80cdf0e10cSrcweir PROP_TIMEOUT, 81cdf0e10cSrcweir PROP_EPSILONLEVEL, 82b1f1da72SPedro Giffuni PROP_LIMITBBDEPTH, 83b1f1da72SPedro Giffuni PROP_NONLINEARTEST 84cdf0e10cSrcweir }; 85cdf0e10cSrcweir } 86cdf0e10cSrcweir 87cdf0e10cSrcweir // ----------------------------------------------------------------------- 88cdf0e10cSrcweir 89cdf0e10cSrcweir // hash map for the coefficients of a dependent cell (objective or constraint) 90cdf0e10cSrcweir // The size of each vector is the number of columns (variable cells) plus one, first entry is initial value. 91cdf0e10cSrcweir 92cdf0e10cSrcweir struct ScSolverCellHash 93cdf0e10cSrcweir { 94cdf0e10cSrcweir size_t operator()( const table::CellAddress& rAddress ) const 95cdf0e10cSrcweir { 96cdf0e10cSrcweir return ( rAddress.Sheet << 24 ) | ( rAddress.Column << 16 ) | rAddress.Row; 97cdf0e10cSrcweir } 98cdf0e10cSrcweir }; 99cdf0e10cSrcweir 100cdf0e10cSrcweir inline bool AddressEqual( const table::CellAddress& rAddr1, const table::CellAddress& rAddr2 ) 101cdf0e10cSrcweir { 102cdf0e10cSrcweir return rAddr1.Sheet == rAddr2.Sheet && rAddr1.Column == rAddr2.Column && rAddr1.Row == rAddr2.Row; 103cdf0e10cSrcweir } 104cdf0e10cSrcweir 105cdf0e10cSrcweir struct ScSolverCellEqual 106cdf0e10cSrcweir { 107cdf0e10cSrcweir bool operator()( const table::CellAddress& rAddr1, const table::CellAddress& rAddr2 ) const 108cdf0e10cSrcweir { 109cdf0e10cSrcweir return AddressEqual( rAddr1, rAddr2 ); 110cdf0e10cSrcweir } 111cdf0e10cSrcweir }; 112cdf0e10cSrcweir 113cdf0e10cSrcweir typedef std::hash_map< table::CellAddress, std::vector<double>, ScSolverCellHash, ScSolverCellEqual > ScSolverCellHashMap; 114cdf0e10cSrcweir 115cdf0e10cSrcweir // ----------------------------------------------------------------------- 116cdf0e10cSrcweir 117cdf0e10cSrcweir uno::Reference<table::XCell> lcl_GetCell( const uno::Reference<sheet::XSpreadsheetDocument>& xDoc, 118cdf0e10cSrcweir const table::CellAddress& rPos ) 119cdf0e10cSrcweir { 120cdf0e10cSrcweir uno::Reference<container::XIndexAccess> xSheets( xDoc->getSheets(), uno::UNO_QUERY ); 121cdf0e10cSrcweir uno::Reference<sheet::XSpreadsheet> xSheet( xSheets->getByIndex( rPos.Sheet ), uno::UNO_QUERY ); 122cdf0e10cSrcweir return xSheet->getCellByPosition( rPos.Column, rPos.Row ); 123cdf0e10cSrcweir } 124cdf0e10cSrcweir 125cdf0e10cSrcweir void lcl_SetValue( const uno::Reference<sheet::XSpreadsheetDocument>& xDoc, 126cdf0e10cSrcweir const table::CellAddress& rPos, double fValue ) 127cdf0e10cSrcweir { 128cdf0e10cSrcweir lcl_GetCell( xDoc, rPos )->setValue( fValue ); 129cdf0e10cSrcweir } 130cdf0e10cSrcweir 131cdf0e10cSrcweir double lcl_GetValue( const uno::Reference<sheet::XSpreadsheetDocument>& xDoc, 132cdf0e10cSrcweir const table::CellAddress& rPos ) 133cdf0e10cSrcweir { 134cdf0e10cSrcweir return lcl_GetCell( xDoc, rPos )->getValue(); 135cdf0e10cSrcweir } 136cdf0e10cSrcweir 137cdf0e10cSrcweir // ------------------------------------------------------------------------- 138cdf0e10cSrcweir 139cdf0e10cSrcweir SolverComponent::SolverComponent( const uno::Reference<uno::XComponentContext>& /* rSMgr */ ) : 140cdf0e10cSrcweir OPropertyContainer( GetBroadcastHelper() ), 141cdf0e10cSrcweir mbMaximize( sal_True ), 142cdf0e10cSrcweir mbNonNegative( sal_False ), 143cdf0e10cSrcweir mbInteger( sal_False ), 144e74d7e62SPedro Giffuni mnTimeout( 120 ), 145cdf0e10cSrcweir mnEpsilonLevel( 0 ), 146cdf0e10cSrcweir mbLimitBBDepth( sal_True ), 147b1f1da72SPedro Giffuni mbNonLinearTest( sal_True ), 148cdf0e10cSrcweir mbSuccess( sal_False ), 149cdf0e10cSrcweir mfResultValue( 0.0 ) 150cdf0e10cSrcweir { 151cdf0e10cSrcweir // for XPropertySet implementation: 152cdf0e10cSrcweir registerProperty( C2U(STR_NONNEGATIVE), PROP_NONNEGATIVE, 0, &mbNonNegative, getCppuType( &mbNonNegative ) ); 153cdf0e10cSrcweir registerProperty( C2U(STR_INTEGER), PROP_INTEGER, 0, &mbInteger, getCppuType( &mbInteger ) ); 154cdf0e10cSrcweir registerProperty( C2U(STR_TIMEOUT), PROP_TIMEOUT, 0, &mnTimeout, getCppuType( &mnTimeout ) ); 155cdf0e10cSrcweir registerProperty( C2U(STR_EPSILONLEVEL), PROP_EPSILONLEVEL, 0, &mnEpsilonLevel, getCppuType( &mnEpsilonLevel ) ); 156cdf0e10cSrcweir registerProperty( C2U(STR_LIMITBBDEPTH), PROP_LIMITBBDEPTH, 0, &mbLimitBBDepth, getCppuType( &mbLimitBBDepth ) ); 157b1f1da72SPedro Giffuni registerProperty( C2U(STR_NONLINEARTEST), PROP_NONLINEARTEST, 0, &mbNonLinearTest, getCppuType( &mbNonLinearTest ) ); 158cdf0e10cSrcweir } 159cdf0e10cSrcweir 160cdf0e10cSrcweir SolverComponent::~SolverComponent() 161cdf0e10cSrcweir { 162cdf0e10cSrcweir } 163cdf0e10cSrcweir 164cdf0e10cSrcweir IMPLEMENT_FORWARD_XINTERFACE2( SolverComponent, SolverComponent_Base, OPropertyContainer ) 165cdf0e10cSrcweir IMPLEMENT_FORWARD_XTYPEPROVIDER2( SolverComponent, SolverComponent_Base, OPropertyContainer ) 166cdf0e10cSrcweir 167cdf0e10cSrcweir cppu::IPropertyArrayHelper* SolverComponent::createArrayHelper() const 168cdf0e10cSrcweir { 169cdf0e10cSrcweir uno::Sequence<beans::Property> aProps; 170cdf0e10cSrcweir describeProperties( aProps ); 171cdf0e10cSrcweir return new cppu::OPropertyArrayHelper( aProps ); 172cdf0e10cSrcweir } 173cdf0e10cSrcweir 174cdf0e10cSrcweir cppu::IPropertyArrayHelper& SAL_CALL SolverComponent::getInfoHelper() 175cdf0e10cSrcweir { 176cdf0e10cSrcweir return *getArrayHelper(); 177cdf0e10cSrcweir } 178cdf0e10cSrcweir 179cdf0e10cSrcweir uno::Reference<beans::XPropertySetInfo> SAL_CALL SolverComponent::getPropertySetInfo() throw(uno::RuntimeException) 180cdf0e10cSrcweir { 181cdf0e10cSrcweir return createPropertySetInfo( getInfoHelper() ); 182cdf0e10cSrcweir } 183cdf0e10cSrcweir 184cdf0e10cSrcweir // XSolverDescription 185cdf0e10cSrcweir 186cdf0e10cSrcweir OUString SAL_CALL SolverComponent::getComponentDescription() throw (uno::RuntimeException) 187cdf0e10cSrcweir { 188cdf0e10cSrcweir return lcl_GetResourceString( RID_SOLVER_COMPONENT ); 189cdf0e10cSrcweir } 190cdf0e10cSrcweir 191cdf0e10cSrcweir OUString SAL_CALL SolverComponent::getStatusDescription() throw (uno::RuntimeException) 192cdf0e10cSrcweir { 193cdf0e10cSrcweir return maStatus; 194cdf0e10cSrcweir } 195cdf0e10cSrcweir 196cdf0e10cSrcweir OUString SAL_CALL SolverComponent::getPropertyDescription( const OUString& rPropertyName ) throw (uno::RuntimeException) 197cdf0e10cSrcweir { 198cdf0e10cSrcweir sal_uInt32 nResId = 0; 199cdf0e10cSrcweir sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); 200cdf0e10cSrcweir switch (nHandle) 201cdf0e10cSrcweir { 202cdf0e10cSrcweir case PROP_NONNEGATIVE: 203cdf0e10cSrcweir nResId = RID_PROPERTY_NONNEGATIVE; 204cdf0e10cSrcweir break; 205cdf0e10cSrcweir case PROP_INTEGER: 206cdf0e10cSrcweir nResId = RID_PROPERTY_INTEGER; 207cdf0e10cSrcweir break; 208cdf0e10cSrcweir case PROP_TIMEOUT: 209cdf0e10cSrcweir nResId = RID_PROPERTY_TIMEOUT; 210cdf0e10cSrcweir break; 211cdf0e10cSrcweir case PROP_EPSILONLEVEL: 212cdf0e10cSrcweir nResId = RID_PROPERTY_EPSILONLEVEL; 213cdf0e10cSrcweir break; 214cdf0e10cSrcweir case PROP_LIMITBBDEPTH: 215cdf0e10cSrcweir nResId = RID_PROPERTY_LIMITBBDEPTH; 216cdf0e10cSrcweir break; 217b1f1da72SPedro Giffuni case PROP_NONLINEARTEST: 218b1f1da72SPedro Giffuni nResId = RID_PROPERTY_NONLINEARTEST; 219b1f1da72SPedro Giffuni break; 220cdf0e10cSrcweir default: 221cdf0e10cSrcweir { 222cdf0e10cSrcweir // unknown - leave empty 223cdf0e10cSrcweir } 224cdf0e10cSrcweir } 225cdf0e10cSrcweir OUString aRet; 226cdf0e10cSrcweir if ( nResId ) 227cdf0e10cSrcweir aRet = lcl_GetResourceString( nResId ); 228cdf0e10cSrcweir return aRet; 229cdf0e10cSrcweir } 230cdf0e10cSrcweir 231cdf0e10cSrcweir // XSolver: settings 232cdf0e10cSrcweir 233cdf0e10cSrcweir uno::Reference<sheet::XSpreadsheetDocument> SAL_CALL SolverComponent::getDocument() throw(uno::RuntimeException) 234cdf0e10cSrcweir { 235cdf0e10cSrcweir return mxDoc; 236cdf0e10cSrcweir } 237cdf0e10cSrcweir 238cdf0e10cSrcweir void SAL_CALL SolverComponent::setDocument( const uno::Reference<sheet::XSpreadsheetDocument>& _document ) 239cdf0e10cSrcweir throw(uno::RuntimeException) 240cdf0e10cSrcweir { 241cdf0e10cSrcweir mxDoc = _document; 242cdf0e10cSrcweir } 243cdf0e10cSrcweir 244cdf0e10cSrcweir table::CellAddress SAL_CALL SolverComponent::getObjective() throw(uno::RuntimeException) 245cdf0e10cSrcweir { 246cdf0e10cSrcweir return maObjective; 247cdf0e10cSrcweir } 248cdf0e10cSrcweir 249cdf0e10cSrcweir void SAL_CALL SolverComponent::setObjective( const table::CellAddress& _objective ) throw(uno::RuntimeException) 250cdf0e10cSrcweir { 251cdf0e10cSrcweir maObjective = _objective; 252cdf0e10cSrcweir } 253cdf0e10cSrcweir 254cdf0e10cSrcweir uno::Sequence<table::CellAddress> SAL_CALL SolverComponent::getVariables() throw(uno::RuntimeException) 255cdf0e10cSrcweir { 256cdf0e10cSrcweir return maVariables; 257cdf0e10cSrcweir } 258cdf0e10cSrcweir 259cdf0e10cSrcweir void SAL_CALL SolverComponent::setVariables( const uno::Sequence<table::CellAddress>& _variables ) 260cdf0e10cSrcweir throw(uno::RuntimeException) 261cdf0e10cSrcweir { 262cdf0e10cSrcweir maVariables = _variables; 263cdf0e10cSrcweir } 264cdf0e10cSrcweir 265cdf0e10cSrcweir uno::Sequence<sheet::SolverConstraint> SAL_CALL SolverComponent::getConstraints() throw(uno::RuntimeException) 266cdf0e10cSrcweir { 267cdf0e10cSrcweir return maConstraints; 268cdf0e10cSrcweir } 269cdf0e10cSrcweir 270cdf0e10cSrcweir void SAL_CALL SolverComponent::setConstraints( const uno::Sequence<sheet::SolverConstraint>& _constraints ) 271cdf0e10cSrcweir throw(uno::RuntimeException) 272cdf0e10cSrcweir { 273cdf0e10cSrcweir maConstraints = _constraints; 274cdf0e10cSrcweir } 275cdf0e10cSrcweir 276cdf0e10cSrcweir sal_Bool SAL_CALL SolverComponent::getMaximize() throw(uno::RuntimeException) 277cdf0e10cSrcweir { 278cdf0e10cSrcweir return mbMaximize; 279cdf0e10cSrcweir } 280cdf0e10cSrcweir 281cdf0e10cSrcweir void SAL_CALL SolverComponent::setMaximize( sal_Bool _maximize ) throw(uno::RuntimeException) 282cdf0e10cSrcweir { 283cdf0e10cSrcweir mbMaximize = _maximize; 284cdf0e10cSrcweir } 285cdf0e10cSrcweir 286cdf0e10cSrcweir // XSolver: get results 287cdf0e10cSrcweir 288cdf0e10cSrcweir sal_Bool SAL_CALL SolverComponent::getSuccess() throw(uno::RuntimeException) 289cdf0e10cSrcweir { 290cdf0e10cSrcweir return mbSuccess; 291cdf0e10cSrcweir } 292cdf0e10cSrcweir 293cdf0e10cSrcweir double SAL_CALL SolverComponent::getResultValue() throw(uno::RuntimeException) 294cdf0e10cSrcweir { 295cdf0e10cSrcweir return mfResultValue; 296cdf0e10cSrcweir } 297cdf0e10cSrcweir 298cdf0e10cSrcweir uno::Sequence<double> SAL_CALL SolverComponent::getSolution() throw(uno::RuntimeException) 299cdf0e10cSrcweir { 300cdf0e10cSrcweir return maSolution; 301cdf0e10cSrcweir } 302cdf0e10cSrcweir 303cdf0e10cSrcweir // ------------------------------------------------------------------------- 304cdf0e10cSrcweir 305cdf0e10cSrcweir void SAL_CALL SolverComponent::solve() throw(uno::RuntimeException) 306cdf0e10cSrcweir { 307cdf0e10cSrcweir uno::Reference<frame::XModel> xModel( mxDoc, uno::UNO_QUERY ); 308cdf0e10cSrcweir if ( !xModel.is() ) 309cdf0e10cSrcweir throw uno::RuntimeException(); 310cdf0e10cSrcweir 311cdf0e10cSrcweir maStatus = OUString(); 312cdf0e10cSrcweir mbSuccess = false; 313cdf0e10cSrcweir 314cdf0e10cSrcweir xModel->lockControllers(); 315cdf0e10cSrcweir 316cdf0e10cSrcweir // collect variables in vector (?) 317cdf0e10cSrcweir 318cdf0e10cSrcweir std::vector<table::CellAddress> aVariableCells; 319cdf0e10cSrcweir for (sal_Int32 nPos=0; nPos<maVariables.getLength(); nPos++) 320cdf0e10cSrcweir aVariableCells.push_back( maVariables[nPos] ); 321cdf0e10cSrcweir size_t nVariables = aVariableCells.size(); 322cdf0e10cSrcweir size_t nVar = 0; 323cdf0e10cSrcweir 324cdf0e10cSrcweir // collect all dependent cells 325cdf0e10cSrcweir 326cdf0e10cSrcweir ScSolverCellHashMap aCellsHash; 327cdf0e10cSrcweir aCellsHash[maObjective].reserve( nVariables + 1 ); // objective function 328cdf0e10cSrcweir 329cdf0e10cSrcweir for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos) 330cdf0e10cSrcweir { 331cdf0e10cSrcweir table::CellAddress aCellAddr = maConstraints[nConstrPos].Left; 332cdf0e10cSrcweir aCellsHash[aCellAddr].reserve( nVariables + 1 ); // constraints: left hand side 333cdf0e10cSrcweir 334cdf0e10cSrcweir if ( maConstraints[nConstrPos].Right >>= aCellAddr ) 335cdf0e10cSrcweir aCellsHash[aCellAddr].reserve( nVariables + 1 ); // constraints: right hand side 336cdf0e10cSrcweir } 337cdf0e10cSrcweir 338cdf0e10cSrcweir // set all variables to zero 339cdf0e10cSrcweir //! store old values? 340cdf0e10cSrcweir //! use old values as initial values? 341cdf0e10cSrcweir std::vector<table::CellAddress>::const_iterator aVarIter; 342cdf0e10cSrcweir for ( aVarIter = aVariableCells.begin(); aVarIter != aVariableCells.end(); ++aVarIter ) 343cdf0e10cSrcweir { 344cdf0e10cSrcweir lcl_SetValue( mxDoc, *aVarIter, 0.0 ); 345cdf0e10cSrcweir } 346cdf0e10cSrcweir 347cdf0e10cSrcweir // read initial values from all dependent cells 348cdf0e10cSrcweir ScSolverCellHashMap::iterator aCellsIter; 349cdf0e10cSrcweir for ( aCellsIter = aCellsHash.begin(); aCellsIter != aCellsHash.end(); ++aCellsIter ) 350cdf0e10cSrcweir { 351cdf0e10cSrcweir double fValue = lcl_GetValue( mxDoc, aCellsIter->first ); 352cdf0e10cSrcweir aCellsIter->second.push_back( fValue ); // store as first element, as-is 353cdf0e10cSrcweir } 354cdf0e10cSrcweir 355cdf0e10cSrcweir // loop through variables 356cdf0e10cSrcweir for ( aVarIter = aVariableCells.begin(); aVarIter != aVariableCells.end(); ++aVarIter ) 357cdf0e10cSrcweir { 358cdf0e10cSrcweir lcl_SetValue( mxDoc, *aVarIter, 1.0 ); // set to 1 to examine influence 359cdf0e10cSrcweir 360cdf0e10cSrcweir // read value change from all dependent cells 361cdf0e10cSrcweir for ( aCellsIter = aCellsHash.begin(); aCellsIter != aCellsHash.end(); ++aCellsIter ) 362cdf0e10cSrcweir { 363cdf0e10cSrcweir double fChanged = lcl_GetValue( mxDoc, aCellsIter->first ); 364cdf0e10cSrcweir double fInitial = aCellsIter->second.front(); 365cdf0e10cSrcweir aCellsIter->second.push_back( fChanged - fInitial ); 366cdf0e10cSrcweir } 367cdf0e10cSrcweir 368cdf0e10cSrcweir lcl_SetValue( mxDoc, *aVarIter, 2.0 ); // minimal test for linearity 369cdf0e10cSrcweir 370cdf0e10cSrcweir for ( aCellsIter = aCellsHash.begin(); aCellsIter != aCellsHash.end(); ++aCellsIter ) 371cdf0e10cSrcweir { 372cdf0e10cSrcweir double fInitial = aCellsIter->second.front(); 373cdf0e10cSrcweir double fCoeff = aCellsIter->second.back(); // last appended: coefficient for this variable 374cdf0e10cSrcweir double fTwo = lcl_GetValue( mxDoc, aCellsIter->first ); 375b1f1da72SPedro Giffuni 376b1f1da72SPedro Giffuni if ( mbNonLinearTest ) 377b1f1da72SPedro Giffuni { 378b1f1da72SPedro Giffuni bool bLinear ( sal_True ); 379b1f1da72SPedro Giffuni bLinear = rtl::math::approxEqual( fTwo, fInitial + 2.0 * fCoeff ) || 380b1f1da72SPedro Giffuni rtl::math::approxEqual( fInitial, fTwo - 2.0 * fCoeff ); 381b1f1da72SPedro Giffuni // second comparison is needed in case fTwo is zero 382b1f1da72SPedro Giffuni if ( !bLinear ) 383b1f1da72SPedro Giffuni maStatus = lcl_GetResourceString( RID_ERROR_NONLINEAR ); 384b1f1da72SPedro Giffuni } 385cdf0e10cSrcweir } 386cdf0e10cSrcweir 387cdf0e10cSrcweir lcl_SetValue( mxDoc, *aVarIter, 0.0 ); // set back to zero for examining next variable 388cdf0e10cSrcweir } 389cdf0e10cSrcweir 390cdf0e10cSrcweir xModel->unlockControllers(); 391cdf0e10cSrcweir 392cdf0e10cSrcweir if ( maStatus.getLength() ) 393cdf0e10cSrcweir return; 394cdf0e10cSrcweir 395cdf0e10cSrcweir // 39670840c81SAndre Fischer // build parameter arrays for CoinMP 397cdf0e10cSrcweir // 398cdf0e10cSrcweir 399cdf0e10cSrcweir // set objective function 400cdf0e10cSrcweir 401cdf0e10cSrcweir const std::vector<double>& rObjCoeff = aCellsHash[maObjective]; 40270840c81SAndre Fischer double* pObjectCoeffs = new double[nVariables]; 403cdf0e10cSrcweir for (nVar=0; nVar<nVariables; nVar++) 40470840c81SAndre Fischer pObjectCoeffs[nVar] = rObjCoeff[nVar+1]; 40570840c81SAndre Fischer double nObjectConst = rObjCoeff[0]; // constant term of objective 406cdf0e10cSrcweir 407cdf0e10cSrcweir // add rows 408cdf0e10cSrcweir 40970840c81SAndre Fischer size_t nRows = maConstraints.getLength(); 41070840c81SAndre Fischer size_t nCompSize = nVariables * nRows; 41170840c81SAndre Fischer double* pCompMatrix = new double[nCompSize]; // first collect all coefficients, row-wise 41270840c81SAndre Fischer for (size_t i=0; i<nCompSize; i++) 41370840c81SAndre Fischer pCompMatrix[i] = 0.0; 41470840c81SAndre Fischer 41570840c81SAndre Fischer double* pRHS = new double[nRows]; 41670840c81SAndre Fischer char* pRowType = new char[nRows]; 41770840c81SAndre Fischer for (size_t i=0; i<nRows; i++) 41870840c81SAndre Fischer { 41970840c81SAndre Fischer pRHS[i] = 0.0; 42070840c81SAndre Fischer pRowType[i] = 'N'; 42170840c81SAndre Fischer } 422cdf0e10cSrcweir 423cdf0e10cSrcweir for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos) 424cdf0e10cSrcweir { 425cdf0e10cSrcweir // integer constraints are set later 426cdf0e10cSrcweir sheet::SolverConstraintOperator eOp = maConstraints[nConstrPos].Operator; 427cdf0e10cSrcweir if ( eOp == sheet::SolverConstraintOperator_LESS_EQUAL || 428cdf0e10cSrcweir eOp == sheet::SolverConstraintOperator_GREATER_EQUAL || 429cdf0e10cSrcweir eOp == sheet::SolverConstraintOperator_EQUAL ) 430cdf0e10cSrcweir { 431cdf0e10cSrcweir double fDirectValue = 0.0; 432cdf0e10cSrcweir bool bRightCell = false; 433cdf0e10cSrcweir table::CellAddress aRightAddr; 434cdf0e10cSrcweir const uno::Any& rRightAny = maConstraints[nConstrPos].Right; 435cdf0e10cSrcweir if ( rRightAny >>= aRightAddr ) 436cdf0e10cSrcweir bRightCell = true; // cell specified as right-hand side 437cdf0e10cSrcweir else 438cdf0e10cSrcweir rRightAny >>= fDirectValue; // constant value 439cdf0e10cSrcweir 440cdf0e10cSrcweir table::CellAddress aLeftAddr = maConstraints[nConstrPos].Left; 441cdf0e10cSrcweir 442cdf0e10cSrcweir const std::vector<double>& rLeftCoeff = aCellsHash[aLeftAddr]; 44370840c81SAndre Fischer double* pValues = &pCompMatrix[nConstrPos * nVariables]; 444cdf0e10cSrcweir for (nVar=0; nVar<nVariables; nVar++) 44570840c81SAndre Fischer pValues[nVar] = rLeftCoeff[nVar+1]; 446cdf0e10cSrcweir 447cdf0e10cSrcweir // if left hand cell has a constant term, put into rhs value 448cdf0e10cSrcweir double fRightValue = -rLeftCoeff[0]; 449cdf0e10cSrcweir 450cdf0e10cSrcweir if ( bRightCell ) 451cdf0e10cSrcweir { 452cdf0e10cSrcweir const std::vector<double>& rRightCoeff = aCellsHash[aRightAddr]; 453cdf0e10cSrcweir // modify pValues with rhs coefficients 454cdf0e10cSrcweir for (nVar=0; nVar<nVariables; nVar++) 45570840c81SAndre Fischer pValues[nVar] -= rRightCoeff[nVar+1]; 456cdf0e10cSrcweir 457cdf0e10cSrcweir fRightValue += rRightCoeff[0]; // constant term 458cdf0e10cSrcweir } 459cdf0e10cSrcweir else 460cdf0e10cSrcweir fRightValue += fDirectValue; 461cdf0e10cSrcweir 462cdf0e10cSrcweir switch ( eOp ) 463cdf0e10cSrcweir { 46470840c81SAndre Fischer case sheet::SolverConstraintOperator_LESS_EQUAL: pRowType[nConstrPos] = 'L'; break; 46570840c81SAndre Fischer case sheet::SolverConstraintOperator_GREATER_EQUAL: pRowType[nConstrPos] = 'G'; break; 46670840c81SAndre Fischer case sheet::SolverConstraintOperator_EQUAL: pRowType[nConstrPos] = 'E'; break; 467cdf0e10cSrcweir default: 468cdf0e10cSrcweir OSL_ENSURE( false, "unexpected enum type" ); 469cdf0e10cSrcweir } 47070840c81SAndre Fischer pRHS[nConstrPos] = fRightValue; 471cdf0e10cSrcweir } 472cdf0e10cSrcweir } 473cdf0e10cSrcweir 47470840c81SAndre Fischer // Find non-zero coefficients, column-wise 47570840c81SAndre Fischer 47670840c81SAndre Fischer int* pMatrixBegin = new int[nVariables+1]; 47770840c81SAndre Fischer int* pMatrixCount = new int[nVariables]; 47870840c81SAndre Fischer double* pMatrix = new double[nCompSize]; // not always completely used 47970840c81SAndre Fischer int* pMatrixIndex = new int[nCompSize]; 48070840c81SAndre Fischer int nMatrixPos = 0; 48170840c81SAndre Fischer for (nVar=0; nVar<nVariables; nVar++) 48270840c81SAndre Fischer { 48370840c81SAndre Fischer int nBegin = nMatrixPos; 48470840c81SAndre Fischer for (size_t nRow=0; nRow<nRows; nRow++) 48570840c81SAndre Fischer { 48670840c81SAndre Fischer double fCoeff = pCompMatrix[ nRow * nVariables + nVar ]; // row-wise 48770840c81SAndre Fischer if ( fCoeff != 0.0 ) 48870840c81SAndre Fischer { 48970840c81SAndre Fischer pMatrix[nMatrixPos] = fCoeff; 49070840c81SAndre Fischer pMatrixIndex[nMatrixPos] = nRow; 49170840c81SAndre Fischer ++nMatrixPos; 49270840c81SAndre Fischer } 49370840c81SAndre Fischer } 49470840c81SAndre Fischer pMatrixBegin[nVar] = nBegin; 49570840c81SAndre Fischer pMatrixCount[nVar] = nMatrixPos - nBegin; 49670840c81SAndre Fischer } 49770840c81SAndre Fischer pMatrixBegin[nVariables] = nMatrixPos; 49870840c81SAndre Fischer delete[] pCompMatrix; 49970840c81SAndre Fischer pCompMatrix = NULL; 500cdf0e10cSrcweir 501cdf0e10cSrcweir // apply settings to all variables 502cdf0e10cSrcweir 50370840c81SAndre Fischer double* pLowerBounds = new double[nVariables]; 50470840c81SAndre Fischer double* pUpperBounds = new double[nVariables]; 505cdf0e10cSrcweir for (nVar=0; nVar<nVariables; nVar++) 506cdf0e10cSrcweir { 50770840c81SAndre Fischer pLowerBounds[nVar] = mbNonNegative ? 0.0 : -DBL_MAX; 50870840c81SAndre Fischer pUpperBounds[nVar] = DBL_MAX; 50970840c81SAndre Fischer 51070840c81SAndre Fischer // bounds could possibly be further restricted from single-cell constraints 511cdf0e10cSrcweir } 512cdf0e10cSrcweir 51370840c81SAndre Fischer char* pColType = new char[nVariables]; 51470840c81SAndre Fischer for (nVar=0; nVar<nVariables; nVar++) 51570840c81SAndre Fischer pColType[nVar] = mbInteger ? 'I' : 'C'; 51670840c81SAndre Fischer 517cdf0e10cSrcweir // apply single-var integer constraints 518cdf0e10cSrcweir 519cdf0e10cSrcweir for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos) 520cdf0e10cSrcweir { 521cdf0e10cSrcweir sheet::SolverConstraintOperator eOp = maConstraints[nConstrPos].Operator; 522cdf0e10cSrcweir if ( eOp == sheet::SolverConstraintOperator_INTEGER || 523cdf0e10cSrcweir eOp == sheet::SolverConstraintOperator_BINARY ) 524cdf0e10cSrcweir { 525cdf0e10cSrcweir table::CellAddress aLeftAddr = maConstraints[nConstrPos].Left; 526cdf0e10cSrcweir // find variable index for cell 527cdf0e10cSrcweir for (nVar=0; nVar<nVariables; nVar++) 528cdf0e10cSrcweir if ( AddressEqual( aVariableCells[nVar], aLeftAddr ) ) 529cdf0e10cSrcweir { 530cdf0e10cSrcweir if ( eOp == sheet::SolverConstraintOperator_INTEGER ) 53170840c81SAndre Fischer pColType[nVar] = 'I'; 532cdf0e10cSrcweir else 53370840c81SAndre Fischer { 53470840c81SAndre Fischer pColType[nVar] = 'B'; 53570840c81SAndre Fischer pLowerBounds[nVar] = 0.0; 53670840c81SAndre Fischer pUpperBounds[nVar] = 1.0; 53770840c81SAndre Fischer } 538cdf0e10cSrcweir } 539cdf0e10cSrcweir } 540cdf0e10cSrcweir } 541cdf0e10cSrcweir 54270840c81SAndre Fischer int nObjectSense = mbMaximize ? SOLV_OBJSENS_MAX : SOLV_OBJSENS_MIN; 543cdf0e10cSrcweir 54470840c81SAndre Fischer HPROB hProb = CoinCreateProblem(""); 54570840c81SAndre Fischer int nResult = CoinLoadProblem( hProb, nVariables, nRows, nMatrixPos, 0, 54670840c81SAndre Fischer nObjectSense, nObjectConst, pObjectCoeffs, 54770840c81SAndre Fischer pLowerBounds, pUpperBounds, pRowType, pRHS, NULL, 54870840c81SAndre Fischer pMatrixBegin, pMatrixCount, pMatrixIndex, pMatrix, 54970840c81SAndre Fischer NULL, NULL, NULL ); 55070840c81SAndre Fischer nResult = CoinLoadInteger( hProb, pColType ); 551cdf0e10cSrcweir 55270840c81SAndre Fischer delete[] pColType; 55370840c81SAndre Fischer delete[] pMatrixIndex; 55470840c81SAndre Fischer delete[] pMatrix; 55570840c81SAndre Fischer delete[] pMatrixCount; 55670840c81SAndre Fischer delete[] pMatrixBegin; 55770840c81SAndre Fischer delete[] pUpperBounds; 55870840c81SAndre Fischer delete[] pLowerBounds; 55970840c81SAndre Fischer delete[] pRowType; 56070840c81SAndre Fischer delete[] pRHS; 56170840c81SAndre Fischer delete[] pObjectCoeffs; 56270840c81SAndre Fischer 56370840c81SAndre Fischer CoinSetRealOption( hProb, COIN_REAL_MAXSECONDS, mnTimeout ); 56470840c81SAndre Fischer CoinSetRealOption( hProb, COIN_REAL_MIPMAXSEC, mnTimeout ); 56570840c81SAndre Fischer 56670840c81SAndre Fischer // TODO: handle (or remove) settings: epsilon, B&B depth 567cdf0e10cSrcweir 568cdf0e10cSrcweir // solve model 569cdf0e10cSrcweir 57070840c81SAndre Fischer nResult = CoinCheckProblem( hProb ); 57170840c81SAndre Fischer nResult = CoinOptimizeProblem( hProb, 0 ); 572cdf0e10cSrcweir 57370840c81SAndre Fischer mbSuccess = ( nResult == SOLV_CALL_SUCCESS ); 574cdf0e10cSrcweir if ( mbSuccess ) 575cdf0e10cSrcweir { 576cdf0e10cSrcweir // get solution 577cdf0e10cSrcweir 578cdf0e10cSrcweir maSolution.realloc( nVariables ); 57970840c81SAndre Fischer CoinGetSolutionValues( hProb, maSolution.getArray(), NULL, NULL, NULL ); 58070840c81SAndre Fischer mfResultValue = CoinGetObjectValue( hProb ); 581cdf0e10cSrcweir } 58270840c81SAndre Fischer else 58370840c81SAndre Fischer { 58470840c81SAndre Fischer int nSolutionStatus = CoinGetSolutionStatus( hProb ); 58570840c81SAndre Fischer if ( nSolutionStatus == 1 ) 586cdf0e10cSrcweir maStatus = lcl_GetResourceString( RID_ERROR_INFEASIBLE ); 58770840c81SAndre Fischer else if ( nSolutionStatus == 2 ) 588cdf0e10cSrcweir maStatus = lcl_GetResourceString( RID_ERROR_UNBOUNDED ); 58970840c81SAndre Fischer // TODO: detect timeout condition and report as RID_ERROR_TIMEOUT 59070840c81SAndre Fischer // (currently reported as infeasible) 59170840c81SAndre Fischer } 592cdf0e10cSrcweir 59370840c81SAndre Fischer CoinUnloadProblem( hProb ); 594cdf0e10cSrcweir } 595cdf0e10cSrcweir 596cdf0e10cSrcweir // ------------------------------------------------------------------------- 597cdf0e10cSrcweir 598cdf0e10cSrcweir // XServiceInfo 599cdf0e10cSrcweir 600cdf0e10cSrcweir uno::Sequence< OUString > SolverComponent_getSupportedServiceNames() 601cdf0e10cSrcweir { 602cdf0e10cSrcweir uno::Sequence< OUString > aServiceNames( 1 ); 603cdf0e10cSrcweir aServiceNames[ 0 ] = OUString::createFromAscii( "com.sun.star.sheet.Solver" ); 604cdf0e10cSrcweir return aServiceNames; 605cdf0e10cSrcweir } 606cdf0e10cSrcweir 607cdf0e10cSrcweir OUString SolverComponent_getImplementationName() 608cdf0e10cSrcweir { 609cdf0e10cSrcweir return OUString::createFromAscii( "com.sun.star.comp.Calc.Solver" ); 610cdf0e10cSrcweir } 611cdf0e10cSrcweir 612cdf0e10cSrcweir OUString SAL_CALL SolverComponent::getImplementationName() throw(uno::RuntimeException) 613cdf0e10cSrcweir { 614cdf0e10cSrcweir return SolverComponent_getImplementationName(); 615cdf0e10cSrcweir } 616cdf0e10cSrcweir 617cdf0e10cSrcweir sal_Bool SAL_CALL SolverComponent::supportsService( const OUString& rServiceName ) throw(uno::RuntimeException) 618cdf0e10cSrcweir { 619cdf0e10cSrcweir const uno::Sequence< OUString > aServices = SolverComponent_getSupportedServiceNames(); 620cdf0e10cSrcweir const OUString* pArray = aServices.getConstArray(); 621cdf0e10cSrcweir const OUString* pArrayEnd = pArray + aServices.getLength(); 622cdf0e10cSrcweir return ::std::find( pArray, pArrayEnd, rServiceName ) != pArrayEnd; 623cdf0e10cSrcweir } 624cdf0e10cSrcweir 625cdf0e10cSrcweir uno::Sequence<OUString> SAL_CALL SolverComponent::getSupportedServiceNames() throw(uno::RuntimeException) 626cdf0e10cSrcweir { 627cdf0e10cSrcweir return SolverComponent_getSupportedServiceNames(); 628cdf0e10cSrcweir } 629cdf0e10cSrcweir 630cdf0e10cSrcweir uno::Reference<uno::XInterface> SolverComponent_createInstance( const uno::Reference<uno::XComponentContext>& rSMgr ) 631cdf0e10cSrcweir throw(uno::Exception) 632cdf0e10cSrcweir { 633cdf0e10cSrcweir return (cppu::OWeakObject*) new SolverComponent( rSMgr ); 634cdf0e10cSrcweir } 635cdf0e10cSrcweir 636cdf0e10cSrcweir // ------------------------------------------------------------------------- 637cdf0e10cSrcweir 638cdf0e10cSrcweir extern "C" 639cdf0e10cSrcweir { 640cdf0e10cSrcweir SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment( 641cdf0e10cSrcweir const sal_Char ** ppEnvTypeName, uno_Environment ** ) 642cdf0e10cSrcweir { 643cdf0e10cSrcweir *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; 644cdf0e10cSrcweir } 645cdf0e10cSrcweir 646cdf0e10cSrcweir // ------------------------------------------------------------------------- 647cdf0e10cSrcweir 648cdf0e10cSrcweir SAL_DLLPUBLIC_EXPORT void* SAL_CALL component_getFactory( const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ ) 649cdf0e10cSrcweir { 650cdf0e10cSrcweir OUString aImplName( OUString::createFromAscii( pImplName ) ); 651cdf0e10cSrcweir void* pRet = 0; 652cdf0e10cSrcweir 653cdf0e10cSrcweir if( pServiceManager ) 654cdf0e10cSrcweir { 655cdf0e10cSrcweir uno::Reference< lang::XSingleComponentFactory > xFactory; 656cdf0e10cSrcweir if( aImplName.equals( SolverComponent_getImplementationName() ) ) 657cdf0e10cSrcweir xFactory = cppu::createSingleComponentFactory( 658cdf0e10cSrcweir SolverComponent_createInstance, 659cdf0e10cSrcweir OUString::createFromAscii( pImplName ), 660cdf0e10cSrcweir SolverComponent_getSupportedServiceNames() ); 661cdf0e10cSrcweir 662cdf0e10cSrcweir if( xFactory.is() ) 663cdf0e10cSrcweir { 664cdf0e10cSrcweir xFactory->acquire(); 665cdf0e10cSrcweir pRet = xFactory.get(); 666cdf0e10cSrcweir } 667cdf0e10cSrcweir } 668cdf0e10cSrcweir return pRet; 669cdf0e10cSrcweir } 670cdf0e10cSrcweir } 671cdf0e10cSrcweir 672