sc/inc/SolverSettings.hxx              |  117 ++++++++++++++++-
 sc/qa/unit/data/ods/tdf158735.ods      |binary
 sc/qa/unit/ucalc_solver.cxx            |   29 ++++
 sc/source/core/data/SolverSettings.cxx |  220 +++++++++++++++++++++++++++++++++
 4 files changed, 356 insertions(+), 10 deletions(-)

New commits:
commit fa8351c50bd8f14830a461c09805e43c6fdb065d
Author:     Rafael Lima <rafael.palma.l...@gmail.com>
AuthorDate: Mon Mar 4 19:01:40 2024 +0100
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Thu Mar 7 12:11:37 2024 +0100

    tdf#158735 Save solver settings for DEPS and SCO as well
    
    When bug tdf#38948 was originally fixed, the solvers DEPS and SCO were not 
considered. This caused a regression, because setting engine options for these 
solvers made them never be saved, even in its own sheet.
    
    This patch fixes that by incorporating the engine options for DEPS and SCO.
    
    Change-Id: I93af712f91da2f7b1ac57ed74f6c2c2d7d411bba
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164376
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>
    (cherry picked from commit 04d884cc99eb66679fb254129b54488bd40e5abf)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164385
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/sc/inc/SolverSettings.hxx b/sc/inc/SolverSettings.hxx
index ec1ef994a7b8..985e8d30f796 100644
--- a/sc/inc/SolverSettings.hxx
+++ b/sc/inc/SolverSettings.hxx
@@ -39,11 +39,34 @@ enum SolverParameter
     SP_LO_ENGINE, // Engine name used in LO
     SP_MS_ENGINE, // Engine ID used in MSO
     SP_INTEGER, // Assume all variables are integer (0: no, 1: yes)
+    // LpSolve, CoinMP and SwarmSolver
     SP_NON_NEGATIVE, // Assume non negativity (1: yes, 2: no)
     SP_EPSILON_LEVEL, // Epsilon level
     SP_LIMIT_BBDEPTH, // Branch and bound depth
     SP_TIMEOUT, // Time limit to return a solution
-    SP_ALGORITHM // Algorithm used by the SwarmSolver (1, 2 or 3)
+    SP_ALGORITHM, // Algorithm used by the SwarmSolver (1, 2 or 3)
+    // Engine options common for DEPS and SCO
+    SP_SWARM_SIZE, // Size of Swarm
+    SP_LEARNING_CYCLES, // Learning Cycles
+    SP_GUESS_VARIABLE_RANGE, // Variable Bounds Guessing
+    SP_VARIABLE_RANGE_THRESHOLD, // Variable Bounds Threshold (when guessing)
+    SP_ACR_COMPARATOR, // Use ACR Comparator (instead of BCH)
+    SP_RND_STARTING_POINT, // Use Random starting point
+    SP_STRONGER_PRNG, // Use a stronger random generator (slower)
+    SP_STAGNATION_LIMIT, // Stagnation Limit
+    SP_STAGNATION_TOLERANCE, // Stagnation Tolerance
+    SP_ENHANCED_STATUS, // Show enhanced solver status
+    // DEPS Options
+    SP_AGENT_SWITCH_RATE, // Agent Switch Rate (DE Probability)
+    SP_SCALING_MIN, // DE: Min Scaling Factor (0-1.2)
+    SP_SCALING_MAX, // DE: Max Scaling Factor (0-1.2)
+    SP_CROSSOVER_PROB, // DE: Crossover Probability (0-1)
+    SP_COGNITIVE_CONST, // Cognitive Constant
+    SP_SOCIAL_CONST, // Social Constant
+    SP_CONSTRICTION_COEFF, // PS: Constriction Coefficient
+    SP_MUTATION_PROB, // Mutation Probability (0-0.005)
+    // SCO Options
+    SP_LIBRARY_SIZE, // Size of library
 };
 
 // Starts at 1 to maintain MS compatibility
