Antares Simulator
Power System Simulator
EvalVisitor.h
1 /*
2 ** Copyright 2007-2025, RTE (https://www.rte-france.com)
3 ** See AUTHORS.txt
4 ** SPDX-License-Identifier: MPL-2.0
5 ** This file is part of Antares-Simulator,
6 ** Adequacy and Performance assessment for interconnected energy networks.
7 **
8 ** Antares_Simulator is free software: you can redistribute it and/or modify
9 ** it under the terms of the Mozilla Public Licence 2.0 as published by
10 ** the Mozilla Foundation, either version 2 of the License, or
11 ** (at your option) any later version.
12 **
13 ** Antares_Simulator is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ** Mozilla Public Licence 2.0 for more details.
17 **
18 ** You should have received a copy of the Mozilla Public Licence 2.0
19 ** along with Antares_Simulator. If not, see <https://opensource.org/license/mpl-2-0/>.
20 */
21 #pragma once
22 
23 #include <functional>
24 #include <sstream>
25 #include <variant>
26 
27 #include <antares/optimisation/linear-problem-api/ILinearProblemData.h>
28 #include "antares/expressions/visitors/NodeVisitor.h"
29 #include "antares/modeler-optimisation-container/EvaluationContext.h"
30 #include "antares/modeler-optimisation-container/OptimEntityContainer.h"
31 #include "antares/solver/optim-model-filler/Dimensions.h"
32 #include "antares/study/system-model/component.h"
33 
34 #include "VariadicNodeFunctionVisit.h"
35 
36 namespace Antares::Expressions::Visitors
37 {
38 
39 class EvalVisitorDivisionException: public std::runtime_error
40 {
41 public:
42  EvalVisitorDivisionException(double left, double right, const std::string& message);
43 };
44 
45 class EvalVisitorNotImplemented: public std::invalid_argument
46 {
47 public:
48  EvalVisitorNotImplemented(const std::string& visitor, const std::string& node);
49 };
50 
51 static constexpr double DEFAULT_THRESHOLD = 1e-16;
52 
54 {
55 public:
56  explicit EvaluationResult(double value);
57 
58  explicit EvaluationResult(const std::vector<double>& values);
59 
60  EvaluationResult operator+(const EvaluationResult& right) const
61  {
62  return evaluateBinaryOperation(right, std::plus<>());
63  }
64 
65  EvaluationResult operator+=(const EvaluationResult& right)
66  {
67  *this = *this + right;
68  return *this;
69  }
70 
71  EvaluationResult operator-(const EvaluationResult& right) const
72  {
73  return evaluateBinaryOperation(right, std::minus<>());
74  }
75 
76  EvaluationResult operator*(const EvaluationResult& right) const
77  {
78  return evaluateBinaryOperation(right, std::multiplies<>());
79  }
80 
81  EvaluationResult operator==(const EvaluationResult& right) const
82  {
83  return evaluateBinaryOperation(right, std::equal_to<>());
84  }
85 
86  EvaluationResult operator<=(const EvaluationResult& right) const
87  {
88  return evaluateBinaryOperation(right, std::less_equal<>());
89  }
90 
91  EvaluationResult operator>=(const EvaluationResult& right) const
92  {
93  return evaluateBinaryOperation(right, std::greater_equal<>());
94  }
95 
96  size_t size() const;
97  double value(unsigned i) const;
98 
99  struct SafeDivides
100  {
101  explicit SafeDivides(double threshold = DEFAULT_THRESHOLD):
102  threshold_(threshold)
103  {
104  }
105 
106  double operator()(double lhs, double rhs) const
107  {
108  if (std::abs(rhs) <= threshold_)
109  {
110  throw EvalVisitorDivisionException(lhs, rhs, "Division by zero");
111  }
112  return lhs / rhs;
113  }
114 
115  private:
116  double threshold_;
117  };
118 
119  EvaluationResult operator/(const EvaluationResult& right) const
120  {
121  return evaluateBinaryOperation(right, SafeDivides{});
122  }
123 
124  EvaluationResult operator-() const
125  {
126  return evaluateUnaryOperation(std::negate<>());
127  }
128 
129  [[nodiscard]] const std::variant<double, std::vector<double>>& value() const
130  {
131  return value_;
132  }
133 
134  class EvalResultTypeError: public std::runtime_error
135  {
136  public:
137  using std::runtime_error::runtime_error;
138  };
139 
140  class EvalResultTimeIndexOutOfRange: public std::out_of_range
141  {
142  public:
143  using std::out_of_range::out_of_range;
144  };
145 
146  double valueAsDouble() const
147  {
148  if (!std::holds_alternative<double>(value_))
149  {
150  throw EvalResultTypeError("Expected a double but found a vector.");
151  }
152  return std::get<double>(value_);
153  }
154 
155  [[nodiscard]] std::vector<double> valuesAsVector() const
156  {
157  if (const auto* v = std::get_if<std::vector<double>>(&value_))
158  {
159  return *v;
160  }
161  throw EvalResultTypeError("Expected a vector but found a double.");
162  }
163 
164  [[nodiscard]] double getValueInVector(unsigned index) const
165  {
166  if (const auto* v = std::get_if<std::vector<double>>(&value_))
167  {
168  return (*v)[index];
169  }
170  throw EvalResultTypeError("Expected a vector but found a double.");
171  }
172 
173  EvaluationResult operator[](int timeIndex) const;
174  EvaluationResult timeShift(int time_shift) const;
175  EvaluationResult timeSum(int from, int to) const;
176  EvaluationResult alltimeSum(int numberOfTimeStep) const;
177 
178  template<typename Op>
179  EvaluationResult evaluateBinaryOperation(const EvaluationResult& right, Op op) const;
180 
181 private:
182  std::variant<double, std::vector<double>> value_;
183  explicit EvaluationResult(const std::variant<double, std::vector<double>>& value);
184 
185  template<typename Op>
186  EvaluationResult evaluateUnaryOperation(Op op) const;
187 
188  static double shift(double value, int)
189  {
190  return value;
191  }
192 
193  static std::vector<double> shift(const std::vector<double>& values, int shiftValue);
194 };
195 
196 template<typename BinaryOp>
197 double computeBinaryOperation(double lhs, double rhs, BinaryOp op)
198 {
199  return op(lhs, rhs);
200 }
201 
202 template<typename BinaryOp>
203 std::vector<double> computeBinaryOperation(const std::vector<double>& lhs, double rhs, BinaryOp op)
204 {
205  auto result(lhs);
206  for (double& value: result)
207  {
208  value = op(value, rhs);
209  }
210  return result;
211 }
212 
213 template<typename BinaryOp>
214 std::vector<double> computeBinaryOperation(double lhs, const std::vector<double>& rhs, BinaryOp op)
215 {
216  std::vector<double> result(rhs.size());
217  for (size_t i = 0; i < rhs.size(); ++i)
218  {
219  result[i] = op(lhs, rhs[i]);
220  }
221  return result;
222 }
223 
224 class VectorsMismatchSize final: public std::runtime_error
225 {
226 public:
227  using std::runtime_error::runtime_error;
228 };
229 
230 template<typename BinaryOp>
231 std::vector<double> computeBinaryOperation(const std::vector<double>& lhs,
232  const std::vector<double>& rhs,
233  BinaryOp op)
234 {
235  if (lhs.size() != rhs.size())
236  {
237  std::ostringstream errorMsg;
238  errorMsg << "Failed to compute binary operation: vectors have different sizes ("
239  << lhs.size() << " and " << rhs.size() << ").";
240  throw VectorsMismatchSize(errorMsg.str());
241  }
242 
243  std::vector<double> result(lhs.size());
244  for (size_t i = 0; i < lhs.size(); ++i)
245  {
246  result[i] = op(lhs[i], rhs[i]);
247  }
248  return result;
249 }
250 
251 template<typename Op>
252 EvaluationResult EvaluationResult::evaluateBinaryOperation(const EvaluationResult& right,
253  Op op) const
254 {
255  return EvaluationResult(
256  std::visit([&op](const auto& l, const auto& r) -> std::variant<double, std::vector<double>>
257  { return computeBinaryOperation(l, r, op); },
258  value_,
259  right.value_));
260 }
261 
262 template<typename UnaryOp>
263 std::vector<double> computeUnaryOperation(const std::vector<double>& values, UnaryOp op)
264 {
265  auto result(values);
266  for (double& v: result)
267  {
268  v = op(v);
269  }
270  return result;
271 }
272 
273 template<typename UnaryOp>
274 double computeUnaryOperation(double value, UnaryOp op)
275 {
276  return op(value);
277 }
278 
279 template<typename Op>
280 EvaluationResult EvaluationResult::evaluateUnaryOperation(Op op) const
281 {
282  return EvaluationResult(
283  std::visit([&op](const auto& v) -> std::variant<double, std::vector<double>>
284  { return computeUnaryOperation(v, op); },
285  value_));
286 }
287 
288 template<class Operation>
289 EvaluationResult applyOperation(const std::vector<EvaluationResult>& in, Operation op)
290 {
291  if (in.size() < 2)
292  {
293  throw std::invalid_argument("Expected at least two EvaluationResult");
294  }
295  const size_t size = getMaxSize(in);
296  std::vector<double> values(size);
297  std::vector<double> row(in.size());
298 
299  for (size_t timeIndex = 0; timeIndex < size; ++timeIndex)
300  {
301  for (size_t evalIndex = 0; evalIndex < in.size(); ++evalIndex)
302  {
303  const auto& evalResult = in[evalIndex];
304  row[evalIndex] = evalResult.value(timeIndex);
305  }
306  values[timeIndex] = op(row);
307  }
308  if (size > 1)
309  {
310  return EvaluationResult(values);
311  }
312 
313  return EvaluationResult(values.at(0));
314 }
315 
319 class EvalVisitor: public NodeVisitor<EvaluationResult>
320 {
321 public:
329  explicit EvalVisitor(const Optimisation::OptimEntityContainer& optimContainer,
331  const ModelerStudy::SystemModel::Component& component);
332 
333  std::string name() const override;
334 
335 private:
336  const Optimisation::OptimEntityContainer& optimContainer_;
337  const Optimisation::EvaluationContext& evalContext_;
339  const ModelerStudy::SystemModel::Component& component_;
340 
341  EvaluationResult visit(const Nodes::SumNode* node) override;
342  EvaluationResult visit(const Nodes::SubtractionNode* node) override;
343  EvaluationResult visit(const Nodes::MultiplicationNode* node) override;
344  EvaluationResult visit(const Nodes::DivisionNode* node) override;
345  EvaluationResult visit(const Nodes::EqualNode* node) override;
346  EvaluationResult visit(const Nodes::LessThanOrEqualNode* node) override;
347  EvaluationResult visit(const Nodes::GreaterThanOrEqualNode* node) override;
348  EvaluationResult visit(const Nodes::NegationNode* node) override;
349  EvaluationResult visit(const Nodes::VariableNode* node) override;
350  EvaluationResult visit(const Nodes::ParameterNode* node) override;
351  EvaluationResult visit(const Nodes::LiteralNode* node) override;
352  EvaluationResult visit(const Nodes::PortFieldNode* node) override;
353  EvaluationResult visit(const Nodes::PortFieldSumNode* node) override;
354  EvaluationResult visit(const Nodes::TimeShiftNode* node) override;
355  EvaluationResult visit(const Nodes::TimeIndexNode* node) override;
356  EvaluationResult visit(const Nodes::TimeSumNode* node) override;
357  EvaluationResult visit(const Nodes::AllTimeSumNode* node) override;
358  EvaluationResult visit(const Nodes::FunctionNode* node) override;
359 
360  EvaluationResult handleReducedCost(const Nodes::FunctionNode* node);
361  EvaluationResult handleDual(const Nodes::FunctionNode* node);
362  EvaluationResult handlePow(const Nodes::FunctionNode* node);
363 };
364 } // namespace Antares::Expressions::Visitors
Represents a AllTimeSumNode node in a syntax tree.
Definition: AllTimeSumNode.h:31
Represents a division node in a syntax tree.
Definition: DivisionNode.h:31
Represents an equality comparison node in a syntax tree.
Definition: EqualNode.h:31
AST node representing a function expression (max, min, pow, ...).
Definition: FunctionNode.h:63
Represents a greater than or equal comparison node in a syntax tree.
Definition: GreaterThanOrEqualNode.h:31
Represents a less than or equal comparison node in a syntax tree.
Definition: LessThanOrEqualNode.h:31
Represents a literal node in a syntax tree, storing a double value.
Definition: LiteralNode.h:11
Represents a multiplication node in a syntax tree.
Definition: MultiplicationNode.h:31
Represents a negation node in a syntax tree.
Definition: NegationNode.h:31
Represents a parameter node in a syntax tree, storing a string value.
Definition: ParameterNode.h:14
Represents a port field node in a syntax tree.
Definition: PortFieldNode.h:32
Represents a port field node where the expression is a sum.
Definition: PortFieldSumNode.h:32
Represents a subtraction node in a syntax tree.
Definition: SubtractionNode.h:31
Definition: SumNode.h:29
Definition: TimeIndexNode.h:28
Definition: TimeShiftNode.h:29
Definition: TimeSumNode.h:28
Represents a variable node in a syntax tree, storing a string value.
Definition: VariableNode.h:20
Represents a visitor for evaluating expressions within a given context.
Definition: EvalVisitor.h:320
EvalVisitor(const Optimisation::OptimEntityContainer &optimContainer, const Optimisation::LinearProblemApi::FillContext &fillContext, const ModelerStudy::SystemModel::Component &component)
Constructs an evaluation visitor with the specified context.
Definition: EvalVisitor.cpp:35
Represents the context for evaluating expressions.
Definition: EvaluationContext.h:25
Context for filling linear problem data. Contains temporal information.
Definition: ILinearProblemData.h:35
Definition: OptimEntityContainer.h:46