LibreOffice Module sc (master) 1
SolverSettings.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 */
10
11#include <global.hxx>
12#include <table.hxx>
13#include <docsh.hxx>
14#include <solverutil.hxx>
16#include <SolverSettings.hxx>
17
18namespace sc
19{
21 : m_rTable(rTable)
22 , m_rDoc(m_rTable.GetDoc())
23 , m_pDocShell(dynamic_cast<ScDocShell*>(m_rDoc.GetDocumentShell()))
24{
25 // Get the named range manager for this tab
26 std::map<OUString, ScRangeName*> rRangeMap;
27 m_rDoc.GetRangeNameMap(rRangeMap);
28 m_pRangeName = rRangeMap.find(m_rTable.GetName())->second;
29
30 Initialize();
31}
32
34{
35 // Assign default values for the solver parameters
37
38 // Read the parameter values in the sheet
42
43 // Read the objective type
44 OUString sObjType;
45 if (ReadParamValue(SP_OBJ_TYPE, sObjType))
46 {
47 switch (sObjType.toInt32())
48 {
49 case 1:
51 break;
52 case 2:
54 break;
55 case 3:
57 break;
58 default:
60 }
61 }
62
63 // Read all constraints in the tab
65
66 // Read the solver engine being used
67 ReadEngine();
68
69 // Read engine options
76}
77
78// Returns the current value of the parameter in the object as a string
80{
81 switch (eParam)
82 {
83 case SP_OBJ_CELL:
84 return m_sObjCell;
85 break;
86 case SP_OBJ_TYPE:
87 return OUString::number(m_eObjType);
88 break;
89 case SP_OBJ_VAL:
90 return m_sObjVal;
91 break;
92 case SP_VAR_CELLS:
93 return m_sVariableCells;
94 break;
95 case SP_CONSTR_COUNT:
96 return OUString::number(m_aConstraints.size());
97 break;
98 case SP_LO_ENGINE:
99 return m_sLOEngineName;
100 break;
101 case SP_MS_ENGINE:
102 return m_sMSEngineId;
103 break;
104 case SP_INTEGER:
105 return m_sInteger;
106 break;
107 case SP_NON_NEGATIVE:
108 return m_sNonNegative;
109 break;
110 case SP_EPSILON_LEVEL:
111 return m_sEpsilonLevel;
112 break;
113 case SP_LIMIT_BBDEPTH:
114 return m_sLimitBBDepth;
115 break;
116 case SP_TIMEOUT:
117 return m_sTimeout;
118 break;
119 case SP_ALGORITHM:
120 return m_sAlgorithm;
121 break;
122 default:
123 return "";
124 }
125}
126
127// Sets the value of a single solver parameter in the object
129{
130 switch (eParam)
131 {
132 case SP_OBJ_CELL:
133 m_sObjCell = sValue;
134 break;
135 case SP_OBJ_TYPE:
136 {
137 sal_Int32 nObjType = sValue.toInt32();
138 switch (nObjType)
139 {
140 case OT_MAXIMIZE:
142 break;
143 case OT_MINIMIZE:
145 break;
146 case OT_VALUE:
148 break;
149 default:
151 break;
152 }
153 break;
154 }
155 case SP_OBJ_VAL:
156 m_sObjVal = sValue;
157 break;
158 case SP_VAR_CELLS:
159 m_sVariableCells = sValue;
160 break;
161 case SP_LO_ENGINE:
162 m_sLOEngineName = sValue;
163 break;
164 case SP_INTEGER:
165 {
166 if (sValue == "0" || sValue == "1")
167 m_sInteger = sValue;
168 }
169 break;
170 case SP_NON_NEGATIVE:
171 {
172 if (sValue == "1" || sValue == "2")
173 m_sNonNegative = sValue;
174 }
175 break;
176 case SP_EPSILON_LEVEL:
177 m_sEpsilonLevel = sValue;
178 break;
179 case SP_LIMIT_BBDEPTH:
180 m_sLimitBBDepth = sValue;
181 break;
182 case SP_TIMEOUT:
183 m_sTimeout = sValue;
184 break;
185 case SP_ALGORITHM:
186 {
187 if (sValue == "1" || sValue == "2" || sValue == "3")
188 m_sAlgorithm = sValue;
189 }
190 break;
191 default:
192 break;
193 }
194}
195
197
198// Loads all constraints in the tab
200{
201 // Condition indices start at 1 for MS compatibility
202 // The number of "lhs", "rel" and "rhs" entries will always be the same
203 tools::Long nConstraint = 1;
204 m_aConstraints.clear();
205 OUString sValue;
206
207 while (ReadConstraintPart(CP_LEFT_HAND_SIDE, nConstraint, sValue))
208 {
209 // Left hand side
210 ModelConstraint aNewCondition;
211 aNewCondition.aLeftStr = sValue;
212
213 // Right hand side
214 if (ReadConstraintPart(CP_RIGHT_HAND_SIDE, nConstraint, sValue))
215 aNewCondition.aRightStr = sValue;
216
217 // Relation (operator)
218 if (ReadConstraintPart(CP_OPERATOR, nConstraint, sValue))
219 aNewCondition.nOperator = static_cast<sc::ConstraintOperator>(sValue.toInt32());
220
221 m_aConstraints.push_back(aNewCondition);
222 nConstraint++;
223 }
224}
225
226// Writes all constraints to the file
228{
229 // Condition indices start at 1 for MS compatibility
230 tools::Long nConstraint = 1;
231
232 for (auto& aConstraint : m_aConstraints)
233 {
234 // Left hand side
235 WriteConstraintPart(CP_LEFT_HAND_SIDE, nConstraint, aConstraint.aLeftStr);
236 // Relation (operator)
237 WriteConstraintPart(CP_OPERATOR, nConstraint, OUString::number(aConstraint.nOperator));
238 // Right hand side
239 WriteConstraintPart(CP_RIGHT_HAND_SIDE, nConstraint, aConstraint.aRightStr);
240 nConstraint++;
241 }
242}
243
244// Write a single constraint part to the file
246{
247 // Empty named ranges cannot be written to the file (this corrupts MS files)
248 if (sValue.isEmpty())
249 return;
250
251 OUString sRange = m_aConstraintParts[ePart] + OUString::number(nIndex);
252 ScRangeData* pNewEntry = new ScRangeData(m_rDoc, sRange, sValue);
253 m_pRangeName->insert(pNewEntry);
254}
255
256// Reads a single constraint part from its associated named range; returns false if the named
257// range does not exist in the file
259{
260 OUString sRange = m_aConstraintParts[ePart] + OUString::number(nIndex);
261 ScRangeData* pRangeData
263 if (pRangeData)
264 {
265 rValue = pRangeData->GetSymbol();
266 return true;
267 }
268 return false;
269}
270
271/* Reads the engine name parameter as informed in the file in the format used in LO.
272 * If only a MS engine is informed, then it is converted to a LO-equivalent engine
273 */
275{
277 {
278 // If no engine is defined, use CoinMP solver as default
279 m_sLOEngineName = "com.sun.star.comp.Calc.CoinMPSolver";
280 }
281
283 {
284 // Find equivalent MS engine code
286 }
287}
288
289// Write solver LO and MS-equivalent engine names
291{
293 // Find equivalent MS engine code
295 {
298 }
299}
300
301// Assigns a new constraints vector
302void SolverSettings::SetConstraints(std::vector<ModelConstraint> aConstraints)
303{
304 m_aConstraints = std::move(aConstraints);
305}
306
307// Saves all solver settings into the file
309{
310 // Before saving, remove all existing named ranges related to the solver
312
314 WriteParamValue(SP_OBJ_TYPE, OUString::number(m_eObjType));
317
319 WriteEngine();
320
321 sal_Int32 nConstrCount = m_aConstraints.size();
322 WriteParamValue(SP_CONSTR_COUNT, OUString::number(nConstrCount));
323
330
331 if (m_pDocShell)
333}
334
335/* Reads the current value of the parameter in the named range into rValue
336 * If the value does not exist, the rValue is left unchanged
337 * This is private because it is only used during initialization
338 * Returns true if the value exits; returns false otherwise
339 */
340bool SolverSettings::ReadParamValue(SolverParameter eParam, OUString& rValue, bool bRemoveQuotes)
341{
342 OUString sRange = m_mNamedRanges.find(eParam)->second;
343 ScRangeData* pRangeData
345 if (pRangeData)
346 {
347 rValue = pRangeData->GetSymbol();
348 if (bRemoveQuotes)
349 ScGlobal::EraseQuotes(rValue, '"');
350 return true;
351 }
352 return false;
353}
354
355/* Writes a parameter value to the file as a named range.
356 * Argument bQuoted indicates whether the value should be enclosed with quotes or not (used
357 * for string expressions that must be enclosed with quotes)
358 */
359void SolverSettings::WriteParamValue(SolverParameter eParam, OUString sValue, bool bQuoted)
360{
361 // Empty parameters cannot be written to the file (this corrupts MS files)
362 // There's no problem if the parameter is missing both for LO and MS
363 if (sValue.isEmpty())
364 return;
365
366 if (bQuoted)
367 ScGlobal::AddQuotes(sValue, '"');
368
369 OUString sRange = m_mNamedRanges.find(eParam)->second;
370 ScRangeData* pNewEntry = new ScRangeData(m_rDoc, sRange, sValue);
371 m_pRangeName->insert(pNewEntry);
372}
373
374void SolverSettings::GetEngineOptions(css::uno::Sequence<css::beans::PropertyValue>& aOptions)
375{
376 sal_Int32 nOptionsSize = aOptions.getLength();
377 auto pParamValues = aOptions.getArray();
378
379 for (auto i = 0; i < nOptionsSize; i++)
380 {
381 css::beans::PropertyValue aProp = aOptions[i];
382 OUString sLOParamName = aProp.Name;
383 // Only try to get the parameter value if it is an expected parameter name
384 if (SolverParamNames.count(sLOParamName))
385 {
386 TParamInfo aParamInfo;
387 aParamInfo = SolverParamNames.find(sLOParamName)->second;
388 SolverParameter eParamId = std::get<SolverParameter>(aParamInfo[0]);
389 OUString sParamType = std::get<OUString>(aParamInfo[2]);
390 OUString sParamValue = GetParameter(eParamId);
391 if (sParamType == "int")
392 {
393 css::uno::Any nValue(sParamValue.toInt32());
394 pParamValues[i] = css::beans::PropertyValue(sLOParamName, -1, nValue,
395 css::beans::PropertyState_DIRECT_VALUE);
396 }
397 if (sParamType == "bool")
398 {
399 // The parameter NonNegative is a special case for MS compatibility
400 // It uses "1" for "true" and "2" for "false"
401 bool bTmpValue;
402 if (sLOParamName == "NonNegative")
403 bTmpValue = sParamValue == "1" ? true : false;
404 else
405 bTmpValue = sParamValue.toBoolean();
406
407 css::uno::Any bValue(bTmpValue);
408 pParamValues[i] = css::beans::PropertyValue(sLOParamName, -1, bValue,
409 css::beans::PropertyState_DIRECT_VALUE);
410 }
411 }
412 }
413}
414
415// Updates the object members related to solver engine options using aOptions info
416void SolverSettings::SetEngineOptions(css::uno::Sequence<css::beans::PropertyValue>& aOptions)
417{
418 sal_Int32 nOptionsSize = aOptions.getLength();
419
420 for (auto i = 0; i < nOptionsSize; i++)
421 {
422 css::beans::PropertyValue aProp = aOptions[i];
423 OUString sLOParamName = aProp.Name;
424 // Only try to set the parameter value if it is an expected parameter name
425 if (SolverParamNames.count(sLOParamName))
426 {
427 TParamInfo aParamInfo;
428 aParamInfo = SolverParamNames.find(sLOParamName)->second;
429 SolverParameter eParamId = std::get<SolverParameter>(aParamInfo[0]);
430 OUString sParamType = std::get<OUString>(aParamInfo[2]);
431 if (sParamType == "int")
432 {
433 sal_Int32 nValue = 0;
434 aProp.Value >>= nValue;
435 SetParameter(eParamId, OUString::number(nValue));
436 }
437 if (sParamType == "bool")
438 {
439 bool bValue = false;
440 aProp.Value >>= bValue;
441 if (sLOParamName == "NonNegative")
442 {
443 // The parameter NonNegative is a special case for MS compatibility
444 // It uses "1" for "true" and "2" for "false"
445 if (bValue)
446 SetParameter(eParamId, OUString::number(1));
447 else
448 SetParameter(eParamId, OUString::number(2));
449 }
450 else
451 {
452 SetParameter(eParamId, OUString::number(sal_Int32(bValue)));
453 }
454 }
455 }
456 }
457}
458
459// Deletes all named ranges in the current tab that are related to the solver (i.e. start with "solver_")
461{
462 std::vector<ScRangeData*> aItemsToErase;
463
464 // Indices in m_pRangeName start at 1
465 for (size_t i = 1; i <= m_pRangeName->size(); ++i)
466 {
468 if (pData && pData->GetName().startsWith("solver_"))
469 aItemsToErase.push_back(pData);
470 }
471
472 for (auto pItem : aItemsToErase)
473 m_pRangeName->erase(*pItem);
474}
475
476/* Sets all solver parameters to their default values and clear all constraints.
477 * This method only resets the object properties, but does not save changes to the
478 * document. To save changes, call SaveSolverSettings().
479 */
481{
482 m_sObjCell = "";
484 m_sObjVal = "";
485 m_sVariableCells = "";
486 m_sMSEngineId = "1";
487
488 // The default solver engine is the first implementation available
489 css::uno::Sequence<OUString> aEngineNames;
490 css::uno::Sequence<OUString> aDescriptions;
491 ScSolverUtil::GetImplementations(aEngineNames, aDescriptions);
492 m_sLOEngineName = aEngineNames[0];
493
494 // Default engine options
496
497 // Default solver engine options
499
500 // Clear all constraints
501 m_aConstraints.clear();
502}
503
504} // namespace sc
void SetDocumentModified()
Definition: docsh.cxx:2982
SC_DLLPUBLIC void GetRangeNameMap(std::map< OUString, ScRangeName * > &rRangeName)
Definition: documen3.cxx:149
static SC_DLLPUBLIC void EraseQuotes(OUString &rString, sal_Unicode cQuote, bool bUnescapeEmbedded=true)
Erases the character cQuote from rString, if it exists at beginning AND end.
Definition: global.cxx:733
static SC_DLLPUBLIC void AddQuotes(OUString &rString, sal_Unicode cQuote, bool bEscapeEmbedded=true)
Inserts the character cQuote at beginning and end of rString.
Definition: global.cxx:720
static SC_DLLPUBLIC const CharClass & getCharClass()
Definition: global.cxx:1064
SC_DLLPUBLIC OUString GetSymbol(const formula::FormulaGrammar::Grammar eGrammar=formula::FormulaGrammar::GRAM_DEFAULT) const
Definition: rangenam.cxx:244
SC_DLLPUBLIC ScRangeData * findByIndex(sal_uInt16 i) const
Definition: rangenam.cxx:716
SC_DLLPUBLIC size_t size() const
Definition: rangenam.hxx:247
SC_DLLPUBLIC ScRangeData * findByUpperName(const OUString &rName)
Definition: rangenam.cxx:704
void erase(const ScRangeData &r)
Definition: rangenam.cxx:846
SC_DLLPUBLIC bool insert(ScRangeData *p, bool bReuseFreeIndex=true)
Insert object into set.
Definition: rangenam.cxx:802
static void GetImplementations(css::uno::Sequence< OUString > &rImplNames, css::uno::Sequence< OUString > &rDescriptions)
Definition: solverutil.cxx:39
static css::uno::Sequence< css::beans::PropertyValue > GetDefaults(std::u16string_view rImplName)
Definition: solverutil.cxx:136
const OUString & GetName() const
Definition: table.hxx:397
SC_DLLPUBLIC void GetEngineOptions(css::uno::Sequence< css::beans::PropertyValue > &aOptions)
bool ReadConstraintPart(ConstraintPart ePart, tools::Long nIndex, OUString &rValue)
std::map< OUString, TParamInfo > SolverParamNames
std::vector< OUString > m_aConstraintParts
ScRangeName * m_pRangeName
SolverSettings(ScTable &pTable)
css::uno::Sequence< css::beans::PropertyValue > m_aEngineOptions
std::map< OUString, OUString > SolverNamesToExcelEngines
SC_DLLPUBLIC OUString GetParameter(SolverParameter eParam)
SC_DLLPUBLIC void ResetToDefaults()
std::map< SolverParameter, OUString > m_mNamedRanges
SC_DLLPUBLIC void SetObjectiveType(ObjectiveType eType)
SC_DLLPUBLIC void SetConstraints(std::vector< ModelConstraint > aConstraints)
void WriteConstraintPart(ConstraintPart ePart, tools::Long nIndex, OUString sValue)
bool ReadParamValue(SolverParameter eParam, OUString &rValue, bool bRemoveQuotes=false)
SC_DLLPUBLIC void SetEngineOptions(css::uno::Sequence< css::beans::PropertyValue > &aOptions)
ScDocShell * m_pDocShell
ObjectiveType m_eObjType
std::vector< std::variant< OUString, SolverParameter > > TParamInfo
SC_DLLPUBLIC void SetParameter(SolverParameter eParam, OUString sValue)
SC_DLLPUBLIC void SaveSolverSettings()
void WriteParamValue(SolverParameter eParam, OUString sValue, bool bQuoted=false)
std::vector< ModelConstraint > m_aConstraints
SwDoc & m_rDoc
DocumentType eType
sal_Int16 nValue
sal_Int32 nIndex
std::unique_ptr< sal_Int32[]> pData
int i
CAUTION! The following defines must be in the same namespace as the respective type.
Definition: broadcast.cxx:15
SolverParameter
@ SP_OBJ_VAL
@ SP_MS_ENGINE
@ SP_OBJ_CELL
@ SP_CONSTR_COUNT
@ SP_TIMEOUT
@ SP_OBJ_TYPE
@ SP_LO_ENGINE
@ SP_EPSILON_LEVEL
@ SP_LIMIT_BBDEPTH
@ SP_VAR_CELLS
@ SP_ALGORITHM
@ SP_INTEGER
@ SP_NON_NEGATIVE
@ OT_VALUE
@ OT_MAXIMIZE
@ OT_MINIMIZE
ConstraintOperator
ConstraintPart
@ CP_OPERATOR
@ CP_LEFT_HAND_SIDE
@ CP_RIGHT_HAND_SIDE
long Long
ConstraintOperator nOperator
ITableControl & m_rTable