@@ -123,6 +146,28 @@ private:
     OUString m_sLimitBBDepth;
     OUString m_sTimeout;
     OUString m_sAlgorithm;
+    // DEPS and SCO
+    OUString m_sSwarmSize;
+    OUString m_sLearningCycles;
+    OUString m_sGuessVariableRange;
+    OUString m_sVariableRangeThreshold;
+    OUString m_sUseACRComparator;
+    OUString m_sUseRandomStartingPoint;
+    OUString m_sUseStrongerPRNG;
+    OUString m_sStagnationLimit;
+    OUString m_sTolerance;
+    OUString m_sEnhancedSolverStatus;
+    // DEPS only
+    OUString m_sAgentSwitchRate;
+    OUString m_sScalingFactorMin;
+    OUString m_sScalingFactorMax;
+    OUString m_sCrossoverProbability;
+    OUString m_sCognitiveConstant;
+    OUString m_sSocialConstant;
+    OUString m_sConstrictionCoeff;
+    OUString m_sMutationProbability;
+    OUString m_sLibrarySize;
+
     css::uno::Sequence<css::beans::PropertyValue> m_aEngineOptions;
 
     std::vector<ModelConstraint> m_aConstraints;
@@ -131,7 +176,9 @@ private:
 
     // Used to create or read a single solver parameter based on its named 
range
     bool ReadParamValue(SolverParameter eParam, OUString& rValue, bool 
bRemoveQuotes = false);
+    bool ReadDoubleParamValue(SolverParameter eParam, OUString& rValue);
     void WriteParamValue(SolverParameter eParam, OUString sValue, bool bQuoted 
= false);
+    void WriteDoubleParamValue(SolverParameter eParam, std::u16string_view 
sValue);
 
     // Creates or reads all constraints stored in named ranges
     void ReadConstraints();
@@ -149,19 +196,46 @@ private:
 
     // Maps solver parameters to named ranges
     std::map<SolverParameter, OUString> m_mNamedRanges
-        = { { SP_OBJ_CELL, "solver_opt" },      { SP_OBJ_TYPE, "solver_typ" },
-            { SP_OBJ_VAL, "solver_val" },       { SP_VAR_CELLS, "solver_adj" },
-            { SP_CONSTR_COUNT, "solver_num" },  { SP_LO_ENGINE, 
"solver_lo_eng" },
-            { SP_MS_ENGINE, "solver_eng" },     { SP_INTEGER, "solver_int" },
-            { SP_NON_NEGATIVE, "solver_neg" },  { SP_EPSILON_LEVEL, 
"solver_eps" },
-            { SP_LIMIT_BBDEPTH, "solver_bbd" }, { SP_TIMEOUT, "solver_tim" },
-            { SP_ALGORITHM, "solver_alg" } };
+        = { { SP_OBJ_CELL, "solver_opt" },
+            { SP_OBJ_TYPE, "solver_typ" },
+            { SP_OBJ_VAL, "solver_val" },
+            { SP_VAR_CELLS, "solver_adj" },
+            { SP_CONSTR_COUNT, "solver_num" },
+            { SP_LO_ENGINE, "solver_lo_eng" },
+            { SP_MS_ENGINE, "solver_eng" },
+            { SP_INTEGER, "solver_int" },
+            { SP_NON_NEGATIVE, "solver_neg" },
+            { SP_EPSILON_LEVEL, "solver_eps" },
+            { SP_LIMIT_BBDEPTH, "solver_bbd" },
+            { SP_TIMEOUT, "solver_tim" },
+            { SP_ALGORITHM, "solver_alg" },
+            { SP_SWARM_SIZE, "solver_ssz" },
+            { SP_LEARNING_CYCLES, "solver_lcy" },
+            { SP_GUESS_VARIABLE_RANGE, "solver_gvr" },
+            { SP_VARIABLE_RANGE_THRESHOLD, "solver_vrt" },
+            { SP_ACR_COMPARATOR, "solver_acr" },
+            { SP_RND_STARTING_POINT, "solver_rsp" },
+            { SP_STRONGER_PRNG, "solver_prng" },
+            { SP_STAGNATION_LIMIT, "solver_slim" },
+            { SP_STAGNATION_TOLERANCE, "solver_stol" },
+            { SP_ENHANCED_STATUS, "solver_enst" },
+            { SP_AGENT_SWITCH_RATE, "solver_asr" },
+            { SP_SCALING_MIN, "solver_smin" },
+            { SP_SCALING_MAX, "solver_smax" },
+            { SP_CROSSOVER_PROB, "solver_crpb" },
+            { SP_COGNITIVE_CONST, "solver_cog" },
+            { SP_SOCIAL_CONST, "solver_soc" },
+            { SP_CONSTRICTION_COEFF, "solver_ccoeff" },
+            { SP_MUTATION_PROB, "solver_mtpb" },
+            { SP_LIBRARY_SIZE, "solver_lbsz" } };
 
     // Maps LO solver implementation names to MS engine codes
     std::map<OUString, OUString> SolverNamesToExcelEngines = {
         { "com.sun.star.comp.Calc.CoinMPSolver", "2" }, // Simplex LP
         { "com.sun.star.comp.Calc.LpsolveSolver", "2" }, // Simplex LP
-        { "com.sun.star.comp.Calc.SwarmSolver", "1" } // GRG Nonlinear
+        { "com.sun.star.comp.Calc.SwarmSolver", "1" }, // GRG Nonlinear
+        { "com.sun.star.comp.Calc.NLPSolver.DEPSSolverImpl", "3" }, // DEPS
+        { "com.sun.star.comp.Calc.NLPSolver.SCOSolverImpl", "3" } // SCO
     };
 
     // Maps MS solver engine codes to LO solver implementation names
@@ -180,7 +254,30 @@ private:
             { "EpsilonLevel", { SP_EPSILON_LEVEL, "solver_eps", "int" } },
             { "LimitBBDepth", { SP_LIMIT_BBDEPTH, "solver_bbd", "bool" } },
             { "Timeout", { SP_TIMEOUT, "solver_tim", "int" } },
-            { "Algorithm", { SP_ALGORITHM, "solver_alg", "int" } } };
+            { "Algorithm", { SP_ALGORITHM, "solver_alg", "int" } },
+            // SCO and DEPS
+            { "AssumeNonNegative", { SP_NON_NEGATIVE, "solver_neg", "bool" } },
+            { "SwarmSize", { SP_SWARM_SIZE, "solver_ssz", "int" } },
+            { "LearningCycles", { SP_LEARNING_CYCLES, "solver_lcy", "int" } },
+            { "GuessVariableRange", { SP_GUESS_VARIABLE_RANGE, "solver_gvr", 
"bool" } },
+            { "VariableRangeThreshold", { SP_VARIABLE_RANGE_THRESHOLD, 
"solver_vrt", "double" } },
+            { "UseACRComparator", { SP_ACR_COMPARATOR, "solver_acr", "bool" } 
},
+            { "UseRandomStartingPoint", { SP_RND_STARTING_POINT, "solver_rsp", 
"bool" } },
+            { "UseStrongerPRNG", { SP_STRONGER_PRNG, "solver_prng", "bool" } },
+            { "StagnationLimit", { SP_STAGNATION_LIMIT, "solver_slim", "int" } 
},
+            { "Tolerance", { SP_STAGNATION_TOLERANCE, "solver_stol", "double" 
} },
+            { "EnhancedSolverStatus", { SP_ENHANCED_STATUS, "solver_enst", 
"bool" } },
+            // DEPS only
+            { "AgentSwitchRate", { SP_AGENT_SWITCH_RATE, "solver_asr", 
"double" } },
+            { "DEFactorMin", { SP_SCALING_MIN, "solver_smin", "double" } },
+            { "DEFactorMax", { SP_SCALING_MAX, "solver_smax", "double" } },
+            { "DECR", { SP_CROSSOVER_PROB, "solver_crpb", "double" } },
+            { "PSC1", { SP_COGNITIVE_CONST, "solver_cog", "double" } },
+            { "PSC2", { SP_SOCIAL_CONST, "solver_soc", "double" } },
+            { "PSWeight", { SP_CONSTRICTION_COEFF, "solver_ccoeff", "double" } 
},
+            { "PSCL", { SP_MUTATION_PROB, "solver_mtpb", "double" } },
+            // SCO only
+            { "LibrarySize", { SP_LIBRARY_SIZE, "solver_lbsz", "int" } } };
 
     // Stores the roots used for named ranges of constraint parts
     // Items here must be in the same order as in ConstraintPart enum
