1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 * This file is part of the LibreOffice project.
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/.
12 #include <compiler.hxx>
15 #include <rtl/math.hxx>
16 #include <o3tl/string_view.hxx>
17 #include <solverutil.hxx>
18 #include <unotools/charclass.hxx>
19 #include <SolverSettings.hxx>
23 SolverSettings::SolverSettings(ScTable
& rTable
)
25 , m_rDoc(m_rTable
.GetDoc())
26 , m_pDocShell(m_rDoc
.GetDocumentShell())
28 // Get the named range manager for this tab
29 std::map
<OUString
, ScRangeName
*> rRangeMap
;
30 m_rDoc
.GetRangeNameMap(rRangeMap
);
31 m_pRangeName
= rRangeMap
.find(m_rTable
.GetName())->second
;
36 void SolverSettings::Initialize()
38 // Assign default values for the solver parameters
41 // Read the parameter values in the sheet
42 ReadParamValue(SP_OBJ_CELL
, m_sObjCell
);
43 ReadParamValue(SP_OBJ_VAL
, m_sObjVal
);
44 ReadParamValue(SP_VAR_CELLS
, m_sVariableCells
);
46 // Read the objective type
48 if (ReadParamValue(SP_OBJ_TYPE
, sObjType
))
50 switch (sObjType
.toInt32())
53 m_eObjType
= ObjectiveType::OT_MAXIMIZE
;
56 m_eObjType
= ObjectiveType::OT_MINIMIZE
;
59 m_eObjType
= ObjectiveType::OT_VALUE
;
62 m_eObjType
= ObjectiveType::OT_MAXIMIZE
;
66 // Read all constraints in the tab
69 // Read the solver engine being used
72 // Read engine options
73 ReadParamValue(SP_INTEGER
, m_sInteger
);
74 ReadParamValue(SP_NON_NEGATIVE
, m_sNonNegative
);
75 ReadParamValue(SP_EPSILON_LEVEL
, m_sEpsilonLevel
);
76 ReadParamValue(SP_LIMIT_BBDEPTH
, m_sLimitBBDepth
);
77 ReadParamValue(SP_TIMEOUT
, m_sTimeout
);
78 ReadParamValue(SP_ALGORITHM
, m_sAlgorithm
);
79 // Engine options common for DEPS and SCO
80 ReadParamValue(SP_SWARM_SIZE
, m_sSwarmSize
);
81 ReadParamValue(SP_LEARNING_CYCLES
, m_sLearningCycles
);
82 ReadParamValue(SP_GUESS_VARIABLE_RANGE
, m_sGuessVariableRange
);
83 ReadDoubleParamValue(SP_VARIABLE_RANGE_THRESHOLD
, m_sVariableRangeThreshold
);
84 ReadParamValue(SP_ACR_COMPARATOR
, m_sUseACRComparator
);
85 ReadParamValue(SP_RND_STARTING_POINT
, m_sUseRandomStartingPoint
);
86 ReadParamValue(SP_STRONGER_PRNG
, m_sUseStrongerPRNG
);
87 ReadParamValue(SP_STAGNATION_LIMIT
, m_sStagnationLimit
);
88 ReadDoubleParamValue(SP_STAGNATION_TOLERANCE
, m_sTolerance
);
89 ReadParamValue(SP_ENHANCED_STATUS
, m_sEnhancedSolverStatus
);
91 ReadDoubleParamValue(SP_AGENT_SWITCH_RATE
, m_sAgentSwitchRate
);
92 ReadDoubleParamValue(SP_SCALING_MIN
, m_sScalingFactorMin
);
93 ReadDoubleParamValue(SP_SCALING_MAX
, m_sScalingFactorMax
);
94 ReadDoubleParamValue(SP_CROSSOVER_PROB
, m_sCrossoverProbability
);
95 ReadDoubleParamValue(SP_COGNITIVE_CONST
, m_sCognitiveConstant
);
96 ReadDoubleParamValue(SP_SOCIAL_CONST
, m_sSocialConstant
);
97 ReadDoubleParamValue(SP_CONSTRICTION_COEFF
, m_sConstrictionCoeff
);
98 ReadDoubleParamValue(SP_MUTATION_PROB
, m_sMutationProbability
);
100 ReadParamValue(SP_LIBRARY_SIZE
, m_sLibrarySize
);
103 // Returns the current value of the parameter in the object as a string
104 OUString
SolverSettings::GetParameter(SolverParameter eParam
)
112 return OUString::number(m_eObjType
);
118 return m_sVariableCells
;
120 case SP_CONSTR_COUNT
:
121 return OUString::number(m_aConstraints
.size());
124 return m_sLOEngineName
;
127 return m_sMSEngineId
;
132 case SP_NON_NEGATIVE
:
133 return m_sNonNegative
;
135 case SP_EPSILON_LEVEL
:
136 return m_sEpsilonLevel
;
138 case SP_LIMIT_BBDEPTH
:
139 return m_sLimitBBDepth
;
150 case SP_LEARNING_CYCLES
:
151 return m_sLearningCycles
;
153 case SP_GUESS_VARIABLE_RANGE
:
154 return m_sGuessVariableRange
;
156 case SP_VARIABLE_RANGE_THRESHOLD
:
157 return m_sVariableRangeThreshold
;
159 case SP_ACR_COMPARATOR
:
160 return m_sUseACRComparator
;
162 case SP_RND_STARTING_POINT
:
163 return m_sUseRandomStartingPoint
;
165 case SP_STRONGER_PRNG
:
166 return m_sUseStrongerPRNG
;
168 case SP_STAGNATION_LIMIT
:
169 return m_sStagnationLimit
;
171 case SP_STAGNATION_TOLERANCE
:
174 case SP_ENHANCED_STATUS
:
175 return m_sEnhancedSolverStatus
;
177 case SP_AGENT_SWITCH_RATE
:
178 return m_sAgentSwitchRate
;
181 return m_sScalingFactorMin
;
184 return m_sScalingFactorMax
;
186 case SP_CROSSOVER_PROB
:
187 return m_sCrossoverProbability
;
189 case SP_COGNITIVE_CONST
:
190 return m_sCognitiveConstant
;
192 case SP_SOCIAL_CONST
:
193 return m_sSocialConstant
;
195 case SP_CONSTRICTION_COEFF
:
196 return m_sConstrictionCoeff
;
198 case SP_MUTATION_PROB
:
199 return m_sMutationProbability
;
201 case SP_LIBRARY_SIZE
:
202 return m_sLibrarySize
;
209 // Sets the value of a single solver parameter in the object
210 void SolverSettings::SetParameter(SolverParameter eParam
, const OUString
& sValue
)
219 sal_Int32 nObjType
= sValue
.toInt32();
223 m_eObjType
= ObjectiveType::OT_MAXIMIZE
;
226 m_eObjType
= ObjectiveType::OT_MINIMIZE
;
229 m_eObjType
= ObjectiveType::OT_VALUE
;
232 m_eObjType
= ObjectiveType::OT_MAXIMIZE
;
241 m_sVariableCells
= sValue
;
244 m_sLOEngineName
= sValue
;
248 if (sValue
== "0" || sValue
== "1")
252 case SP_NON_NEGATIVE
:
254 if (sValue
== "1" || sValue
== "2")
255 m_sNonNegative
= sValue
;
258 case SP_EPSILON_LEVEL
:
259 m_sEpsilonLevel
= sValue
;
261 case SP_LIMIT_BBDEPTH
:
262 m_sLimitBBDepth
= sValue
;
269 if (sValue
== "1" || sValue
== "2" || sValue
== "3")
270 m_sAlgorithm
= sValue
;
274 m_sSwarmSize
= sValue
;
276 case SP_LEARNING_CYCLES
:
277 m_sLearningCycles
= sValue
;
279 case SP_GUESS_VARIABLE_RANGE
:
280 m_sGuessVariableRange
= sValue
;
282 case SP_VARIABLE_RANGE_THRESHOLD
:
283 m_sVariableRangeThreshold
= sValue
;
285 case SP_ACR_COMPARATOR
:
287 if (sValue
== "0" || sValue
== "1")
288 m_sUseACRComparator
= sValue
;
291 case SP_RND_STARTING_POINT
:
293 if (sValue
== "0" || sValue
== "1")
294 m_sUseRandomStartingPoint
= sValue
;
297 case SP_STRONGER_PRNG
:
299 if (sValue
== "0" || sValue
== "1")
300 m_sUseStrongerPRNG
= sValue
;
303 case SP_STAGNATION_LIMIT
:
304 m_sStagnationLimit
= sValue
;
306 case SP_STAGNATION_TOLERANCE
:
307 m_sTolerance
= sValue
;
309 case SP_ENHANCED_STATUS
:
311 if (sValue
== "0" || sValue
== "1")
312 m_sEnhancedSolverStatus
= sValue
;
315 case SP_AGENT_SWITCH_RATE
:
316 m_sAgentSwitchRate
= sValue
;
319 m_sScalingFactorMin
= sValue
;
322 m_sScalingFactorMax
= sValue
;
324 case SP_CROSSOVER_PROB
:
325 m_sCrossoverProbability
= sValue
;
327 case SP_COGNITIVE_CONST
:
328 m_sCognitiveConstant
= sValue
;
330 case SP_SOCIAL_CONST
:
331 m_sSocialConstant
= sValue
;
333 case SP_CONSTRICTION_COEFF
:
334 m_sConstrictionCoeff
= sValue
;
336 case SP_MUTATION_PROB
:
337 m_sMutationProbability
= sValue
;
339 case SP_LIBRARY_SIZE
:
340 m_sLibrarySize
= sValue
;
347 void SolverSettings::SetObjectiveType(ObjectiveType eType
) { m_eObjType
= eType
; }
349 // Loads all constraints in the tab
350 void SolverSettings::ReadConstraints()
352 // Condition indices start at 1 for MS compatibility
353 // The number of "lhs", "rel" and "rhs" entries will always be the same
354 tools::Long nConstraint
= 1;
355 m_aConstraints
.clear();
358 while (ReadConstraintPart(CP_LEFT_HAND_SIDE
, nConstraint
, sValue
))
361 ModelConstraint aNewCondition
;
362 aNewCondition
.aLeftStr
= sValue
;
365 if (ReadConstraintPart(CP_RIGHT_HAND_SIDE
, nConstraint
, sValue
))
366 aNewCondition
.aRightStr
= sValue
;
368 // Relation (operator)
369 if (ReadConstraintPart(CP_OPERATOR
, nConstraint
, sValue
))
370 aNewCondition
.nOperator
= static_cast<sc::ConstraintOperator
>(sValue
.toInt32());
372 m_aConstraints
.push_back(aNewCondition
);
377 // Writes all constraints to the file
378 void SolverSettings::WriteConstraints()
380 // Condition indices start at 1 for MS compatibility
381 tools::Long nConstraint
= 1;
383 for (auto& aConstraint
: m_aConstraints
)
386 WriteConstraintPart(CP_LEFT_HAND_SIDE
, nConstraint
, aConstraint
.aLeftStr
);
387 // Relation (operator)
388 WriteConstraintPart(CP_OPERATOR
, nConstraint
, OUString::number(aConstraint
.nOperator
));
390 WriteConstraintPart(CP_RIGHT_HAND_SIDE
, nConstraint
, aConstraint
.aRightStr
);
395 // Write a single constraint part to the file
396 void SolverSettings::WriteConstraintPart(ConstraintPart ePart
, tools::Long nIndex
,
397 const OUString
& sValue
)
399 // Empty named ranges cannot be written to the file (this corrupts MS files)
400 if (sValue
.isEmpty())
403 OUString sRange
= m_aConstraintParts
[ePart
] + OUString::number(nIndex
);
404 ScRangeData
* pNewEntry
= new ScRangeData(m_rDoc
, sRange
, sValue
);
405 pNewEntry
->AddType(ScRangeData::Type::Hidden
);
406 m_pRangeName
->insert(pNewEntry
);
409 // Reads a single constraint part from its associated named range; returns false if the named
410 // range does not exist in the file
411 bool SolverSettings::ReadConstraintPart(ConstraintPart ePart
, tools::Long nIndex
, OUString
& rValue
)
413 OUString sRange
= m_aConstraintParts
[ePart
] + OUString::number(nIndex
);
414 ScRangeData
* pRangeData
415 = m_pRangeName
->findByUpperName(ScGlobal::getCharClass().uppercase(sRange
));
418 rValue
= pRangeData
->GetSymbol();
419 // tdf#156814 Remove sheet name if it is a range that refers to the same sheet
421 ScRefFlags nFlags
= aRange
.ParseAny(rValue
, m_rDoc
);
422 bool bIsValidRange
= (nFlags
& ScRefFlags::VALID
) == ScRefFlags::VALID
;
423 if (bIsValidRange
&& m_rTable
.GetTab() == aRange
.aStart
.Tab())
424 rValue
= aRange
.Format(m_rDoc
, ScRefFlags::RANGE_ABS
);
430 /* Reads the engine name parameter as informed in the file in the format used in LO.
431 * If only a MS engine is informed, then it is converted to a LO-equivalent engine
433 void SolverSettings::ReadEngine()
435 if (!ReadParamValue(SP_LO_ENGINE
, m_sLOEngineName
, true))
437 // If no engine is defined, use CoinMP solver as default
438 m_sLOEngineName
= "com.sun.star.comp.Calc.CoinMPSolver";
441 if (SolverNamesToExcelEngines
.count(m_sLOEngineName
))
443 // Find equivalent MS engine code
444 m_sMSEngineId
= SolverNamesToExcelEngines
.find(m_sLOEngineName
)->second
;
448 // Write solver LO and MS-equivalent engine names
449 void SolverSettings::WriteEngine()
451 WriteParamValue(SP_LO_ENGINE
, m_sLOEngineName
, true);
452 // Find equivalent MS engine code
453 if (SolverNamesToExcelEngines
.count(m_sLOEngineName
))
455 m_sMSEngineId
= SolverNamesToExcelEngines
.find(m_sLOEngineName
)->second
;
456 WriteParamValue(SP_MS_ENGINE
, m_sMSEngineId
);
460 // Assigns a new constraints vector
461 void SolverSettings::SetConstraints(std::vector
<ModelConstraint
> aConstraints
)
463 m_aConstraints
= std::move(aConstraints
);
466 // Saves all solver settings into the file
467 void SolverSettings::SaveSolverSettings()
469 // Before saving, remove all existing named ranges related to the solver
470 DeleteAllNamedRanges();
472 WriteParamValue(SP_OBJ_CELL
, m_sObjCell
);
473 WriteParamValue(SP_OBJ_TYPE
, OUString::number(m_eObjType
));
474 WriteParamValue(SP_OBJ_VAL
, m_sObjVal
);
475 WriteParamValue(SP_VAR_CELLS
, m_sVariableCells
);
480 sal_Int32 nConstrCount
= m_aConstraints
.size();
481 WriteParamValue(SP_CONSTR_COUNT
, OUString::number(nConstrCount
));
483 // Solver engine options
484 WriteParamValue(SP_INTEGER
, m_sInteger
);
485 WriteParamValue(SP_NON_NEGATIVE
, m_sNonNegative
);
486 WriteParamValue(SP_EPSILON_LEVEL
, m_sEpsilonLevel
);
487 WriteParamValue(SP_LIMIT_BBDEPTH
, m_sLimitBBDepth
);
488 WriteParamValue(SP_TIMEOUT
, m_sTimeout
);
489 WriteParamValue(SP_ALGORITHM
, m_sAlgorithm
);
490 // Engine options common for DEPS and SCO
491 WriteParamValue(SP_SWARM_SIZE
, m_sSwarmSize
);
492 WriteParamValue(SP_LEARNING_CYCLES
, m_sLearningCycles
);
493 WriteParamValue(SP_GUESS_VARIABLE_RANGE
, m_sGuessVariableRange
);
494 WriteDoubleParamValue(SP_VARIABLE_RANGE_THRESHOLD
, m_sVariableRangeThreshold
);
495 WriteParamValue(SP_ACR_COMPARATOR
, m_sUseACRComparator
);
496 WriteParamValue(SP_RND_STARTING_POINT
, m_sUseRandomStartingPoint
);
497 WriteParamValue(SP_STRONGER_PRNG
, m_sUseStrongerPRNG
);
498 WriteParamValue(SP_STAGNATION_LIMIT
, m_sStagnationLimit
);
499 WriteDoubleParamValue(SP_STAGNATION_TOLERANCE
, m_sTolerance
);
500 WriteParamValue(SP_ENHANCED_STATUS
, m_sEnhancedSolverStatus
);
502 WriteDoubleParamValue(SP_AGENT_SWITCH_RATE
, m_sAgentSwitchRate
);
503 WriteDoubleParamValue(SP_SCALING_MIN
, m_sScalingFactorMin
);
504 WriteDoubleParamValue(SP_SCALING_MAX
, m_sScalingFactorMax
);
505 WriteDoubleParamValue(SP_CROSSOVER_PROB
, m_sCrossoverProbability
);
506 WriteDoubleParamValue(SP_COGNITIVE_CONST
, m_sCognitiveConstant
);
507 WriteDoubleParamValue(SP_SOCIAL_CONST
, m_sSocialConstant
);
508 WriteDoubleParamValue(SP_CONSTRICTION_COEFF
, m_sConstrictionCoeff
);
509 WriteDoubleParamValue(SP_MUTATION_PROB
, m_sMutationProbability
);
511 WriteParamValue(SP_LIBRARY_SIZE
, m_sLibrarySize
);
514 m_pDocShell
->SetDocumentModified();
517 /* Reads the current value of the parameter in the named range into rValue
518 * If the value does not exist, the rValue is left unchanged
519 * This is private because it is only used during initialization
520 * Returns true if the value exits; returns false otherwise
522 bool SolverSettings::ReadParamValue(SolverParameter eParam
, OUString
& rValue
, bool bRemoveQuotes
)
524 const auto iter
= m_mNamedRanges
.find(eParam
);
525 assert(iter
!= m_mNamedRanges
.end());
526 OUString sRange
= iter
->second
;
527 ScRangeData
* pRangeData
528 = m_pRangeName
->findByUpperName(ScGlobal::getCharClass().uppercase(sRange
));
531 rValue
= pRangeData
->GetSymbol();
533 ScGlobal::EraseQuotes(rValue
, '"');
535 // tdf#156814 Remove sheet name from the objective cell and value if they refer to the same sheet
536 if (eParam
== SP_OBJ_CELL
|| eParam
== SP_OBJ_VAL
)
539 ScRefFlags nFlags
= aRange
.ParseAny(rValue
, m_rDoc
);
540 bool bIsValidRange
= ((nFlags
& ScRefFlags::VALID
) == ScRefFlags::VALID
);
542 if (bIsValidRange
&& m_rTable
.GetTab() == aRange
.aStart
.Tab())
543 rValue
= aRange
.Format(m_rDoc
, ScRefFlags::RANGE_ABS
);
545 else if (eParam
== SP_VAR_CELLS
)
547 // Variable cells may contain multiple ranges separated by ';'
551 // Delimiter character to separate ranges
552 sal_Unicode cDelimiter
= ScCompiler::GetNativeSymbolChar(OpCode::ocSep
);
556 OUString
aRangeStr(o3tl::getToken(rValue
, 0, cDelimiter
, nIdx
));
558 ScRefFlags nFlags
= aRange
.ParseAny(aRangeStr
, m_rDoc
);
559 bool bIsValidRange
= (nFlags
& ScRefFlags::VALID
) == ScRefFlags::VALID
;
561 if (bIsValidRange
&& m_rTable
.GetTab() == aRange
.aStart
.Tab())
562 aRangeStr
= aRange
.Format(m_rDoc
, ScRefFlags::RANGE_ABS
);
566 sNewValue
= aRangeStr
;
571 sNewValue
+= OUStringChar(cDelimiter
) + aRangeStr
;
582 // Reads a parameter value of type 'double' from the named range and into rValue
583 bool SolverSettings::ReadDoubleParamValue(SolverParameter eParam
, OUString
& rValue
)
585 const auto iter
= m_mNamedRanges
.find(eParam
);
586 assert(iter
!= m_mNamedRanges
.end());
587 OUString sRange
= iter
->second
;
588 ScRangeData
* pRangeData
589 = m_pRangeName
->findByUpperName(ScGlobal::getCharClass().uppercase(sRange
));
592 OUString sLocalizedValue
= pRangeData
->GetSymbol();
593 double fValue
= rtl::math::stringToDouble(sLocalizedValue
,
594 ScGlobal::getLocaleData().getNumDecimalSep()[0],
595 ScGlobal::getLocaleData().getNumThousandSep()[0]);
596 rValue
= OUString::number(fValue
);
602 /* Writes a parameter value to the file as a named range.
603 * Argument bQuoted indicates whether the value should be enclosed with quotes or not (used
604 * for string expressions that must be enclosed with quotes)
606 void SolverSettings::WriteParamValue(SolverParameter eParam
, OUString sValue
, bool bQuoted
)
608 // Empty parameters cannot be written to the file (this corrupts MS files)
609 // There's no problem if the parameter is missing both for LO and MS
610 if (sValue
.isEmpty())
614 ScGlobal::AddQuotes(sValue
, '"');
616 const auto iter
= m_mNamedRanges
.find(eParam
);
617 assert(iter
!= m_mNamedRanges
.end());
618 OUString sRange
= iter
->second
;
619 ScRangeData
* pNewEntry
= new ScRangeData(m_rDoc
, sRange
, sValue
);
620 pNewEntry
->AddType(ScRangeData::Type::Hidden
);
621 m_pRangeName
->insert(pNewEntry
);
624 // Writes a parameter value of type 'double' to the file as a named range
625 // The argument 'sValue' uses dot as decimal separator and needs to be localized before
626 // being written to the file
627 void SolverSettings::WriteDoubleParamValue(SolverParameter eParam
, std::u16string_view sValue
)
629 const auto iter
= m_mNamedRanges
.find(eParam
);
630 assert(iter
!= m_mNamedRanges
.end());
631 OUString sRange
= iter
->second
;
632 double fValue
= rtl::math::stringToDouble(sValue
, '.', ',');
633 OUString sLocalizedValue
= rtl::math::doubleToUString(
634 fValue
, rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
,
635 ScGlobal::getLocaleData().getNumDecimalSep()[0], true);
636 ScRangeData
* pNewEntry
= new ScRangeData(m_rDoc
, sRange
, sLocalizedValue
);
637 pNewEntry
->AddType(ScRangeData::Type::Hidden
);
638 m_pRangeName
->insert(pNewEntry
);
641 void SolverSettings::GetEngineOptions(css::uno::Sequence
<css::beans::PropertyValue
>& aOptions
)
643 sal_Int32 nOptionsSize
= aOptions
.getLength();
644 auto pParamValues
= aOptions
.getArray();
646 for (auto i
= 0; i
< nOptionsSize
; i
++)
648 const css::beans::PropertyValue
& aProp
= aOptions
[i
];
649 OUString sLOParamName
= aProp
.Name
;
650 // Only try to get the parameter value if it is an expected parameter name
651 if (SolverParamNames
.count(sLOParamName
))
653 TParamInfo aParamInfo
;
654 aParamInfo
= SolverParamNames
.find(sLOParamName
)->second
;
655 SolverParameter eParamId
= std::get
<SolverParameter
>(aParamInfo
[0]);
656 OUString sParamType
= std::get
<OUString
>(aParamInfo
[2]);
657 OUString sParamValue
= GetParameter(eParamId
);
658 if (sParamType
== "int")
660 css::uno::Any
nValue(sParamValue
.toInt32());
661 pParamValues
[i
] = css::beans::PropertyValue(sLOParamName
, -1, nValue
,
662 css::beans::PropertyState_DIRECT_VALUE
);
664 if (sParamType
== "double")
666 css::uno::Any
fValue(sParamValue
.toDouble());
667 pParamValues
[i
] = css::beans::PropertyValue(sLOParamName
, -1, fValue
,
668 css::beans::PropertyState_DIRECT_VALUE
);
670 if (sParamType
== "bool")
672 // The parameter NonNegative is a special case for MS compatibility
673 // It uses "1" for "true" and "2" for "false"
675 if (sLOParamName
== "NonNegative")
676 bTmpValue
= sParamValue
== "1" ? true : false;
678 bTmpValue
= sParamValue
.toBoolean();
680 css::uno::Any
bValue(bTmpValue
);
681 pParamValues
[i
] = css::beans::PropertyValue(sLOParamName
, -1, bValue
,
682 css::beans::PropertyState_DIRECT_VALUE
);
688 // Updates the object members related to solver engine options using aOptions info
689 void SolverSettings::SetEngineOptions(const css::uno::Sequence
<css::beans::PropertyValue
>& aOptions
)
691 sal_Int32 nOptionsSize
= aOptions
.getLength();
693 for (auto i
= 0; i
< nOptionsSize
; i
++)
695 const css::beans::PropertyValue
& aProp
= aOptions
[i
];
696 OUString sLOParamName
= aProp
.Name
;
697 // Only try to set the parameter value if it is an expected parameter name
698 if (SolverParamNames
.count(sLOParamName
))
700 TParamInfo aParamInfo
;
701 aParamInfo
= SolverParamNames
.find(sLOParamName
)->second
;
702 SolverParameter eParamId
= std::get
<SolverParameter
>(aParamInfo
[0]);
703 OUString sParamType
= std::get
<OUString
>(aParamInfo
[2]);
704 if (sParamType
== "int")
706 sal_Int32 nValue
= 0;
707 aProp
.Value
>>= nValue
;
708 SetParameter(eParamId
, OUString::number(nValue
));
710 if (sParamType
== "double")
713 aProp
.Value
>>= fValue
;
714 SetParameter(eParamId
, OUString::number(fValue
));
716 if (sParamType
== "bool")
719 aProp
.Value
>>= bValue
;
720 if (sLOParamName
== "NonNegative")
722 // The parameter NonNegative is a special case for MS compatibility
723 // It uses "1" for "true" and "2" for "false"
725 SetParameter(eParamId
, OUString::number(1));
727 SetParameter(eParamId
, OUString::number(2));
731 SetParameter(eParamId
, OUString::number(sal_Int32(bValue
)));
738 // Deletes all named ranges in the current tab that are related to the solver (i.e. start with "solver_")
739 void SolverSettings::DeleteAllNamedRanges()
741 std::vector
<ScRangeData
*> aItemsToErase
;
743 // Indices in m_pRangeName start at 1
744 for (size_t i
= 1; i
<= m_pRangeName
->size(); ++i
)
746 ScRangeData
* pData
= m_pRangeName
->findByIndex(i
);
747 if (pData
&& pData
->GetName().startsWith("solver_"))
748 aItemsToErase
.push_back(pData
);
751 for (auto pItem
: aItemsToErase
)
752 m_pRangeName
->erase(*pItem
);
755 /* Sets all solver parameters to their default values and clear all constraints.
756 * This method only resets the object properties, but does not save changes to the
757 * document. To save changes, call SaveSolverSettings().
759 void SolverSettings::ResetToDefaults()
762 m_eObjType
= ObjectiveType::OT_MAXIMIZE
;
764 m_sVariableCells
= "";
767 css::uno::Sequence
<OUString
> aEngineNames
;
768 css::uno::Sequence
<OUString
> aDescriptions
;
769 ScSolverUtil::GetImplementations(aEngineNames
, aDescriptions
);
771 // tdf#162760 Set the parameters of all available solver engines to the default values
772 for (const auto& sEngine
: aEngineNames
)
774 css::uno::Sequence
<css::beans::PropertyValue
> aEngineProps
775 = ScSolverUtil::GetDefaults(sEngine
);
776 SetEngineOptions(aEngineProps
);
779 // The default solver engine is the first implementation available
780 m_sLOEngineName
= aEngineNames
[0];
782 // Clear all constraints
783 m_aConstraints
.clear();
786 /* Returns true if the current sheet already has a solver model.
787 This is determined by checking if the current tab has the SP_OBJ_CELL named range
788 which is associated with solver models.
789 Note that the named ranges are only created after SaveSolverSettings is called,
790 so before it is called, no solver-related named ranges exist.
792 bool SolverSettings::TabHasSolverModel()
794 // Check if the named range for the objective value exists in the sheet
795 const auto iter
= m_mNamedRanges
.find(SP_OBJ_CELL
);
796 if (iter
== m_mNamedRanges
.end())
798 OUString sRange
= iter
->second
;
799 ScRangeData
* pRangeData
800 = m_pRangeName
->findByUpperName(ScGlobal::getCharClass().uppercase(sRange
));
808 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */