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 23cdf0e10cSrcweir 24*70840c81SAndre Fischer #include <coinmp/CoinMP.h> 25cdf0e10cSrcweir 26cdf0e10cSrcweir #include "solver.hxx" 27cdf0e10cSrcweir #include "solver.hrc" 28cdf0e10cSrcweir 29cdf0e10cSrcweir #include <com/sun/star/beans/XPropertySet.hpp> 30cdf0e10cSrcweir #include <com/sun/star/container/XIndexAccess.hpp> 31cdf0e10cSrcweir #include <com/sun/star/frame/XModel.hpp> 32cdf0e10cSrcweir #include <com/sun/star/lang/XMultiServiceFactory.hpp> 33cdf0e10cSrcweir #include <com/sun/star/sheet/XSpreadsheetDocument.hpp> 34cdf0e10cSrcweir #include <com/sun/star/sheet/XSpreadsheet.hpp> 35cdf0e10cSrcweir #include <com/sun/star/table/CellAddress.hpp> 36cdf0e10cSrcweir #include <com/sun/star/table/CellRangeAddress.hpp> 37cdf0e10cSrcweir #include <com/sun/star/text/XTextRange.hpp> 38cdf0e10cSrcweir 39cdf0e10cSrcweir #include <rtl/math.hxx> 40cdf0e10cSrcweir #include <rtl/ustrbuf.hxx> 41cdf0e10cSrcweir #include <cppuhelper/factory.hxx> 42cdf0e10cSrcweir #include <vector> 43cdf0e10cSrcweir #include <hash_map> 44cdf0e10cSrcweir 45cdf0e10cSrcweir #include <tools/resmgr.hxx> 46cdf0e10cSrcweir 47cdf0e10cSrcweir using namespace com::sun::star; 48cdf0e10cSrcweir 49cdf0e10cSrcweir using ::rtl::OUString; 50cdf0e10cSrcweir 51cdf0e10cSrcweir #define C2U(constAsciiStr) (::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( constAsciiStr ) )) 52cdf0e10cSrcweir 53cdf0e10cSrcweir #define STR_NONNEGATIVE "NonNegative" 54cdf0e10cSrcweir #define STR_INTEGER "Integer" 55cdf0e10cSrcweir #define STR_TIMEOUT "Timeout" 56cdf0e10cSrcweir #define STR_EPSILONLEVEL "EpsilonLevel" 57cdf0e10cSrcweir #define STR_LIMITBBDEPTH "LimitBBDepth" 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, 82cdf0e10cSrcweir PROP_LIMITBBDEPTH 83cdf0e10cSrcweir }; 84cdf0e10cSrcweir } 85cdf0e10cSrcweir 86cdf0e10cSrcweir // ----------------------------------------------------------------------- 87cdf0e10cSrcweir 88cdf0e10cSrcweir // hash map for the coefficients of a dependent cell (objective or constraint) 89cdf0e10cSrcweir // The size of each vector is the number of columns (variable cells) plus one, first entry is initial value. 90cdf0e10cSrcweir 91cdf0e10cSrcweir struct ScSolverCellHash 92cdf0e10cSrcweir { 93cdf0e10cSrcweir size_t operator()( const table::CellAddress& rAddress ) const 94cdf0e10cSrcweir { 95cdf0e10cSrcweir return ( rAddress.Sheet << 24 ) | ( rAddress.Column << 16 ) | rAddress.Row; 96cdf0e10cSrcweir } 97cdf0e10cSrcweir }; 98cdf0e10cSrcweir 99cdf0e10cSrcweir inline bool AddressEqual( const table::CellAddress& rAddr1, const table::CellAddress& rAddr2 ) 100cdf0e10cSrcweir { 101cdf0e10cSrcweir return rAddr1.Sheet == rAddr2.Sheet && rAddr1.Column == rAddr2.Column && rAddr1.Row == rAddr2.Row; 102cdf0e10cSrcweir } 103cdf0e10cSrcweir 104cdf0e10cSrcweir struct ScSolverCellEqual 105cdf0e10cSrcweir { 106cdf0e10cSrcweir bool operator()( const table::CellAddress& rAddr1, const table::CellAddress& rAddr2 ) const 107cdf0e10cSrcweir { 108cdf0e10cSrcweir return AddressEqual( rAddr1, rAddr2 ); 109cdf0e10cSrcweir } 110cdf0e10cSrcweir }; 111cdf0e10cSrcweir 112cdf0e10cSrcweir typedef std::hash_map< table::CellAddress, std::vector<double>, ScSolverCellHash, ScSolverCellEqual > ScSolverCellHashMap; 113cdf0e10cSrcweir 114cdf0e10cSrcweir // ----------------------------------------------------------------------- 115cdf0e10cSrcweir 116cdf0e10cSrcweir uno::Reference<table::XCell> lcl_GetCell( const uno::Reference<sheet::XSpreadsheetDocument>& xDoc, 117cdf0e10cSrcweir const table::CellAddress& rPos ) 118cdf0e10cSrcweir { 119cdf0e10cSrcweir uno::Reference<container::XIndexAccess> xSheets( xDoc->getSheets(), uno::UNO_QUERY ); 120cdf0e10cSrcweir uno::Reference<sheet::XSpreadsheet> xSheet( xSheets->getByIndex( rPos.Sheet ), uno::UNO_QUERY ); 121cdf0e10cSrcweir return xSheet->getCellByPosition( rPos.Column, rPos.Row ); 122cdf0e10cSrcweir } 123cdf0e10cSrcweir 124cdf0e10cSrcweir void lcl_SetValue( const uno::Reference<sheet::XSpreadsheetDocument>& xDoc, 125cdf0e10cSrcweir const table::CellAddress& rPos, double fValue ) 126cdf0e10cSrcweir { 127cdf0e10cSrcweir lcl_GetCell( xDoc, rPos )->setValue( fValue ); 128cdf0e10cSrcweir } 129cdf0e10cSrcweir 130cdf0e10cSrcweir double lcl_GetValue( const uno::Reference<sheet::XSpreadsheetDocument>& xDoc, 131cdf0e10cSrcweir const table::CellAddress& rPos ) 132cdf0e10cSrcweir { 133cdf0e10cSrcweir return lcl_GetCell( xDoc, rPos )->getValue(); 134cdf0e10cSrcweir } 135cdf0e10cSrcweir 136cdf0e10cSrcweir // ------------------------------------------------------------------------- 137cdf0e10cSrcweir 138cdf0e10cSrcweir SolverComponent::SolverComponent( const uno::Reference<uno::XComponentContext>& /* rSMgr */ ) : 139cdf0e10cSrcweir OPropertyContainer( GetBroadcastHelper() ), 140cdf0e10cSrcweir mbMaximize( sal_True ), 141cdf0e10cSrcweir mbNonNegative( sal_False ), 142cdf0e10cSrcweir mbInteger( sal_False ), 143cdf0e10cSrcweir mnTimeout( 100 ), 144cdf0e10cSrcweir mnEpsilonLevel( 0 ), 145cdf0e10cSrcweir mbLimitBBDepth( sal_True ), 146cdf0e10cSrcweir mbSuccess( sal_False ), 147cdf0e10cSrcweir mfResultValue( 0.0 ) 148cdf0e10cSrcweir { 149cdf0e10cSrcweir // for XPropertySet implementation: 150cdf0e10cSrcweir registerProperty( C2U(STR_NONNEGATIVE), PROP_NONNEGATIVE, 0, &mbNonNegative, getCppuType( &mbNonNegative ) ); 151cdf0e10cSrcweir registerProperty( C2U(STR_INTEGER), PROP_INTEGER, 0, &mbInteger, getCppuType( &mbInteger ) ); 152cdf0e10cSrcweir registerProperty( C2U(STR_TIMEOUT), PROP_TIMEOUT, 0, &mnTimeout, getCppuType( &mnTimeout ) ); 153cdf0e10cSrcweir registerProperty( C2U(STR_EPSILONLEVEL), PROP_EPSILONLEVEL, 0, &mnEpsilonLevel, getCppuType( &mnEpsilonLevel ) ); 154cdf0e10cSrcweir registerProperty( C2U(STR_LIMITBBDEPTH), PROP_LIMITBBDEPTH, 0, &mbLimitBBDepth, getCppuType( &mbLimitBBDepth ) ); 155cdf0e10cSrcweir } 156cdf0e10cSrcweir 157cdf0e10cSrcweir SolverComponent::~SolverComponent() 158cdf0e10cSrcweir { 159cdf0e10cSrcweir } 160cdf0e10cSrcweir 161cdf0e10cSrcweir IMPLEMENT_FORWARD_XINTERFACE2( SolverComponent, SolverComponent_Base, OPropertyContainer ) 162cdf0e10cSrcweir IMPLEMENT_FORWARD_XTYPEPROVIDER2( SolverComponent, SolverComponent_Base, OPropertyContainer ) 163cdf0e10cSrcweir 164cdf0e10cSrcweir cppu::IPropertyArrayHelper* SolverComponent::createArrayHelper() const 165cdf0e10cSrcweir { 166cdf0e10cSrcweir uno::Sequence<beans::Property> aProps; 167cdf0e10cSrcweir describeProperties( aProps ); 168cdf0e10cSrcweir return new cppu::OPropertyArrayHelper( aProps ); 169cdf0e10cSrcweir } 170cdf0e10cSrcweir 171cdf0e10cSrcweir cppu::IPropertyArrayHelper& SAL_CALL SolverComponent::getInfoHelper() 172cdf0e10cSrcweir { 173cdf0e10cSrcweir return *getArrayHelper(); 174cdf0e10cSrcweir } 175cdf0e10cSrcweir 176cdf0e10cSrcweir uno::Reference<beans::XPropertySetInfo> SAL_CALL SolverComponent::getPropertySetInfo() throw(uno::RuntimeException) 177cdf0e10cSrcweir { 178cdf0e10cSrcweir return createPropertySetInfo( getInfoHelper() ); 179cdf0e10cSrcweir } 180cdf0e10cSrcweir 181cdf0e10cSrcweir // XSolverDescription 182cdf0e10cSrcweir 183cdf0e10cSrcweir OUString SAL_CALL SolverComponent::getComponentDescription() throw (uno::RuntimeException) 184cdf0e10cSrcweir { 185cdf0e10cSrcweir return lcl_GetResourceString( RID_SOLVER_COMPONENT ); 186cdf0e10cSrcweir } 187cdf0e10cSrcweir 188cdf0e10cSrcweir OUString SAL_CALL SolverComponent::getStatusDescription() throw (uno::RuntimeException) 189cdf0e10cSrcweir { 190cdf0e10cSrcweir return maStatus; 191cdf0e10cSrcweir } 192cdf0e10cSrcweir 193cdf0e10cSrcweir OUString SAL_CALL SolverComponent::getPropertyDescription( const OUString& rPropertyName ) throw (uno::RuntimeException) 194cdf0e10cSrcweir { 195cdf0e10cSrcweir sal_uInt32 nResId = 0; 196cdf0e10cSrcweir sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); 197cdf0e10cSrcweir switch (nHandle) 198cdf0e10cSrcweir { 199cdf0e10cSrcweir case PROP_NONNEGATIVE: 200cdf0e10cSrcweir nResId = RID_PROPERTY_NONNEGATIVE; 201cdf0e10cSrcweir break; 202cdf0e10cSrcweir case PROP_INTEGER: 203cdf0e10cSrcweir nResId = RID_PROPERTY_INTEGER; 204cdf0e10cSrcweir break; 205cdf0e10cSrcweir case PROP_TIMEOUT: 206cdf0e10cSrcweir nResId = RID_PROPERTY_TIMEOUT; 207cdf0e10cSrcweir break; 208cdf0e10cSrcweir case PROP_EPSILONLEVEL: 209cdf0e10cSrcweir nResId = RID_PROPERTY_EPSILONLEVEL; 210cdf0e10cSrcweir break; 211cdf0e10cSrcweir case PROP_LIMITBBDEPTH: 212cdf0e10cSrcweir nResId = RID_PROPERTY_LIMITBBDEPTH; 213cdf0e10cSrcweir break; 214cdf0e10cSrcweir default: 215cdf0e10cSrcweir { 216cdf0e10cSrcweir // unknown - leave empty 217cdf0e10cSrcweir } 218cdf0e10cSrcweir } 219cdf0e10cSrcweir OUString aRet; 220cdf0e10cSrcweir if ( nResId ) 221cdf0e10cSrcweir aRet = lcl_GetResourceString( nResId ); 222cdf0e10cSrcweir return aRet; 223cdf0e10cSrcweir } 224cdf0e10cSrcweir 225cdf0e10cSrcweir // XSolver: settings 226cdf0e10cSrcweir 227cdf0e10cSrcweir uno::Reference<sheet::XSpreadsheetDocument> SAL_CALL SolverComponent::getDocument() throw(uno::RuntimeException) 228cdf0e10cSrcweir { 229cdf0e10cSrcweir return mxDoc; 230cdf0e10cSrcweir } 231cdf0e10cSrcweir 232cdf0e10cSrcweir void SAL_CALL SolverComponent::setDocument( const uno::Reference<sheet::XSpreadsheetDocument>& _document ) 233cdf0e10cSrcweir throw(uno::RuntimeException) 234cdf0e10cSrcweir { 235cdf0e10cSrcweir mxDoc = _document; 236cdf0e10cSrcweir } 237cdf0e10cSrcweir 238cdf0e10cSrcweir table::CellAddress SAL_CALL SolverComponent::getObjective() throw(uno::RuntimeException) 239cdf0e10cSrcweir { 240cdf0e10cSrcweir return maObjective; 241cdf0e10cSrcweir } 242cdf0e10cSrcweir 243cdf0e10cSrcweir void SAL_CALL SolverComponent::setObjective( const table::CellAddress& _objective ) throw(uno::RuntimeException) 244cdf0e10cSrcweir { 245cdf0e10cSrcweir maObjective = _objective; 246cdf0e10cSrcweir } 247cdf0e10cSrcweir 248cdf0e10cSrcweir uno::Sequence<table::CellAddress> SAL_CALL SolverComponent::getVariables() throw(uno::RuntimeException) 249cdf0e10cSrcweir { 250cdf0e10cSrcweir return maVariables; 251cdf0e10cSrcweir } 252cdf0e10cSrcweir 253cdf0e10cSrcweir void SAL_CALL SolverComponent::setVariables( const uno::Sequence<table::CellAddress>& _variables ) 254cdf0e10cSrcweir throw(uno::RuntimeException) 255cdf0e10cSrcweir { 256cdf0e10cSrcweir maVariables = _variables; 257cdf0e10cSrcweir } 258cdf0e10cSrcweir 259cdf0e10cSrcweir uno::Sequence<sheet::SolverConstraint> SAL_CALL SolverComponent::getConstraints() throw(uno::RuntimeException) 260cdf0e10cSrcweir { 261cdf0e10cSrcweir return maConstraints; 262cdf0e10cSrcweir } 263cdf0e10cSrcweir 264cdf0e10cSrcweir void SAL_CALL SolverComponent::setConstraints( const uno::Sequence<sheet::SolverConstraint>& _constraints ) 265cdf0e10cSrcweir throw(uno::RuntimeException) 266cdf0e10cSrcweir { 267cdf0e10cSrcweir maConstraints = _constraints; 268cdf0e10cSrcweir } 269cdf0e10cSrcweir 270cdf0e10cSrcweir sal_Bool SAL_CALL SolverComponent::getMaximize() throw(uno::RuntimeException) 271cdf0e10cSrcweir { 272cdf0e10cSrcweir return mbMaximize; 273cdf0e10cSrcweir } 274cdf0e10cSrcweir 275cdf0e10cSrcweir void SAL_CALL SolverComponent::setMaximize( sal_Bool _maximize ) throw(uno::RuntimeException) 276cdf0e10cSrcweir { 277cdf0e10cSrcweir mbMaximize = _maximize; 278cdf0e10cSrcweir } 279cdf0e10cSrcweir 280cdf0e10cSrcweir // XSolver: get results 281cdf0e10cSrcweir 282cdf0e10cSrcweir sal_Bool SAL_CALL SolverComponent::getSuccess() throw(uno::RuntimeException) 283cdf0e10cSrcweir { 284cdf0e10cSrcweir return mbSuccess; 285cdf0e10cSrcweir } 286cdf0e10cSrcweir 287cdf0e10cSrcweir double SAL_CALL SolverComponent::getResultValue() throw(uno::RuntimeException) 288cdf0e10cSrcweir { 289cdf0e10cSrcweir return mfResultValue; 290cdf0e10cSrcweir } 291cdf0e10cSrcweir 292cdf0e10cSrcweir uno::Sequence<double> SAL_CALL SolverComponent::getSolution() throw(uno::RuntimeException) 293cdf0e10cSrcweir { 294cdf0e10cSrcweir return maSolution; 295cdf0e10cSrcweir } 296cdf0e10cSrcweir 297cdf0e10cSrcweir // ------------------------------------------------------------------------- 298cdf0e10cSrcweir 299cdf0e10cSrcweir void SAL_CALL SolverComponent::solve() throw(uno::RuntimeException) 300cdf0e10cSrcweir { 301cdf0e10cSrcweir uno::Reference<frame::XModel> xModel( mxDoc, uno::UNO_QUERY ); 302cdf0e10cSrcweir if ( !xModel.is() ) 303cdf0e10cSrcweir throw uno::RuntimeException(); 304cdf0e10cSrcweir 305cdf0e10cSrcweir maStatus = OUString(); 306cdf0e10cSrcweir mbSuccess = false; 307cdf0e10cSrcweir 308cdf0e10cSrcweir xModel->lockControllers(); 309cdf0e10cSrcweir 310cdf0e10cSrcweir // collect variables in vector (?) 311cdf0e10cSrcweir 312cdf0e10cSrcweir std::vector<table::CellAddress> aVariableCells; 313cdf0e10cSrcweir for (sal_Int32 nPos=0; nPos<maVariables.getLength(); nPos++) 314cdf0e10cSrcweir aVariableCells.push_back( maVariables[nPos] ); 315cdf0e10cSrcweir size_t nVariables = aVariableCells.size(); 316cdf0e10cSrcweir size_t nVar = 0; 317cdf0e10cSrcweir 318cdf0e10cSrcweir // collect all dependent cells 319cdf0e10cSrcweir 320cdf0e10cSrcweir ScSolverCellHashMap aCellsHash; 321cdf0e10cSrcweir aCellsHash[maObjective].reserve( nVariables + 1 ); // objective function 322cdf0e10cSrcweir 323cdf0e10cSrcweir for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos) 324cdf0e10cSrcweir { 325cdf0e10cSrcweir table::CellAddress aCellAddr = maConstraints[nConstrPos].Left; 326cdf0e10cSrcweir aCellsHash[aCellAddr].reserve( nVariables + 1 ); // constraints: left hand side 327cdf0e10cSrcweir 328cdf0e10cSrcweir if ( maConstraints[nConstrPos].Right >>= aCellAddr ) 329cdf0e10cSrcweir aCellsHash[aCellAddr].reserve( nVariables + 1 ); // constraints: right hand side 330cdf0e10cSrcweir } 331cdf0e10cSrcweir 332cdf0e10cSrcweir // set all variables to zero 333cdf0e10cSrcweir //! store old values? 334cdf0e10cSrcweir //! use old values as initial values? 335cdf0e10cSrcweir std::vector<table::CellAddress>::const_iterator aVarIter; 336cdf0e10cSrcweir for ( aVarIter = aVariableCells.begin(); aVarIter != aVariableCells.end(); ++aVarIter ) 337cdf0e10cSrcweir { 338cdf0e10cSrcweir lcl_SetValue( mxDoc, *aVarIter, 0.0 ); 339cdf0e10cSrcweir } 340cdf0e10cSrcweir 341cdf0e10cSrcweir // read initial values from all dependent cells 342cdf0e10cSrcweir ScSolverCellHashMap::iterator aCellsIter; 343cdf0e10cSrcweir for ( aCellsIter = aCellsHash.begin(); aCellsIter != aCellsHash.end(); ++aCellsIter ) 344cdf0e10cSrcweir { 345cdf0e10cSrcweir double fValue = lcl_GetValue( mxDoc, aCellsIter->first ); 346cdf0e10cSrcweir aCellsIter->second.push_back( fValue ); // store as first element, as-is 347cdf0e10cSrcweir } 348cdf0e10cSrcweir 349cdf0e10cSrcweir // loop through variables 350cdf0e10cSrcweir for ( aVarIter = aVariableCells.begin(); aVarIter != aVariableCells.end(); ++aVarIter ) 351cdf0e10cSrcweir { 352cdf0e10cSrcweir lcl_SetValue( mxDoc, *aVarIter, 1.0 ); // set to 1 to examine influence 353cdf0e10cSrcweir 354cdf0e10cSrcweir // read value change from all dependent cells 355cdf0e10cSrcweir for ( aCellsIter = aCellsHash.begin(); aCellsIter != aCellsHash.end(); ++aCellsIter ) 356cdf0e10cSrcweir { 357cdf0e10cSrcweir double fChanged = lcl_GetValue( mxDoc, aCellsIter->first ); 358cdf0e10cSrcweir double fInitial = aCellsIter->second.front(); 359cdf0e10cSrcweir aCellsIter->second.push_back( fChanged - fInitial ); 360cdf0e10cSrcweir } 361cdf0e10cSrcweir 362cdf0e10cSrcweir lcl_SetValue( mxDoc, *aVarIter, 2.0 ); // minimal test for linearity 363cdf0e10cSrcweir 364cdf0e10cSrcweir for ( aCellsIter = aCellsHash.begin(); aCellsIter != aCellsHash.end(); ++aCellsIter ) 365cdf0e10cSrcweir { 366cdf0e10cSrcweir double fInitial = aCellsIter->second.front(); 367cdf0e10cSrcweir double fCoeff = aCellsIter->second.back(); // last appended: coefficient for this variable 368cdf0e10cSrcweir double fTwo = lcl_GetValue( mxDoc, aCellsIter->first ); 369cdf0e10cSrcweir 370cdf0e10cSrcweir bool bLinear = rtl::math::approxEqual( fTwo, fInitial + 2.0 * fCoeff ) || 371cdf0e10cSrcweir rtl::math::approxEqual( fInitial, fTwo - 2.0 * fCoeff ); 372cdf0e10cSrcweir // second comparison is needed in case fTwo is zero 373cdf0e10cSrcweir if ( !bLinear ) 374cdf0e10cSrcweir maStatus = lcl_GetResourceString( RID_ERROR_NONLINEAR ); 375cdf0e10cSrcweir } 376cdf0e10cSrcweir 377cdf0e10cSrcweir lcl_SetValue( mxDoc, *aVarIter, 0.0 ); // set back to zero for examining next variable 378cdf0e10cSrcweir } 379cdf0e10cSrcweir 380cdf0e10cSrcweir xModel->unlockControllers(); 381cdf0e10cSrcweir 382cdf0e10cSrcweir if ( maStatus.getLength() ) 383cdf0e10cSrcweir return; 384cdf0e10cSrcweir 385cdf0e10cSrcweir // 386*70840c81SAndre Fischer // build parameter arrays for CoinMP 387cdf0e10cSrcweir // 388cdf0e10cSrcweir 389cdf0e10cSrcweir // set objective function 390cdf0e10cSrcweir 391cdf0e10cSrcweir const std::vector<double>& rObjCoeff = aCellsHash[maObjective]; 392*70840c81SAndre Fischer double* pObjectCoeffs = new double[nVariables]; 393cdf0e10cSrcweir for (nVar=0; nVar<nVariables; nVar++) 394*70840c81SAndre Fischer pObjectCoeffs[nVar] = rObjCoeff[nVar+1]; 395*70840c81SAndre Fischer double nObjectConst = rObjCoeff[0]; // constant term of objective 396cdf0e10cSrcweir 397cdf0e10cSrcweir // add rows 398cdf0e10cSrcweir 399*70840c81SAndre Fischer size_t nRows = maConstraints.getLength(); 400*70840c81SAndre Fischer size_t nCompSize = nVariables * nRows; 401*70840c81SAndre Fischer double* pCompMatrix = new double[nCompSize]; // first collect all coefficients, row-wise 402*70840c81SAndre Fischer for (size_t i=0; i<nCompSize; i++) 403*70840c81SAndre Fischer pCompMatrix[i] = 0.0; 404*70840c81SAndre Fischer 405*70840c81SAndre Fischer double* pRHS = new double[nRows]; 406*70840c81SAndre Fischer char* pRowType = new char[nRows]; 407*70840c81SAndre Fischer for (size_t i=0; i<nRows; i++) 408*70840c81SAndre Fischer { 409*70840c81SAndre Fischer pRHS[i] = 0.0; 410*70840c81SAndre Fischer pRowType[i] = 'N'; 411*70840c81SAndre Fischer } 412cdf0e10cSrcweir 413cdf0e10cSrcweir for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos) 414cdf0e10cSrcweir { 415cdf0e10cSrcweir // integer constraints are set later 416cdf0e10cSrcweir sheet::SolverConstraintOperator eOp = maConstraints[nConstrPos].Operator; 417cdf0e10cSrcweir if ( eOp == sheet::SolverConstraintOperator_LESS_EQUAL || 418cdf0e10cSrcweir eOp == sheet::SolverConstraintOperator_GREATER_EQUAL || 419cdf0e10cSrcweir eOp == sheet::SolverConstraintOperator_EQUAL ) 420cdf0e10cSrcweir { 421cdf0e10cSrcweir double fDirectValue = 0.0; 422cdf0e10cSrcweir bool bRightCell = false; 423cdf0e10cSrcweir table::CellAddress aRightAddr; 424cdf0e10cSrcweir const uno::Any& rRightAny = maConstraints[nConstrPos].Right; 425cdf0e10cSrcweir if ( rRightAny >>= aRightAddr ) 426cdf0e10cSrcweir bRightCell = true; // cell specified as right-hand side 427cdf0e10cSrcweir else 428cdf0e10cSrcweir rRightAny >>= fDirectValue; // constant value 429cdf0e10cSrcweir 430cdf0e10cSrcweir table::CellAddress aLeftAddr = maConstraints[nConstrPos].Left; 431cdf0e10cSrcweir 432cdf0e10cSrcweir const std::vector<double>& rLeftCoeff = aCellsHash[aLeftAddr]; 433*70840c81SAndre Fischer double* pValues = &pCompMatrix[nConstrPos * nVariables]; 434cdf0e10cSrcweir for (nVar=0; nVar<nVariables; nVar++) 435*70840c81SAndre Fischer pValues[nVar] = rLeftCoeff[nVar+1]; 436cdf0e10cSrcweir 437cdf0e10cSrcweir // if left hand cell has a constant term, put into rhs value 438cdf0e10cSrcweir double fRightValue = -rLeftCoeff[0]; 439cdf0e10cSrcweir 440cdf0e10cSrcweir if ( bRightCell ) 441cdf0e10cSrcweir { 442cdf0e10cSrcweir const std::vector<double>& rRightCoeff = aCellsHash[aRightAddr]; 443cdf0e10cSrcweir // modify pValues with rhs coefficients 444cdf0e10cSrcweir for (nVar=0; nVar<nVariables; nVar++) 445*70840c81SAndre Fischer pValues[nVar] -= rRightCoeff[nVar+1]; 446cdf0e10cSrcweir 447cdf0e10cSrcweir fRightValue += rRightCoeff[0]; // constant term 448cdf0e10cSrcweir } 449cdf0e10cSrcweir else 450cdf0e10cSrcweir fRightValue += fDirectValue; 451cdf0e10cSrcweir 452cdf0e10cSrcweir switch ( eOp ) 453cdf0e10cSrcweir { 454*70840c81SAndre Fischer case sheet::SolverConstraintOperator_LESS_EQUAL: pRowType[nConstrPos] = 'L'; break; 455*70840c81SAndre Fischer case sheet::SolverConstraintOperator_GREATER_EQUAL: pRowType[nConstrPos] = 'G'; break; 456*70840c81SAndre Fischer case sheet::SolverConstraintOperator_EQUAL: pRowType[nConstrPos] = 'E'; break; 457cdf0e10cSrcweir default: 458cdf0e10cSrcweir OSL_ENSURE( false, "unexpected enum type" ); 459cdf0e10cSrcweir } 460*70840c81SAndre Fischer pRHS[nConstrPos] = fRightValue; 461cdf0e10cSrcweir } 462cdf0e10cSrcweir } 463cdf0e10cSrcweir 464*70840c81SAndre Fischer // Find non-zero coefficients, column-wise 465*70840c81SAndre Fischer 466*70840c81SAndre Fischer int* pMatrixBegin = new int[nVariables+1]; 467*70840c81SAndre Fischer int* pMatrixCount = new int[nVariables]; 468*70840c81SAndre Fischer double* pMatrix = new double[nCompSize]; // not always completely used 469*70840c81SAndre Fischer int* pMatrixIndex = new int[nCompSize]; 470*70840c81SAndre Fischer int nMatrixPos = 0; 471*70840c81SAndre Fischer for (nVar=0; nVar<nVariables; nVar++) 472*70840c81SAndre Fischer { 473*70840c81SAndre Fischer int nBegin = nMatrixPos; 474*70840c81SAndre Fischer for (size_t nRow=0; nRow<nRows; nRow++) 475*70840c81SAndre Fischer { 476*70840c81SAndre Fischer double fCoeff = pCompMatrix[ nRow * nVariables + nVar ]; // row-wise 477*70840c81SAndre Fischer if ( fCoeff != 0.0 ) 478*70840c81SAndre Fischer { 479*70840c81SAndre Fischer pMatrix[nMatrixPos] = fCoeff; 480*70840c81SAndre Fischer pMatrixIndex[nMatrixPos] = nRow; 481*70840c81SAndre Fischer ++nMatrixPos; 482*70840c81SAndre Fischer } 483*70840c81SAndre Fischer } 484*70840c81SAndre Fischer pMatrixBegin[nVar] = nBegin; 485*70840c81SAndre Fischer pMatrixCount[nVar] = nMatrixPos - nBegin; 486*70840c81SAndre Fischer } 487*70840c81SAndre Fischer pMatrixBegin[nVariables] = nMatrixPos; 488*70840c81SAndre Fischer delete[] pCompMatrix; 489*70840c81SAndre Fischer pCompMatrix = NULL; 490cdf0e10cSrcweir 491cdf0e10cSrcweir // apply settings to all variables 492cdf0e10cSrcweir 493*70840c81SAndre Fischer double* pLowerBounds = new double[nVariables]; 494*70840c81SAndre Fischer double* pUpperBounds = new double[nVariables]; 495cdf0e10cSrcweir for (nVar=0; nVar<nVariables; nVar++) 496cdf0e10cSrcweir { 497*70840c81SAndre Fischer pLowerBounds[nVar] = mbNonNegative ? 0.0 : -DBL_MAX; 498*70840c81SAndre Fischer pUpperBounds[nVar] = DBL_MAX; 499*70840c81SAndre Fischer 500*70840c81SAndre Fischer // bounds could possibly be further restricted from single-cell constraints 501cdf0e10cSrcweir } 502cdf0e10cSrcweir 503*70840c81SAndre Fischer char* pColType = new char[nVariables]; 504*70840c81SAndre Fischer for (nVar=0; nVar<nVariables; nVar++) 505*70840c81SAndre Fischer pColType[nVar] = mbInteger ? 'I' : 'C'; 506*70840c81SAndre Fischer 507cdf0e10cSrcweir // apply single-var integer constraints 508cdf0e10cSrcweir 509cdf0e10cSrcweir for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos) 510cdf0e10cSrcweir { 511cdf0e10cSrcweir sheet::SolverConstraintOperator eOp = maConstraints[nConstrPos].Operator; 512cdf0e10cSrcweir if ( eOp == sheet::SolverConstraintOperator_INTEGER || 513cdf0e10cSrcweir eOp == sheet::SolverConstraintOperator_BINARY ) 514cdf0e10cSrcweir { 515cdf0e10cSrcweir table::CellAddress aLeftAddr = maConstraints[nConstrPos].Left; 516cdf0e10cSrcweir // find variable index for cell 517cdf0e10cSrcweir for (nVar=0; nVar<nVariables; nVar++) 518cdf0e10cSrcweir if ( AddressEqual( aVariableCells[nVar], aLeftAddr ) ) 519cdf0e10cSrcweir { 520cdf0e10cSrcweir if ( eOp == sheet::SolverConstraintOperator_INTEGER ) 521*70840c81SAndre Fischer pColType[nVar] = 'I'; 522cdf0e10cSrcweir else 523*70840c81SAndre Fischer { 524*70840c81SAndre Fischer pColType[nVar] = 'B'; 525*70840c81SAndre Fischer pLowerBounds[nVar] = 0.0; 526*70840c81SAndre Fischer pUpperBounds[nVar] = 1.0; 527*70840c81SAndre Fischer } 528cdf0e10cSrcweir } 529cdf0e10cSrcweir } 530cdf0e10cSrcweir } 531cdf0e10cSrcweir 532*70840c81SAndre Fischer int nObjectSense = mbMaximize ? SOLV_OBJSENS_MAX : SOLV_OBJSENS_MIN; 533cdf0e10cSrcweir 534*70840c81SAndre Fischer HPROB hProb = CoinCreateProblem(""); 535*70840c81SAndre Fischer int nResult = CoinLoadProblem( hProb, nVariables, nRows, nMatrixPos, 0, 536*70840c81SAndre Fischer nObjectSense, nObjectConst, pObjectCoeffs, 537*70840c81SAndre Fischer pLowerBounds, pUpperBounds, pRowType, pRHS, NULL, 538*70840c81SAndre Fischer pMatrixBegin, pMatrixCount, pMatrixIndex, pMatrix, 539*70840c81SAndre Fischer NULL, NULL, NULL ); 540*70840c81SAndre Fischer nResult = CoinLoadInteger( hProb, pColType ); 541cdf0e10cSrcweir 542*70840c81SAndre Fischer delete[] pColType; 543*70840c81SAndre Fischer delete[] pMatrixIndex; 544*70840c81SAndre Fischer delete[] pMatrix; 545*70840c81SAndre Fischer delete[] pMatrixCount; 546*70840c81SAndre Fischer delete[] pMatrixBegin; 547*70840c81SAndre Fischer delete[] pUpperBounds; 548*70840c81SAndre Fischer delete[] pLowerBounds; 549*70840c81SAndre Fischer delete[] pRowType; 550*70840c81SAndre Fischer delete[] pRHS; 551*70840c81SAndre Fischer delete[] pObjectCoeffs; 552*70840c81SAndre Fischer 553*70840c81SAndre Fischer CoinSetRealOption( hProb, COIN_REAL_MAXSECONDS, mnTimeout ); 554*70840c81SAndre Fischer CoinSetRealOption( hProb, COIN_REAL_MIPMAXSEC, mnTimeout ); 555*70840c81SAndre Fischer 556*70840c81SAndre Fischer // TODO: handle (or remove) settings: epsilon, B&B depth 557cdf0e10cSrcweir 558cdf0e10cSrcweir // solve model 559cdf0e10cSrcweir 560*70840c81SAndre Fischer nResult = CoinCheckProblem( hProb ); 561*70840c81SAndre Fischer nResult = CoinOptimizeProblem( hProb, 0 ); 562cdf0e10cSrcweir 563*70840c81SAndre Fischer mbSuccess = ( nResult == SOLV_CALL_SUCCESS ); 564cdf0e10cSrcweir if ( mbSuccess ) 565cdf0e10cSrcweir { 566cdf0e10cSrcweir // get solution 567cdf0e10cSrcweir 568cdf0e10cSrcweir maSolution.realloc( nVariables ); 569*70840c81SAndre Fischer CoinGetSolutionValues( hProb, maSolution.getArray(), NULL, NULL, NULL ); 570*70840c81SAndre Fischer mfResultValue = CoinGetObjectValue( hProb ); 571cdf0e10cSrcweir } 572*70840c81SAndre Fischer else 573*70840c81SAndre Fischer { 574*70840c81SAndre Fischer int nSolutionStatus = CoinGetSolutionStatus( hProb ); 575*70840c81SAndre Fischer if ( nSolutionStatus == 1 ) 576cdf0e10cSrcweir maStatus = lcl_GetResourceString( RID_ERROR_INFEASIBLE ); 577*70840c81SAndre Fischer else if ( nSolutionStatus == 2 ) 578cdf0e10cSrcweir maStatus = lcl_GetResourceString( RID_ERROR_UNBOUNDED ); 579*70840c81SAndre Fischer // TODO: detect timeout condition and report as RID_ERROR_TIMEOUT 580*70840c81SAndre Fischer // (currently reported as infeasible) 581*70840c81SAndre Fischer } 582cdf0e10cSrcweir 583*70840c81SAndre Fischer CoinUnloadProblem( hProb ); 584cdf0e10cSrcweir } 585cdf0e10cSrcweir 586cdf0e10cSrcweir // ------------------------------------------------------------------------- 587cdf0e10cSrcweir 588cdf0e10cSrcweir // XServiceInfo 589cdf0e10cSrcweir 590cdf0e10cSrcweir uno::Sequence< OUString > SolverComponent_getSupportedServiceNames() 591cdf0e10cSrcweir { 592cdf0e10cSrcweir uno::Sequence< OUString > aServiceNames( 1 ); 593cdf0e10cSrcweir aServiceNames[ 0 ] = OUString::createFromAscii( "com.sun.star.sheet.Solver" ); 594cdf0e10cSrcweir return aServiceNames; 595cdf0e10cSrcweir } 596cdf0e10cSrcweir 597cdf0e10cSrcweir OUString SolverComponent_getImplementationName() 598cdf0e10cSrcweir { 599cdf0e10cSrcweir return OUString::createFromAscii( "com.sun.star.comp.Calc.Solver" ); 600cdf0e10cSrcweir } 601cdf0e10cSrcweir 602cdf0e10cSrcweir OUString SAL_CALL SolverComponent::getImplementationName() throw(uno::RuntimeException) 603cdf0e10cSrcweir { 604cdf0e10cSrcweir return SolverComponent_getImplementationName(); 605cdf0e10cSrcweir } 606cdf0e10cSrcweir 607cdf0e10cSrcweir sal_Bool SAL_CALL SolverComponent::supportsService( const OUString& rServiceName ) throw(uno::RuntimeException) 608cdf0e10cSrcweir { 609cdf0e10cSrcweir const uno::Sequence< OUString > aServices = SolverComponent_getSupportedServiceNames(); 610cdf0e10cSrcweir const OUString* pArray = aServices.getConstArray(); 611cdf0e10cSrcweir const OUString* pArrayEnd = pArray + aServices.getLength(); 612cdf0e10cSrcweir return ::std::find( pArray, pArrayEnd, rServiceName ) != pArrayEnd; 613cdf0e10cSrcweir } 614cdf0e10cSrcweir 615cdf0e10cSrcweir uno::Sequence<OUString> SAL_CALL SolverComponent::getSupportedServiceNames() throw(uno::RuntimeException) 616cdf0e10cSrcweir { 617cdf0e10cSrcweir return SolverComponent_getSupportedServiceNames(); 618cdf0e10cSrcweir } 619cdf0e10cSrcweir 620cdf0e10cSrcweir uno::Reference<uno::XInterface> SolverComponent_createInstance( const uno::Reference<uno::XComponentContext>& rSMgr ) 621cdf0e10cSrcweir throw(uno::Exception) 622cdf0e10cSrcweir { 623cdf0e10cSrcweir return (cppu::OWeakObject*) new SolverComponent( rSMgr ); 624cdf0e10cSrcweir } 625cdf0e10cSrcweir 626cdf0e10cSrcweir // ------------------------------------------------------------------------- 627cdf0e10cSrcweir 628cdf0e10cSrcweir extern "C" 629cdf0e10cSrcweir { 630cdf0e10cSrcweir SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment( 631cdf0e10cSrcweir const sal_Char ** ppEnvTypeName, uno_Environment ** ) 632cdf0e10cSrcweir { 633cdf0e10cSrcweir *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; 634cdf0e10cSrcweir } 635cdf0e10cSrcweir 636cdf0e10cSrcweir // ------------------------------------------------------------------------- 637cdf0e10cSrcweir 638cdf0e10cSrcweir SAL_DLLPUBLIC_EXPORT void* SAL_CALL component_getFactory( const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ ) 639cdf0e10cSrcweir { 640cdf0e10cSrcweir OUString aImplName( OUString::createFromAscii( pImplName ) ); 641cdf0e10cSrcweir void* pRet = 0; 642cdf0e10cSrcweir 643cdf0e10cSrcweir if( pServiceManager ) 644cdf0e10cSrcweir { 645cdf0e10cSrcweir uno::Reference< lang::XSingleComponentFactory > xFactory; 646cdf0e10cSrcweir if( aImplName.equals( SolverComponent_getImplementationName() ) ) 647cdf0e10cSrcweir xFactory = cppu::createSingleComponentFactory( 648cdf0e10cSrcweir SolverComponent_createInstance, 649cdf0e10cSrcweir OUString::createFromAscii( pImplName ), 650cdf0e10cSrcweir SolverComponent_getSupportedServiceNames() ); 651cdf0e10cSrcweir 652cdf0e10cSrcweir if( xFactory.is() ) 653cdf0e10cSrcweir { 654cdf0e10cSrcweir xFactory->acquire(); 655cdf0e10cSrcweir pRet = xFactory.get(); 656cdf0e10cSrcweir } 657cdf0e10cSrcweir } 658cdf0e10cSrcweir return pRet; 659cdf0e10cSrcweir } 660cdf0e10cSrcweir } 661cdf0e10cSrcweir 662