diff --git a/sc/qa/unit/data/ods/tdf158735.ods 
b/sc/qa/unit/data/ods/tdf158735.ods
new file mode 100644
index 000000000000..6003f29bf38a
Binary files /dev/null and b/sc/qa/unit/data/ods/tdf158735.ods differ
diff --git a/sc/qa/unit/ucalc_solver.cxx b/sc/qa/unit/ucalc_solver.cxx
index 47770ec0c0e5..7834597e9c07 100644
--- a/sc/qa/unit/ucalc_solver.cxx
+++ b/sc/qa/unit/ucalc_solver.cxx
@@ -163,4 +163,33 @@ CPPUNIT_TEST_FIXTURE(SolverTest, tdf156815)
     CPPUNIT_ASSERT_EQUAL(OUString("$NewName.$B$2"), aConstraints[0].aRightStr);
 }
 
+// Tests if settings for the DEPS and SCO solvers are kept in the file
+CPPUNIT_TEST_FIXTURE(SolverTest, tdf158735)
+{
+    createScDoc("ods/tdf158735.ods");
+    ScDocument* pDoc = getScDoc();
+
+    // Test the non-default values of the DEPS model
+    ScTable* pTable = pDoc->FetchTable(0);
+    std::shared_ptr<sc::SolverSettings> pSettings = 
pTable->GetSolverSettings();
+    CPPUNIT_ASSERT(pSettings);
+    
CPPUNIT_ASSERT_EQUAL(OUString("com.sun.star.comp.Calc.NLPSolver.DEPSSolverImpl"),
+                         pSettings->GetParameter(SP_LO_ENGINE));
+    CPPUNIT_ASSERT_EQUAL(OUString("0.45"), 
pSettings->GetParameter(SP_AGENT_SWITCH_RATE));
+    CPPUNIT_ASSERT_EQUAL(OUString("0.85"), 
pSettings->GetParameter(SP_CROSSOVER_PROB));
+    CPPUNIT_ASSERT_EQUAL(OUString("1500"), 
pSettings->GetParameter(SP_LEARNING_CYCLES));
+    CPPUNIT_ASSERT_EQUAL(OUString("0"), 
pSettings->GetParameter(SP_ENHANCED_STATUS));
+
+    // Test the non-default values of the SCO model
+    pTable = pDoc->FetchTable(1);
+    pSettings = pTable->GetSolverSettings();
+    CPPUNIT_ASSERT(pSettings);
+    
CPPUNIT_ASSERT_EQUAL(OUString("com.sun.star.comp.Calc.NLPSolver.SCOSolverImpl"),
+                         pSettings->GetParameter(SP_LO_ENGINE));
+    CPPUNIT_ASSERT_EQUAL(OUString("180"), 
pSettings->GetParameter(SP_LIBRARY_SIZE));
+    CPPUNIT_ASSERT_EQUAL(OUString("0.00055"), 
pSettings->GetParameter(SP_STAGNATION_TOLERANCE));
+    CPPUNIT_ASSERT_EQUAL(OUString("1"), 
pSettings->GetParameter(SP_RND_STARTING_POINT));
+    CPPUNIT_ASSERT_EQUAL(OUString("80"), 
pSettings->GetParameter(SP_STAGNATION_LIMIT));
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sc/source/core/data/SolverSettings.cxx 
b/sc/source/core/data/SolverSettings.cxx
index 60eb747f55f5..64badb8c2790 100644
--- a/sc/source/core/data/SolverSettings.cxx
+++ b/sc/source/core/data/SolverSettings.cxx
@@ -11,6 +11,7 @@
 #include <global.hxx>
 #include <table.hxx>
 #include <docsh.hxx>
+#include <rtl/math.hxx>
 #include <solverutil.hxx>
 #include <unotools/charclass.hxx>
 #include <SolverSettings.hxx>
@@ -73,6 +74,28 @@ void SolverSettings::Initialize()
     ReadParamValue(SP_LIMIT_BBDEPTH, m_sLimitBBDepth);
     ReadParamValue(SP_TIMEOUT, m_sTimeout);
     ReadParamValue(SP_ALGORITHM, m_sAlgorithm);
+    // Engine options common for DEPS and SCO
+    ReadParamValue(SP_SWARM_SIZE, m_sSwarmSize);
+    ReadParamValue(SP_LEARNING_CYCLES, m_sLearningCycles);
+    ReadParamValue(SP_GUESS_VARIABLE_RANGE, m_sGuessVariableRange);
+    ReadDoubleParamValue(SP_VARIABLE_RANGE_THRESHOLD, 
m_sVariableRangeThreshold);
+    ReadParamValue(SP_ACR_COMPARATOR, m_sUseACRComparator);
+    ReadParamValue(SP_RND_STARTING_POINT, m_sUseRandomStartingPoint);
+    ReadParamValue(SP_STRONGER_PRNG, m_sUseStrongerPRNG);
+    ReadParamValue(SP_STAGNATION_LIMIT, m_sStagnationLimit);
+    ReadDoubleParamValue(SP_STAGNATION_TOLERANCE, m_sTolerance);
+    ReadParamValue(SP_ENHANCED_STATUS, m_sEnhancedSolverStatus);
+    // DEPS Options
+    ReadDoubleParamValue(SP_AGENT_SWITCH_RATE, m_sAgentSwitchRate);
+    ReadDoubleParamValue(SP_SCALING_MIN, m_sScalingFactorMin);
+    ReadDoubleParamValue(SP_SCALING_MAX, m_sScalingFactorMax);
+    ReadDoubleParamValue(SP_CROSSOVER_PROB, m_sCrossoverProbability);
+    ReadDoubleParamValue(SP_COGNITIVE_CONST, m_sCognitiveConstant);
+    ReadDoubleParamValue(SP_SOCIAL_CONST, m_sSocialConstant);
+    ReadDoubleParamValue(SP_CONSTRICTION_COEFF, m_sConstrictionCoeff);
+    ReadDoubleParamValue(SP_MUTATION_PROB, m_sMutationProbability);
+    // SCO Options
+    ReadParamValue(SP_LIBRARY_SIZE, m_sLibrarySize);
 }
 
 // Returns the current value of the parameter in the object as a string
