Skip to content

Commit

Permalink
Component Filler (2.3) [ANT-2305] (#2504)
Browse files Browse the repository at this point in the history
Signed-off-by: Peter Mitri <[email protected]>
Co-authored-by: Guillaume PIERRE <[email protected]>
Co-authored-by: payetvin <[email protected]>
Co-authored-by: Florian OMNES <[email protected]>
  • Loading branch information
4 people authored Dec 6, 2024
1 parent 2fc0ada commit 6b0c5ca
Show file tree
Hide file tree
Showing 32 changed files with 1,894 additions and 23 deletions.
1 change: 1 addition & 0 deletions src/solver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ add_subdirectory(simulation)
add_subdirectory(ts-generator)
add_subdirectory(utils)
add_subdirectory(variable)
add_subdirectory(optim-model-filler)

#
# Resource file for Windows
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ class NodeRegistry
{
public:
NodeRegistry() = default;
NodeRegistry(Antares::Solver::Nodes::Node* node,
Antares::Solver::Registry<Antares::Solver::Nodes::Node> registry);
NodeRegistry(Nodes::Node* node, Registry<Nodes::Node> registry);

// Shallow copy
NodeRegistry(NodeRegistry&&) = default;
NodeRegistry& operator=(NodeRegistry&&) = default;

Antares::Solver::Nodes::Node* node;
Antares::Solver::Registry<Antares::Solver::Nodes::Node> registry;
Nodes::Node* node;
Registry<Nodes::Node> registry;
};
} // namespace Antares::Solver
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ namespace Antares::Solver::Modeler::Api
/**
* Linear Problem
* This class is aimed at creating and manipulating variables/constraints
* Also used to to control the objective, maximization or minimization, and to solve the problem
* Also used to control the objective, maximization or minimization, and to solve the problem
*/
class ILinearProblem
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ namespace Antares::Solver::Modeler::Api

class IMipVariable: public IHasBounds, public IHasName
{
public:
virtual bool isInteger() const = 0;
};

} // namespace Antares::Solver::Modeler::Api
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class OrtoolsMipVariable final: public Api::IMipVariable

const std::string& getName() const override;

bool isInteger() const override;

const operations_research::MPVariable* getMpVar() const;

~OrtoolsMipVariable() override = default;
Expand Down
5 changes: 5 additions & 0 deletions src/solver/modeler/ortoolsImpl/mipVariable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,9 @@ const std::string& OrtoolsMipVariable::getName() const
return mpVar_->name();
}

bool OrtoolsMipVariable::isInteger() const
{
return mpVar_->integer();
}

} // namespace Antares::Solver::Modeler::OrtoolsImpl
29 changes: 29 additions & 0 deletions src/solver/optim-model-filler/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
set(PROJ optim-model-filler)

set(SRC_optim_model_filler
include/antares/solver/optim-model-filler/ComponentFiller.h
include/antares/solver/optim-model-filler/LinearExpression.h
include/antares/solver/optim-model-filler/ReadLinearConstraintVisitor.h
include/antares/solver/optim-model-filler/ReadLinearExpressionVisitor.h
ComponentFiller.cpp
LinearExpression.cpp
ReadLinearConstraintVisitor.cpp
ReadLinearExpressionVisitor.cpp
)

add_library(${PROJ} ${SRC_optim_model_filler})
add_library(Antares::${PROJ} ALIAS ${PROJ})

set_target_properties(${PROJ} PROPERTIES LINKER_LANGUAGE CXX)

target_link_libraries(${PROJ}
PRIVATE
Antares::solver-expressions
Antares::antares-study-system-model
Antares::modeler_api
)

