Antares Simulator
Power System Simulator
ForbiddenNodes.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 
22 #pragma once
23 
24 #include <stdexcept>
25 #include <typeindex>
26 #include <unordered_map>
27 #include <unordered_set>
28 
29 #include "antares/expressions/nodes/FunctionNode.h"
30 #include "antares/expressions/nodes/Node.h"
31 
32 namespace Antares::IO::Inputs::ModelConverter
33 {
34 
35 template<typename NodeType>
36 std::type_index forbiddenNodeKey()
37 {
38  static_assert(!std::is_same_v<NodeType, Expressions::Nodes::FunctionNode>,
39  "Use Expressions::Nodes::FunctionNodeType enum values or "
40  "forbiddenNodeKey(Expressions::Nodes::FunctionNodeType) "
41  "instead of FunctionNode for forbidden rules.");
42  return std::type_index(typeid(NodeType));
43 }
44 
45 template<Expressions::Nodes::FunctionNodeType T>
46 std::type_index forbiddenNodeKey()
47 {
48  using Tag = std::integral_constant<Expressions::Nodes::FunctionNodeType, T>;
49  return std::type_index(typeid(Tag));
50 }
51 
52 inline std::type_index forbiddenNodeKey(const Expressions::Nodes::FunctionNodeType& funcType)
53 {
54  switch (funcType)
55  {
56  using NT = Expressions::Nodes::FunctionNodeType;
57  case NT::max:
58  return forbiddenNodeKey<NT::max>();
59  case NT::min:
60  return forbiddenNodeKey<NT::min>();
61  case NT::pow:
62  return forbiddenNodeKey<NT::pow>();
63  case NT::dual:
64  return forbiddenNodeKey<NT::dual>();
65  case NT::reduced_cost:
66  return forbiddenNodeKey<NT::reduced_cost>();
67  default:
68  throw std::runtime_error("ForbiddenNodeKey is not implemented");
69  }
70 }
71 
72 inline std::type_index forbiddenNodeKey(const Expressions::Nodes::Node& node)
73 {
74  if (auto* funcNode = dynamic_cast<const Expressions::Nodes::FunctionNode*>(&node))
75  {
76  return forbiddenNodeKey(funcNode->type());
77  }
78  return {typeid(node)};
79 }
80 
82 {
83 public:
84  // ------------------------- GLOBAL -------------------------
85 
86  template<typename... NodeType>
87  void addGlobalForbidden()
88  {
89  (global_.insert(forbiddenNodeKey<NodeType>()), ...);
90  }
91 
92  template<Expressions::Nodes::FunctionNodeType... NodeType>
93  void addGlobalForbidden()
94  {
95  (global_.insert(forbiddenNodeKey<NodeType>()), ...);
96  }
97 
98  // ---------------------- PARENT -> CHILD --------------------
99  template<Expressions::Nodes::FunctionNodeType Parent, typename Child>
100  requires(!std::is_same_v<Child, Expressions::Nodes::FunctionNodeType>)
101  void addForbiddenFor()
102  {
103  rules_[forbiddenNodeKey<Parent>()].insert(forbiddenNodeKey<Child>());
104  }
105 
106  template<Expressions::Nodes::FunctionNodeType Parent,
107  Expressions::Nodes::FunctionNodeType Child>
108  void addForbiddenFor()
109  {
110  rules_[forbiddenNodeKey<Parent>()].insert(forbiddenNodeKey<Child>());
111  }
112 
113  template<typename Parent, Expressions::Nodes::FunctionNodeType Child>
114  void addForbiddenFor()
115  {
116  rules_[forbiddenNodeKey<Parent>()].insert(forbiddenNodeKey<Child>());
117  }
118 
119  // ---------------------- COMPILE-TIME CHECK ----------------------
120  template<typename Parent, Expressions::Nodes::FunctionNodeType Child>
121  [[nodiscard]] bool isForbiddenFor() const
122  {
123  return check(forbiddenNodeKey<Parent>(), forbiddenNodeKey<Child>());
124  }
125 
126  template<typename Parent, typename Child>
127  [[nodiscard]] bool isForbiddenFor() const
128  {
129  return check(forbiddenNodeKey<Parent>(), forbiddenNodeKey<Child>());
130  }
131 
132  // ---------------------- RUNTIME CHECK ----------------------
133 
134  template<Expressions::Nodes::FunctionNodeType Child>
135  [[nodiscard]] bool isForbiddenFor(const std::type_index& parentKey) const
136  {
137  return check(parentKey, forbiddenNodeKey<Child>());
138  }
139 
140  template<typename Child>
141  [[nodiscard]] bool isForbiddenFor(const std::type_index& parentKey) const
142  {
143  return check(parentKey, forbiddenNodeKey<Child>());
144  }
145 
146  // ---------------------- GLOBALLY FORBIDDEN ----------------------
147 
148  template<typename NodeType>
149  [[nodiscard]] bool isForbidden() const
150  {
151  return global_.contains(forbiddenNodeKey<NodeType>());
152  }
153 
154  template<Expressions::Nodes::FunctionNodeType NodeType>
155  [[nodiscard]] bool isForbidden() const
156  {
157  return global_.contains(forbiddenNodeKey<NodeType>());
158  }
159 
160 private:
161  std::unordered_set<std::type_index> global_;
162  std::unordered_map<std::type_index /* parent */,
163  std::unordered_set<std::type_index> /* children */>
164  rules_;
165 
166  [[nodiscard]] bool check(const std::type_index& parentKey,
167  const std::type_index& childKey) const
168  {
169  // global forbidden child?
170  if (global_.contains(childKey))
171  {
172  return true;
173  }
174 
175  // parent-specific forbidden child?
176  const auto& it = rules_.find(parentKey);
177  if (it == rules_.end())
178  {
179  return false;
180  }
181 
182  return it->second.contains(childKey);
183  }
184 };
185 
186 } // namespace Antares::IO::Inputs::ModelConverter