@@ -119,6 +142,63 @@ OUString SolverSettings::GetParameter(SolverParameter 
eParam)
         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 "";
     }
@@ -188,6 +268,75 @@ void SolverSettings::SetParameter(SolverParameter eParam, 
OUString sValue)
                 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;
     }
@@ -321,12 +470,35 @@ void SolverSettings::SaveSolverSettings()
     sal_Int32 nConstrCount = m_aConstraints.size();
     WriteParamValue(SP_CONSTR_COUNT, OUString::number(nConstrCount));
 
+    // Solver engine options
     WriteParamValue(SP_INTEGER, m_sInteger);
     WriteParamValue(SP_NON_NEGATIVE, m_sNonNegative);
     WriteParamValue(SP_EPSILON_LEVEL, m_sEpsilonLevel);
     WriteParamValue(SP_LIMIT_BBDEPTH, m_sLimitBBDepth);
     WriteParamValue(SP_TIMEOUT, m_sTimeout);
     WriteParamValue(SP_ALGORITHM, m_sAlgorithm);
+    // Engine options common for DEPS and SCO
+    WriteParamValue(SP_SWARM_SIZE, m_sSwarmSize);
+    WriteParamValue(SP_LEARNING_CYCLES, m_sLearningCycles);
+    WriteParamValue(SP_GUESS_VARIABLE_RANGE, m_sGuessVariableRange);
+    WriteDoubleParamValue(SP_VARIABLE_RANGE_THRESHOLD, 
m_sVariableRangeThreshold);
+    WriteParamValue(SP_ACR_COMPARATOR, m_sUseACRComparator);
+    WriteParamValue(SP_RND_STARTING_POINT, m_sUseRandomStartingPoint);
+    WriteParamValue(SP_STRONGER_PRNG, m_sUseStrongerPRNG);
+    WriteParamValue(SP_STAGNATION_LIMIT, m_sStagnationLimit);
+    WriteDoubleParamValue(SP_STAGNATION_TOLERANCE, m_sTolerance);
+    WriteParamValue(SP_ENHANCED_STATUS, m_sEnhancedSolverStatus);
+    // DEPS Options
+    WriteDoubleParamValue(SP_AGENT_SWITCH_RATE, m_sAgentSwitchRate);
+    WriteDoubleParamValue(SP_SCALING_MIN, m_sScalingFactorMin);
+    WriteDoubleParamValue(SP_SCALING_MAX, m_sScalingFactorMax);
+    WriteDoubleParamValue(SP_CROSSOVER_PROB, m_sCrossoverProbability);
+    WriteDoubleParamValue(SP_COGNITIVE_CONST, m_sCognitiveConstant);
+    WriteDoubleParamValue(SP_SOCIAL_CONST, m_sSocialConstant);
+    WriteDoubleParamValue(SP_CONSTRICTION_COEFF, m_sConstrictionCoeff);
+    WriteDoubleParamValue(SP_MUTATION_PROB, m_sMutationProbability);
+    // SCO Options
+    WriteParamValue(SP_LIBRARY_SIZE, m_sLibrarySize);
 
     if (m_pDocShell)
         m_pDocShell->SetDocumentModified();