target_include_directories(${PROJ}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
95 changes: 95 additions & 0 deletions src/solver/optim-model-filler/ComponentFiller.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright 2007-2024, RTE (https://www.rte-france.com)
* See AUTHORS.txt
* SPDX-License-Identifier: MPL-2.0
* This file is part of Antares-Simulator,
* Adequacy and Performance assessment for interconnected energy networks.
*
* Antares_Simulator is free software: you can redistribute it and/or modify
* it under the terms of the Mozilla Public Licence 2.0 as published by
* the Mozilla Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* Antares_Simulator is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Mozilla Public Licence 2.0 for more details.
*
* You should have received a copy of the Mozilla Public Licence 2.0
* along with Antares_Simulator. If not, see <https://opensource.org/license/mpl-2-0/>.
*/

#include <ranges>

#include <antares/solver/expressions/nodes/ExpressionsNodes.h>
#include <antares/solver/expressions/visitors/EvalVisitor.h>
#include <antares/solver/optim-model-filler/ComponentFiller.h>
#include <antares/solver/optim-model-filler/ReadLinearConstraintVisitor.h>
#include <antares/study/system-model/variable.h>

namespace Antares::Optimization
{

ComponentFiller::ComponentFiller(const Study::SystemModel::Component& component):
component_(component),
evaluationContext_(component_.getParameterValues(), {})
{
}

void ComponentFiller::addVariables(Solver::Modeler::Api::ILinearProblem& pb,
Solver::Modeler::Api::LinearProblemData& data,
Solver::Modeler::Api::FillContext& ctx)
{
auto evaluator = std::make_unique<Solver::Visitors::EvalVisitor>(evaluationContext_);
for (const auto& variable: component_.getModel()->Variables() | std::views::values)
{
pb.addVariable(evaluator->dispatch(variable.LowerBound().RootNode()),
evaluator->dispatch(variable.UpperBound().RootNode()),
variable.Type() != Study::SystemModel::ValueType::FLOAT,
component_.Id() + "." + variable.Id());
}
}

void ComponentFiller::addConstraints(Solver::Modeler::Api::ILinearProblem& pb,
Solver::Modeler::Api::LinearProblemData& data,
Solver::Modeler::Api::FillContext& ctx)
{
ReadLinearConstraintVisitor visitor(evaluationContext_);
for (const auto& constraint: component_.getModel()->getConstraints() | std::views::values)
{
auto linear_constraint = visitor.dispatch(constraint.expression().RootNode());
auto* ct = pb.addConstraint(linear_constraint.lb,
linear_constraint.ub,
component_.Id() + "." + constraint.Id());
for (auto [var_id, coef]: linear_constraint.coef_per_var)
{
auto* variable = pb.getVariable(component_.Id() + "." + var_id);
ct->setCoefficient(variable, coef);
}
}
}

void ComponentFiller::addObjective(Solver::Modeler::Api::ILinearProblem& pb,
Solver::Modeler::Api::LinearProblemData& data,
Solver::Modeler::Api::FillContext& ctx)
{
if (component_.getModel()->Objective().Empty())
{
return;
}
ReadLinearExpressionVisitor visitor(evaluationContext_);
auto linear_expression = visitor.dispatch(component_.getModel()->Objective().RootNode());
if (abs(linear_expression.offset()) > 1e-10)
{
throw std::invalid_argument("Antares does not support objective offsets (found in model '"
+ component_.getModel()->Id() + "' of component '"
+ component_.Id() + "').");
}
for (auto [var_id, coef]: linear_expression.coefPerVar())
{
auto* variable = pb.getVariable(component_.Id() + "." + var_id);
pb.setObjectiveCoefficient(variable, coef);
}
}

} // namespace Antares::Optimization
120 changes: 120 additions & 0 deletions src/solver/optim-model-filler/LinearExpression.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright 2007-2024, RTE (https://www.rte-france.com)
* See AUTHORS.txt
* SPDX-License-Identifier: MPL-2.0
* This file is part of Antares-Simulator,
* Adequacy and Performance assessment for interconnected energy networks.
*
* Antares_Simulator is free software: you can redistribute it and/or modify
* it under the terms of the Mozilla Public Licence 2.0 as published by
* the Mozilla Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* Antares_Simulator is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Mozilla Public Licence 2.0 for more details.
*
* You should have received a copy of the Mozilla Public Licence 2.0
* along with Antares_Simulator. If not, see <https://opensource.org/license/mpl-2-0/>.
*/

#include <stdexcept>

#include <antares/solver/optim-model-filler/LinearExpression.h>

namespace Antares::Optimization
{

/**
* Element-wise sum of two [string, double] maps, preceded an element-wise multiplication of the
* right-hand-side map. Keys that do not exist in one of the two maps are considered to have a zero
* value. For every key: value = left_value + rhs_multiplier * right_value
* @param left The left hand side map
* @param right The right hand side map
* @param rhs_multiplier The multiplier to apply to the right hand side map
* @return The map resulting from the operation
*/
static std::map<std::string, double> add_maps(const std::map<std::string, double>& left,
const std::map<std::string, double>& right,
double rhs_multiplier)
{
std::map result(left);
for (auto [key, value]: right)
{
if (result.contains(key))
{
result[key] += rhs_multiplier * value;
}
else
{
result[key] = rhs_multiplier * value;
}
}
return result;
}

/**
* Element-wise multiplication of a map by a scale.
* For every key: final_value = scale * initial_value
* @param map The [string, double] map to scale
* @param scale The scale
* @return The scaled map
*/
static std::map<std::string, double> scale_map(const std::map<std::string, double>& map,
double scale)
{
std::map<std::string, double> result;
for (auto [key, value]: map)
{
result[key] = scale * value;
}
return result;
}

LinearExpression::LinearExpression(double offset, std::map<std::string, double> coef_per_var):
offset_(offset),
coef_per_var_(std::move(coef_per_var))
{
}

LinearExpression LinearExpression::operator+(const LinearExpression& other) const
{
return {offset_ + other.offset_, add_maps(coef_per_var_, other.coef_per_var_, 1)};
}

LinearExpression LinearExpression::operator-(const LinearExpression& other) const
{
return {offset_ - other.offset_, add_maps(coef_per_var_, other.coef_per_var_, -1)};
}

LinearExpression LinearExpression::operator*(const LinearExpression& other) const
{
if (coef_per_var_.empty())
{
return {offset_ * other.offset_, scale_map(other.coef_per_var_, offset_)};
}
else if (other.coef_per_var_.empty())
{
return {offset_ * other.offset_, scale_map(coef_per_var_, other.offset_)};
}
else
{
throw std::invalid_argument("A linear expression can't have quadratic terms.");
}
}

LinearExpression LinearExpression::operator/(const LinearExpression& other) const
{
if (!other.coef_per_var_.empty())
{
throw std::invalid_argument("A linear expression can't have a variable as a dividend.");
}
return LinearExpression(offset_ / other.offset_, scale_map(coef_per_var_, 1 / other.offset_));
}

LinearExpression LinearExpression::negate() const
{
return {-offset_, scale_map(coef_per_var_, -1)};
}
} // namespace Antares::Optimization
Loading

0 comments on commit 6b0c5ca

Please sign in to comment.