namespace sc
{
SolverSettings::SolverSettings(ScTable& rTable)
: m_rTable(rTable)
, m_rDoc(m_rTable.GetDoc())
, m_pDocShell(m_rDoc.GetDocumentShell())
{ // Get the named range manager for this tab
std::map<OUString, ScRangeName*> rRangeMap;
m_rDoc.GetRangeNameMap(rRangeMap);
m_pRangeName = rRangeMap.find(m_rTable.GetName())->second;
Initialize();
}
void SolverSettings::Initialize()
{ // Assign default values for the solver parameters
ResetToDefaults();
// Read the parameter values in the sheet
ReadParamValue(SP_OBJ_CELL, m_sObjCell);
ReadParamValue(SP_OBJ_VAL, m_sObjVal);
ReadParamValue(SP_VAR_CELLS, m_sVariableCells);
// Returns the current value of the parameter in the object as a string
OUString SolverSettings::GetParameter(SolverParameter eParam)
{ switch (eParam)
{ case SP_OBJ_CELL: return m_sObjCell; break; case SP_OBJ_TYPE: return OUString::number(m_eObjType); break; case SP_OBJ_VAL: return m_sObjVal; break; case SP_VAR_CELLS: return m_sVariableCells; break; case SP_CONSTR_COUNT: return OUString::number(m_aConstraints.size()); break; case SP_LO_ENGINE: return m_sLOEngineName; break; case SP_MS_ENGINE: return m_sMSEngineId; break; case SP_INTEGER: return m_sInteger; break; case SP_NON_NEGATIVE: return m_sNonNegative; break; case SP_EPSILON_LEVEL: return m_sEpsilonLevel; break; case SP_LIMIT_BBDEPTH: return m_sLimitBBDepth; break; case SP_TIMEOUT: return m_sTimeout; break; case SP_ALGORITHM: return m_sAlgorithm; break; case SP_SWARM_SIZE: return m_sSwarmSize; break; case SP_LEARNING_CYCLES: return m_sLearningCycles; break; case SP_GUESS_VARIABLE_RANGE: return m_sGuessVariableRange; break; case SP_VARIABLE_RANGE_THRESHOLD: return m_sVariableRangeThreshold; break; case SP_ACR_COMPARATOR: return m_sUseACRComparator; break; case SP_RND_STARTING_POINT: return m_sUseRandomStartingPoint; break; case SP_STRONGER_PRNG: return m_sUseStrongerPRNG; break; case SP_STAGNATION_LIMIT: return m_sStagnationLimit; break; case SP_STAGNATION_TOLERANCE: return m_sTolerance; break; case SP_ENHANCED_STATUS: return m_sEnhancedSolverStatus; break; case SP_AGENT_SWITCH_RATE: return m_sAgentSwitchRate; break; case SP_SCALING_MIN: return m_sScalingFactorMin; break; case SP_SCALING_MAX: return m_sScalingFactorMax; break; case SP_CROSSOVER_PROB: return m_sCrossoverProbability; break; case SP_COGNITIVE_CONST: return m_sCognitiveConstant; break; case SP_SOCIAL_CONST: return m_sSocialConstant; break; case SP_CONSTRICTION_COEFF: return m_sConstrictionCoeff; break; case SP_MUTATION_PROB: return m_sMutationProbability; break; case SP_LIBRARY_SIZE: return m_sLibrarySize; break; default: return u""_ustr;
}
}
// Sets the value of a single solver parameter in the object void SolverSettings::SetParameter(SolverParameter eParam, const OUString& sValue)
{ switch (eParam)
{ case SP_OBJ_CELL:
m_sObjCell = sValue; break; case SP_OBJ_TYPE:
{
sal_Int32 nObjType = sValue.toInt32(); switch (nObjType)
{ case OT_MAXIMIZE:
m_eObjType = ObjectiveType::OT_MAXIMIZE; break; case OT_MINIMIZE:
m_eObjType = ObjectiveType::OT_MINIMIZE; break; case OT_VALUE:
m_eObjType = ObjectiveType::OT_VALUE; break; default:
m_eObjType = ObjectiveType::OT_MAXIMIZE; break;
} break;
} case SP_OBJ_VAL:
m_sObjVal = sValue; break; case SP_VAR_CELLS:
m_sVariableCells = sValue; break; case SP_LO_ENGINE:
m_sLOEngineName = sValue; break; case SP_INTEGER:
{ if (sValue == "0" || sValue == "1")
m_sInteger = sValue;
} break; case SP_NON_NEGATIVE:
{ if (sValue == "1" || sValue == "2")
m_sNonNegative = sValue;
} break; case SP_EPSILON_LEVEL:
m_sEpsilonLevel = sValue; break; case SP_LIMIT_BBDEPTH:
m_sLimitBBDepth = sValue; break; case SP_TIMEOUT:
m_sTimeout = sValue; break; case SP_ALGORITHM:
{ if (sValue == "1" || sValue == "2" || sValue == "3")
m_sAlgorithm = sValue;
} break; case SP_SWARM_SIZE:
m_sSwarmSize = sValue; break; case SP_LEARNING_CYCLES:
m_sLearningCycles = sValue; break; case SP_GUESS_VARIABLE_RANGE:
m_sGuessVariableRange = sValue; break; case SP_VARIABLE_RANGE_THRESHOLD:
m_sVariableRangeThreshold = sValue; break; case SP_ACR_COMPARATOR:
{ if (sValue == "0" || sValue == "1")
m_sUseACRComparator = sValue;
} break; case SP_RND_STARTING_POINT:
{ if (sValue == "0" || sValue == "1")
m_sUseRandomStartingPoint = sValue;
} break; case SP_STRONGER_PRNG:
{ if (sValue == "0" || sValue == "1")
m_sUseStrongerPRNG = sValue;
} break; case SP_STAGNATION_LIMIT:
m_sStagnationLimit = sValue; break; case SP_STAGNATION_TOLERANCE:
m_sTolerance = sValue; break; case SP_ENHANCED_STATUS:
{ if (sValue == "0" || sValue == "1")
m_sEnhancedSolverStatus = sValue;
} break; case SP_AGENT_SWITCH_RATE:
m_sAgentSwitchRate = sValue; break; case SP_SCALING_MIN:
m_sScalingFactorMin = sValue; break; case SP_SCALING_MAX:
m_sScalingFactorMax = sValue; break; case SP_CROSSOVER_PROB:
m_sCrossoverProbability = sValue; break; case SP_COGNITIVE_CONST:
m_sCognitiveConstant = sValue; break; case SP_SOCIAL_CONST:
m_sSocialConstant = sValue; break; case SP_CONSTRICTION_COEFF:
m_sConstrictionCoeff = sValue; break; case SP_MUTATION_PROB:
m_sMutationProbability = sValue; break; case SP_LIBRARY_SIZE:
m_sLibrarySize = sValue; break; default: break;
}
}
// Loads all constraints in the tab void SolverSettings::ReadConstraints()
{ // Condition indices start at 1 for MS compatibility // The number of "lhs", "rel" and "rhs" entries will always be the same
tools::Long nConstraint = 1;
m_aConstraints.clear();
OUString sValue;
while (ReadConstraintPart(CP_LEFT_HAND_SIDE, nConstraint, sValue))
{ // Left hand side
ModelConstraint aNewCondition;
aNewCondition.aLeftStr = sValue;
// Right hand side if (ReadConstraintPart(CP_RIGHT_HAND_SIDE, nConstraint, sValue))
aNewCondition.aRightStr = sValue;
// Relation (operator) if (ReadConstraintPart(CP_OPERATOR, nConstraint, sValue))
aNewCondition.nOperator = static_cast<sc::ConstraintOperator>(sValue.toInt32());
// Writes all constraints to the file void SolverSettings::WriteConstraints()
{ // Condition indices start at 1 for MS compatibility
tools::Long nConstraint = 1;
for (auto& aConstraint : m_aConstraints)
{ // Left hand side
WriteConstraintPart(CP_LEFT_HAND_SIDE, nConstraint, aConstraint.aLeftStr); // Relation (operator)
WriteConstraintPart(CP_OPERATOR, nConstraint, OUString::number(aConstraint.nOperator)); // Right hand side
WriteConstraintPart(CP_RIGHT_HAND_SIDE, nConstraint, aConstraint.aRightStr);
nConstraint++;
}
}
// Write a single constraint part to the file void SolverSettings::WriteConstraintPart(ConstraintPart ePart, tools::Long nIndex, const OUString& sValue)
{ // Empty named ranges cannot be written to the file (this corrupts MS files) if (sValue.isEmpty()) return;
// Reads a single constraint part from its associated named range; returns false if the named // range does not exist in the file bool SolverSettings::ReadConstraintPart(ConstraintPart ePart, tools::Long nIndex, OUString& rValue)
{
OUString sRange = m_aConstraintParts[ePart] + OUString::number(nIndex);
ScRangeData* pRangeData
= m_pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(sRange)); if (pRangeData)
{
rValue = pRangeData->GetSymbol(); // tdf#156814 Remove sheet name if it is a range that refers to the same sheet
ScRange aRange;
ScRefFlags nFlags = aRange.ParseAny(rValue, m_rDoc); bool bIsValidRange = (nFlags & ScRefFlags::VALID) == ScRefFlags::VALID; if (bIsValidRange && m_rTable.GetTab() == aRange.aStart.Tab())
rValue = aRange.Format(m_rDoc, ScRefFlags::RANGE_ABS); returntrue;
} returnfalse;
}
/* Reads the engine name parameter as informed in the file in the format used in LO. *IfonlyaMSengineisinformed,thenitisconvertedtoaLO-equivalentengine
*/ void SolverSettings::ReadEngine()
{ if (!ReadParamValue(SP_LO_ENGINE, m_sLOEngineName, true))
{ // If no engine is defined, use CoinMP solver as default
m_sLOEngineName = "com.sun.star.comp.Calc.CoinMPSolver";
}
if (SolverNamesToExcelEngines.count(m_sLOEngineName))
{ // Find equivalent MS engine code
m_sMSEngineId = SolverNamesToExcelEngines.find(m_sLOEngineName)->second;
}
}
// Write solver LO and MS-equivalent engine names void SolverSettings::WriteEngine()
{
WriteParamValue(SP_LO_ENGINE, m_sLOEngineName, true); // Find equivalent MS engine code if (SolverNamesToExcelEngines.count(m_sLOEngineName))
{
m_sMSEngineId = SolverNamesToExcelEngines.find(m_sLOEngineName)->second;
WriteParamValue(SP_MS_ENGINE, m_sMSEngineId);
}
}
// Assigns a new constraints vector void SolverSettings::SetConstraints(std::vector<ModelConstraint> aConstraints)
{
m_aConstraints = std::move(aConstraints);
}
// Saves all solver settings into the file void SolverSettings::SaveSolverSettings()
{ // Before saving, remove all existing named ranges related to the solver
DeleteAllNamedRanges();
if (m_pDocShell)
m_pDocShell->SetDocumentModified();
}
/* Reads the current value of the parameter in the named range into rValue *Ifthevaluedoesnotexist,therValueisleftunchanged *Thisisprivatebecauseitisonlyusedduringinitialization *Returnstrueifthevalueexits;returnsfalseotherwise
*/ bool SolverSettings::ReadParamValue(SolverParameter eParam, OUString& rValue, bool bRemoveQuotes)
{ constauto iter = m_mNamedRanges.find(eParam);
assert(iter != m_mNamedRanges.end());
OUString sRange = iter->second;
ScRangeData* pRangeData
= m_pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(sRange)); if (pRangeData)
{
rValue = pRangeData->GetSymbol(); if (bRemoveQuotes)
ScGlobal::EraseQuotes(rValue, '"');
// tdf#156814 Remove sheet name from the objective cell and value if they refer to the same sheet if (eParam == SP_OBJ_CELL || eParam == SP_OBJ_VAL)
{
ScRange aRange;
ScRefFlags nFlags = aRange.ParseAny(rValue, m_rDoc); bool bIsValidRange = ((nFlags & ScRefFlags::VALID) == ScRefFlags::VALID);
if (bIsValidRange && m_rTable.GetTab() == aRange.aStart.Tab())
rValue = aRange.Format(m_rDoc, ScRefFlags::RANGE_ABS);
} elseif (eParam == SP_VAR_CELLS)
{ // Variable cells may contain multiple ranges separated by ';'
sal_Int32 nIdx = 0;
OUString sNewValue; bool bFirst = true; // Delimiter character to separate ranges
sal_Unicode cDelimiter = ScCompiler::GetNativeSymbolChar(OpCode::ocSep);
// Reads a parameter value of type 'double' from the named range and into rValue bool SolverSettings::ReadDoubleParamValue(SolverParameter eParam, OUString& rValue)
{ constauto iter = m_mNamedRanges.find(eParam);
assert(iter != m_mNamedRanges.end());
OUString sRange = iter->second;
ScRangeData* pRangeData
= m_pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(sRange)); if (pRangeData)
{
OUString sLocalizedValue = pRangeData->GetSymbol(); double fValue = rtl::math::stringToDouble(sLocalizedValue,
ScGlobal::getLocaleData().getNumDecimalSep()[0],
ScGlobal::getLocaleData().getNumThousandSep()[0]);
rValue = OUString::number(fValue); returntrue;
} returnfalse;
}
/* Writes a parameter value to the file as a named range. *ArgumentbQuotedindicateswhetherthevalueshouldbeenclosedwithquotesornot(used *forstringexpressionsthatmustbeenclosedwithquotes)
*/ void SolverSettings::WriteParamValue(SolverParameter eParam, OUString sValue, bool bQuoted)
{ // Empty parameters cannot be written to the file (this corrupts MS files) // There's no problem if the parameter is missing both for LO and MS if (sValue.isEmpty()) return;
// Writes a parameter value of type 'double' to the file as a named range // The argument 'sValue' uses dot as decimal separator and needs to be localized before // being written to the file void SolverSettings::WriteDoubleParamValue(SolverParameter eParam, std::u16string_view sValue)
{ constauto iter = m_mNamedRanges.find(eParam);
assert(iter != m_mNamedRanges.end());
OUString sRange = iter->second; double fValue = rtl::math::stringToDouble(sValue, '.', ',');
OUString sLocalizedValue = rtl::math::doubleToUString(
fValue, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
ScGlobal::getLocaleData().getNumDecimalSep()[0], true);
ScRangeData* pNewEntry = new ScRangeData(m_rDoc, sRange, sLocalizedValue);
pNewEntry->AddType(ScRangeData::Type::Hidden);
m_pRangeName->insert(pNewEntry);
}
for (auto i = 0; i < nOptionsSize; i++)
{ const css::beans::PropertyValue& aProp = aOptions[i];
OUString sLOParamName = aProp.Name; // Only try to get the parameter value if it is an expected parameter name if (SolverParamNames.count(sLOParamName))
{
TParamInfo aParamInfo;
aParamInfo = SolverParamNames.find(sLOParamName)->second;
SolverParameter eParamId = std::get<SolverParameter>(aParamInfo[0]);
OUString sParamType = std::get<OUString>(aParamInfo[2]);
OUString sParamValue = GetParameter(eParamId); if (sParamType == "int")
{
css::uno::Any nValue(sParamValue.toInt32());
pParamValues[i] = css::beans::PropertyValue(sLOParamName, -1, nValue,
css::beans::PropertyState_DIRECT_VALUE);
} if (sParamType == "double")
{
css::uno::Any fValue(sParamValue.toDouble());
pParamValues[i] = css::beans::PropertyValue(sLOParamName, -1, fValue,
css::beans::PropertyState_DIRECT_VALUE);
} if (sParamType == "bool")
{ // The parameter NonNegative is a special case for MS compatibility // It uses "1" for "true" and "2" for "false" bool bTmpValue; if (sLOParamName == "NonNegative")
bTmpValue = sParamValue == "1" ? true : false; else
bTmpValue = sParamValue.toBoolean();
// Updates the object members related to solver engine options using aOptions info void SolverSettings::SetEngineOptions(const css::uno::Sequence<css::beans::PropertyValue>& aOptions)
{
sal_Int32 nOptionsSize = aOptions.getLength();
for (auto i = 0; i < nOptionsSize; i++)
{ const css::beans::PropertyValue& aProp = aOptions[i];
OUString sLOParamName = aProp.Name; // Only try to set the parameter value if it is an expected parameter name if (SolverParamNames.count(sLOParamName))
{
TParamInfo aParamInfo;
aParamInfo = SolverParamNames.find(sLOParamName)->second;
SolverParameter eParamId = std::get<SolverParameter>(aParamInfo[0]);
OUString sParamType = std::get<OUString>(aParamInfo[2]); if (sParamType == "int")
{
sal_Int32 nValue = 0;
aProp.Value >>= nValue;
SetParameter(eParamId, OUString::number(nValue));
} if (sParamType == "double")
{ double fValue = 0;
aProp.Value >>= fValue;
SetParameter(eParamId, OUString::number(fValue));
} if (sParamType == "bool")
{ bool bValue = false;
aProp.Value >>= bValue; if (sLOParamName == "NonNegative")
{ // The parameter NonNegative is a special case for MS compatibility // It uses "1" for "true" and "2" for "false" if (bValue)
SetParameter(eParamId, OUString::number(1)); else
SetParameter(eParamId, OUString::number(2));
} else
{
SetParameter(eParamId, OUString::number(sal_Int32(bValue)));
}
}
}
}
}
// Deletes all named ranges in the current tab that are related to the solver (i.e. start with "solver_") void SolverSettings::DeleteAllNamedRanges()
{
std::vector<ScRangeData*> aItemsToErase;
// Indices in m_pRangeName start at 1 for (size_t i = 1; i <= m_pRangeName->size(); ++i)
{
ScRangeData* pData = m_pRangeName->findByIndex(i); if (pData && pData->GetName().startsWith("solver_"))
aItemsToErase.push_back(pData);
}
for (auto pItem : aItemsToErase)
m_pRangeName->erase(*pItem);
}
/* Sets all solver parameters to their default values and clear all constraints. *Thismethodonlyresetstheobjectproperties,butdoesnotsavechangestothe *document.Tosavechanges,callSaveSolverSettings().
*/ void SolverSettings::ResetToDefaults()
{
m_sObjCell = "";
m_eObjType = ObjectiveType::OT_MAXIMIZE;
m_sObjVal = "";
m_sVariableCells = "";
m_sMSEngineId = "1";
// tdf#162760 Set the parameters of all available solver engines to the default values for (constauto& sEngine : aEngineNames)
{
css::uno::Sequence<css::beans::PropertyValue> aEngineProps
= ScSolverUtil::GetDefaults(sEngine);
SetEngineOptions(aEngineProps);
}
// The default solver engine is the first implementation available
m_sLOEngineName = aEngineNames[0];
// Clear all constraints
m_aConstraints.clear();
}
/* Returns true if the current sheet already has a solver model. ThisisdeterminedbycheckingifthecurrenttabhastheSP_OBJ_CELLnamedrange whichisassociatedwithsolvermodels. NotethatthenamedrangesareonlycreatedafterSaveSolverSettingsiscalled, sobeforeitiscalled,nosolver-relatednamedrangesexist.
*/ bool SolverSettings::TabHasSolverModel()
{ // Check if the named range for the objective value exists in the sheet constauto iter = m_mNamedRanges.find(SP_OBJ_CELL); if (iter == m_mNamedRanges.end()) returnfalse;
OUString sRange = iter->second;
ScRangeData* pRangeData
= m_pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(sRange)); if (pRangeData) returntrue; returnfalse;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.