@@ -354,6 +526,26 @@ bool SolverSettings::ReadParamValue(SolverParameter 
eParam, OUString& rValue, bo
     return false;
 }
 
+// Reads a parameter value of type 'double' from the named range and into 
rValue
+bool SolverSettings::ReadDoubleParamValue(SolverParameter eParam, OUString& 
rValue)
+{
+    const auto 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);
+        return true;
+    }
+    return false;
+}
+
 /* Writes a parameter value to the file as a named range.
  * Argument bQuoted indicates whether the value should be enclosed with quotes 
or not (used
  * for string expressions that must be enclosed with quotes)
@@ -375,6 +567,22 @@ void SolverSettings::WriteParamValue(SolverParameter 
eParam, OUString sValue, bo
     m_pRangeName->insert(pNewEntry);
 }
 
+// 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)
+{
+    const auto 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);
+    m_pRangeName->insert(pNewEntry);
+}
+
 void 
SolverSettings::GetEngineOptions(css::uno::Sequence<css::beans::PropertyValue>& 
aOptions)
 {
     sal_Int32 nOptionsSize = aOptions.getLength();
@@ -398,6 +606,12 @@ void 
SolverSettings::GetEngineOptions(css::uno::Sequence<css::beans::PropertyVal
                 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
@@ -438,6 +652,12 @@ void 
SolverSettings::SetEngineOptions(css::uno::Sequence<css::beans::PropertyVal
                 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;

Reply via email to