Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/inc/SolverSettings.hxx
Line
Count
Source
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
#pragma once
12
13
#include <utility>
14
#include <variant>
15
#include <rtl/ustring.hxx>
16
#include <com/sun/star/beans/PropertyValue.hpp>
17
18
#include "document.hxx"
19
#include <docsh.hxx>
20
21
namespace sc
22
{
23
// These values are MS compatible
24
enum ObjectiveType
25
{
26
    OT_MAXIMIZE = 1,
27
    OT_MINIMIZE = 2,
28
    OT_VALUE = 3
29
};
30
31
enum SolverParameter
32
{
33
    SP_OBJ_CELL, // Objective cell
34
    SP_OBJ_TYPE, // Objective type (max, min, value)
35
    SP_OBJ_VAL, // Value (used when objective is of type "value")
36
    SP_VAR_CELLS, // Variable cells
37
    SP_CONSTR_COUNT, // Number of constraints (MSO only)
38
    SP_LO_ENGINE, // Engine name used in LO
39
    SP_MS_ENGINE, // Engine ID used in MSO
40
    SP_INTEGER, // Assume all variables are integer (0: no, 1: yes)
41
    // LpSolve, CoinMP and SwarmSolver
42
    SP_NON_NEGATIVE, // Assume non negativity (1: yes, 2: no)
43
    SP_EPSILON_LEVEL, // Epsilon level
44
    SP_LIMIT_BBDEPTH, // Branch and bound depth
45
    SP_TIMEOUT, // Time limit to return a solution
46
    SP_ALGORITHM, // Algorithm used by the SwarmSolver (1, 2 or 3)
47
    // Engine options common for DEPS and SCO
48
    SP_SWARM_SIZE, // Size of Swarm
49
    SP_LEARNING_CYCLES, // Learning Cycles
50
    SP_GUESS_VARIABLE_RANGE, // Variable Bounds Guessing
51
    SP_VARIABLE_RANGE_THRESHOLD, // Variable Bounds Threshold (when guessing)
52
    SP_ACR_COMPARATOR, // Use ACR Comparator (instead of BCH)
53
    SP_RND_STARTING_POINT, // Use Random starting point
54
    SP_STRONGER_PRNG, // Use a stronger random generator (slower)
55
    SP_STAGNATION_LIMIT, // Stagnation Limit
56
    SP_STAGNATION_TOLERANCE, // Stagnation Tolerance
57
    SP_ENHANCED_STATUS, // Show enhanced solver status
58
    // DEPS Options
59
    SP_AGENT_SWITCH_RATE, // Agent Switch Rate (DE Probability)
60
    SP_SCALING_MIN, // DE: Min Scaling Factor (0-1.2)
61
    SP_SCALING_MAX, // DE: Max Scaling Factor (0-1.2)
62
    SP_CROSSOVER_PROB, // DE: Crossover Probability (0-1)
63
    SP_COGNITIVE_CONST, // Cognitive Constant
64
    SP_SOCIAL_CONST, // Social Constant
65
    SP_CONSTRICTION_COEFF, // PS: Constriction Coefficient
66
    SP_MUTATION_PROB, // Mutation Probability (0-0.005)
67
    // SCO Options
68
    SP_LIBRARY_SIZE, // Size of library
69
};
70
71
// Starts at 1 to maintain MS compatibility
72
enum ConstraintOperator
73
{
74
    CO_LESS_EQUAL = 1,
75
    CO_EQUAL = 2,
76
    CO_GREATER_EQUAL = 3,
77
    CO_INTEGER = 4,
78
    CO_BINARY = 5
79
};
80
81
// Parts of a constraint
82
enum ConstraintPart
83
{
84
    CP_LEFT_HAND_SIDE,
85
    CP_OPERATOR,
86
    CP_RIGHT_HAND_SIDE
87
};
88
89
// Stores the information of a single constraint (condition)
90
struct ModelConstraint
91
{
92
    OUString aLeftStr;
93
    ConstraintOperator nOperator;
94
    OUString aRightStr;
95
96
    ModelConstraint()
97
0
        : nOperator(CO_LESS_EQUAL)
98
0
    {
99
0
    }
100
    bool IsDefault() const
101
0
    {
102
0
        return aLeftStr.isEmpty() && aRightStr.isEmpty() && nOperator == CO_LESS_EQUAL;
103
0
    }
104
};
105
106
/* Class SolverSettings
107
 *
108
 * This class is used to load/save and manipulate solver settings in a Calc tab.
109
 *
110
 * During initialization, (see Initialize() method) all settings stored in the tab are loaded onto
111
 * the object. Settings that are not defined use default values.
112
 *
113
 * Read/Write methods are private and are used internally to load/write solver settings from
114
 * named ranges associated with the sheet.
115
 *
116
 * Get/Set methods are public methods used to change object properties (they do not save data
117
 * to the file).
118
 *
119
 * The method SaveSolverSettings() is used to create the named ranges containing the current
120
 * property values into the file.
121
 *
122
 */
123
124
class SolverSettings
125
{
126
private:
127
    ScTable& m_rTable;
128
    ScDocument& m_rDoc;
129
    ScDocShell* m_pDocShell;
130
131
    // Used to read/write the named ranges in the tab
132
    ScRangeName* m_pRangeName;
133
134
    OUString m_sObjCell;
135
    ObjectiveType m_eObjType;
136
    OUString m_sObjVal;
137
    OUString m_sVariableCells;
138
    OUString m_sLOEngineName;
139
    OUString m_sMSEngineId;
140
141
    // Solver engine options
142
    OUString m_sInteger;
143
    OUString m_sNonNegative;
144
    OUString m_sEpsilonLevel;
145
    OUString m_sLimitBBDepth;
146
    OUString m_sTimeout;
147
    OUString m_sAlgorithm;
148
    // DEPS and SCO
149
    OUString m_sSwarmSize;
150
    OUString m_sLearningCycles;
151
    OUString m_sGuessVariableRange;
152
    OUString m_sVariableRangeThreshold;
153
    OUString m_sUseACRComparator;
154
    OUString m_sUseRandomStartingPoint;
155
    OUString m_sUseStrongerPRNG;
156
    OUString m_sStagnationLimit;
157
    OUString m_sTolerance;
158
    OUString m_sEnhancedSolverStatus;
159
    // DEPS only
160
    OUString m_sAgentSwitchRate;
161
    OUString m_sScalingFactorMin;
162
    OUString m_sScalingFactorMax;
163
    OUString m_sCrossoverProbability;
164
    OUString m_sCognitiveConstant;
165
    OUString m_sSocialConstant;
166
    OUString m_sConstrictionCoeff;
167
    OUString m_sMutationProbability;
168
    // SCO only
169
    OUString m_sLibrarySize;
170
171
    std::vector<ModelConstraint> m_aConstraints;
172
173
    void Initialize();
174
175
    // Used to create or read a single solver parameter based on its named range
176
    bool ReadParamValue(SolverParameter eParam, OUString& rValue, bool bRemoveQuotes = false);
177
    bool ReadDoubleParamValue(SolverParameter eParam, OUString& rValue);
178
    void WriteParamValue(SolverParameter eParam, OUString sValue, bool bQuoted = false);
179
    void WriteDoubleParamValue(SolverParameter eParam, std::u16string_view sValue);
180
181
    // Creates or reads all constraints stored in named ranges
182
    void ReadConstraints();
183
    void WriteConstraints();
184
185
    // Used to create or get a single constraint part
186
    bool ReadConstraintPart(ConstraintPart ePart, tools::Long nIndex, OUString& rValue);
187
    void WriteConstraintPart(ConstraintPart ePart, tools::Long nIndex, const OUString& sValue);
188
189
    // Creates or reads all named ranges associated with solver engine options
190
    void ReadEngine();
191
    void WriteEngine();
192
193
    void DeleteAllNamedRanges();
194
195
    // Maps solver parameters to named ranges
196
    std::map<SolverParameter, OUString> m_mNamedRanges
197
        = { { SP_OBJ_CELL, "solver_opt" },
198
            { SP_OBJ_TYPE, "solver_typ" },
199
            { SP_OBJ_VAL, "solver_val" },
200
            { SP_VAR_CELLS, "solver_adj" },
201
            { SP_CONSTR_COUNT, "solver_num" },
202
            { SP_LO_ENGINE, "solver_lo_eng" },
203
            { SP_MS_ENGINE, "solver_eng" },
204
            { SP_INTEGER, "solver_int" },
205
            { SP_NON_NEGATIVE, "solver_neg" },
206
            { SP_EPSILON_LEVEL, "solver_eps" },
207
            { SP_LIMIT_BBDEPTH, "solver_bbd" },
208
            { SP_TIMEOUT, "solver_tim" },
209
            { SP_ALGORITHM, "solver_alg" },
210
            { SP_SWARM_SIZE, "solver_ssz" },
211
            { SP_LEARNING_CYCLES, "solver_lcy" },
212
            { SP_GUESS_VARIABLE_RANGE, "solver_gvr" },
213
            { SP_VARIABLE_RANGE_THRESHOLD, "solver_vrt" },
214
            { SP_ACR_COMPARATOR, "solver_acr" },
215
            { SP_RND_STARTING_POINT, "solver_rsp" },
216
            { SP_STRONGER_PRNG, "solver_prng" },
217
            { SP_STAGNATION_LIMIT, "solver_slim" },
218
            { SP_STAGNATION_TOLERANCE, "solver_stol" },
219
            { SP_ENHANCED_STATUS, "solver_enst" },
220
            { SP_AGENT_SWITCH_RATE, "solver_asr" },
221
            { SP_SCALING_MIN, "solver_smin" },
222
            { SP_SCALING_MAX, "solver_smax" },
223
            { SP_CROSSOVER_PROB, "solver_crpb" },
224
            { SP_COGNITIVE_CONST, "solver_cog" },
225
            { SP_SOCIAL_CONST, "solver_soc" },
226
            { SP_CONSTRICTION_COEFF, "solver_ccoeff" },
227
            { SP_MUTATION_PROB, "solver_mtpb" },
228
            { SP_LIBRARY_SIZE, "solver_lbsz" } };
229
230
    // Maps LO solver implementation names to MS engine codes
231
    std::map<OUString, OUString> SolverNamesToExcelEngines = {
232
        { "com.sun.star.comp.Calc.CoinMPSolver", "2" }, // Simplex LP
233
        { "com.sun.star.comp.Calc.LpsolveSolver", "2" }, // Simplex LP
234
        { "com.sun.star.comp.Calc.SwarmSolver", "1" }, // GRG Nonlinear
235
        { "com.sun.star.comp.Calc.NLPSolver.DEPSSolverImpl", "3" }, // DEPS
236
        { "com.sun.star.comp.Calc.NLPSolver.SCOSolverImpl", "3" } // SCO
237
    };
238
239
    // Maps MS solver engine codes to LO solver implementation names
240
    std::map<OUString, OUString> SolverCodesToLOEngines = {
241
        { "1", "com.sun.star.comp.Calc.SwarmSolver" }, // GRG Nonlinear
242
        { "2", "com.sun.star.comp.Calc.CoinMPSolver" }, // Simplex LP
243
        { "3", "com.sun.star.comp.Calc.SwarmSolver" } // Evolutionary
244
    };
245
246
    // Maps LO solver parameters to named ranges to be used
247
    // NonNegative: for MS compatibility, use 1 for selected and 2 for not selected
248
    typedef std::vector<std::variant<OUString, SolverParameter>> TParamInfo;
249
    std::map<OUString, TParamInfo> SolverParamNames
250
        = { { u"Integer"_ustr, { SP_INTEGER, "solver_int", "bool" } },
251
            { u"NonNegative"_ustr, { SP_NON_NEGATIVE, "solver_neg", "bool" } },
252
            { u"EpsilonLevel"_ustr, { SP_EPSILON_LEVEL, "solver_eps", "int" } },
253
            { u"LimitBBDepth"_ustr, { SP_LIMIT_BBDEPTH, "solver_bbd", "bool" } },
254
            { u"Timeout"_ustr, { SP_TIMEOUT, "solver_tim", "int" } },
255
            { u"Algorithm"_ustr, { SP_ALGORITHM, "solver_alg", "int" } },
256
            // SCO and DEPS
257
            { u"AssumeNonNegative"_ustr, { SP_NON_NEGATIVE, "solver_neg", "bool" } },
258
            { u"SwarmSize"_ustr, { SP_SWARM_SIZE, "solver_ssz", "int" } },
259
            { u"LearningCycles"_ustr, { SP_LEARNING_CYCLES, "solver_lcy", "int" } },
260
            { u"GuessVariableRange"_ustr, { SP_GUESS_VARIABLE_RANGE, "solver_gvr", "bool" } },
261
            { u"VariableRangeThreshold"_ustr,
262
              { SP_VARIABLE_RANGE_THRESHOLD, "solver_vrt", "double" } },
263
            { u"UseACRComparator"_ustr, { SP_ACR_COMPARATOR, "solver_acr", "bool" } },
264
            { u"UseRandomStartingPoint"_ustr, { SP_RND_STARTING_POINT, "solver_rsp", "bool" } },
265
            { u"UseStrongerPRNG"_ustr, { SP_STRONGER_PRNG, "solver_prng", "bool" } },
266
            { u"StagnationLimit"_ustr, { SP_STAGNATION_LIMIT, "solver_slim", "int" } },
267
            { u"Tolerance"_ustr, { SP_STAGNATION_TOLERANCE, "solver_stol", "double" } },
268
            { u"EnhancedSolverStatus"_ustr, { SP_ENHANCED_STATUS, "solver_enst", "bool" } },
269
            // DEPS only
270
            { u"AgentSwitchRate"_ustr, { SP_AGENT_SWITCH_RATE, "solver_asr", "double" } },
271
            { u"DEFactorMin"_ustr, { SP_SCALING_MIN, "solver_smin", "double" } },
272
            { u"DEFactorMax"_ustr, { SP_SCALING_MAX, "solver_smax", "double" } },
273
            { u"DECR"_ustr, { SP_CROSSOVER_PROB, "solver_crpb", "double" } },
274
            { u"PSC1"_ustr, { SP_COGNITIVE_CONST, "solver_cog", "double" } },
275
            { u"PSC2"_ustr, { SP_SOCIAL_CONST, "solver_soc", "double" } },
276
            { u"PSWeight"_ustr, { SP_CONSTRICTION_COEFF, "solver_ccoeff", "double" } },
277
            { u"PSCL"_ustr, { SP_MUTATION_PROB, "solver_mtpb", "double" } },
278
            // SCO only
279
            { u"LibrarySize"_ustr, { SP_LIBRARY_SIZE, "solver_lbsz", "int" } } };
280
281
    // Stores the roots used for named ranges of constraint parts
282
    // Items here must be in the same order as in ConstraintPart enum
283
    std::vector<OUString> m_aConstraintParts{ u"solver_lhs"_ustr, u"solver_rel"_ustr,
284
                                              u"solver_rhs"_ustr };
285
286
public:
287
    /* A SolverSettings object is linked to the ScTable where solver parameters
288
     *  are located and saved to */
289
    SolverSettings(ScTable& pTable);
290
291
    SC_DLLPUBLIC OUString GetParameter(SolverParameter eParam);
292
    SC_DLLPUBLIC void SetParameter(SolverParameter eParam, const OUString& sValue);
293
0
    SC_DLLPUBLIC ObjectiveType GetObjectiveType() { return m_eObjType; }
294
    SC_DLLPUBLIC void SetObjectiveType(ObjectiveType eType);
295
    SC_DLLPUBLIC void GetEngineOptions(css::uno::Sequence<css::beans::PropertyValue>& aOptions);
296
    SC_DLLPUBLIC void
297
    SetEngineOptions(const css::uno::Sequence<css::beans::PropertyValue>& aOptions);
298
0
    SC_DLLPUBLIC const std::vector<ModelConstraint>& GetConstraints() { return m_aConstraints; }
299
    SC_DLLPUBLIC void SetConstraints(std::vector<ModelConstraint> aConstraints);
300
301
    SC_DLLPUBLIC void SaveSolverSettings();
302
    SC_DLLPUBLIC void ResetToDefaults();
303
    SC_DLLPUBLIC bool TabHasSolverModel();
304
};
305
306
} // namespace sc
307
308
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */