Skip to content

Mutation Clean Slate #77

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: mutations-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ cmake-build-debug
cmake-build-release
.idea
result
Makefile
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ add_subdirectory(count)
add_subdirectory(ports)
add_subdirectory(hello)
add_subdirectory(power_train)
add_subdirectory(multiport_mutation)
2 changes: 1 addition & 1 deletion examples/count/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using namespace reactor;
using namespace std::chrono_literals;

class Count : public Reactor {
class Count final : public Reactor {
private:
// actions
Timer timer{"timer", this};
Expand Down
2 changes: 1 addition & 1 deletion examples/hello/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using namespace reactor;
using namespace std::chrono_literals;

class Hello : public Reactor {
class Hello final : public Reactor {
private:
// actions
Timer timer{"timer", this, 1s, 2s};
Expand Down
3 changes: 3 additions & 0 deletions examples/multiport_mutation/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_executable(mutation_multiports main.cc)
target_link_libraries(mutation_multiports reactor-cpp)
add_dependencies(examples mutation_multiports)
48 changes: 48 additions & 0 deletions examples/multiport_mutation/consumer.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2025 TU Dresden
* All rights reserved.
*
* Authors:
* Tassilo Tanneberger
*/

#ifndef MULTIPORT_MUTATION_CONSUMER_HH
#define MULTIPORT_MUTATION_CONSUMER_HH

#include <reactor-cpp/reactor-cpp.hh>
#include <reactor-cpp/scopes.hh>

using namespace reactor;
using namespace std::chrono_literals;

class Consumer final : public Reactor { // NOLINT
class Inner : public Scope {
Inner(Reactor* reactor, std::size_t index)
: Scope(reactor)
, index_(index) {}
std::size_t index_ = 0;

void reaction_1(const Input<unsigned>& in) const {
// std::cout << "consumer: " << index_ << " received value:" << *in.get() << '\n';
}

friend Consumer;
};

Inner _lf_inner;
Reaction handle{"handle", 1, this, [this]() { _lf_inner.reaction_1(this->in); }};

public:
Consumer(const std::string& name, Environment* env, std::size_t index)
: Reactor(name, env)
, _lf_inner(this, index) {
std::cout << "creating instance of consumer" << '\n';
}
~Consumer() override { std::cout << "Consumer Object is deleted" << '\n'; };

Input<unsigned> in{"in", this}; // NOLINT

void assemble() override { handle.declare_trigger(&in); }
};

#endif // MULTIPORT_MUTATION_CONSUMER_HH
64 changes: 64 additions & 0 deletions examples/multiport_mutation/load_balancer.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright (C) 2025 TU Dresden
* All rights reserved.
*
* Authors:
* Tassilo Tanneberger
*/

#ifndef MULTIPORT_MUTATION_LOAD_BALANCER_HH
#define MULTIPORT_MUTATION_LOAD_BALANCER_HH

#include <reactor-cpp/mutations/multiport.hh>
#include <reactor-cpp/reactor-cpp.hh>

using namespace reactor;
using namespace std::chrono_literals;

class LoadBalancer final : public Reactor { // NOLINT
class Inner : public MutableScope {
explicit Inner(Reactor* reactor)
: MutableScope(reactor) {}

// reaction bodies
static void reaction_1(const Input<unsigned>& inbound, Output<unsigned>& scale_bank,
Multiport<Output<unsigned>>& outbound) {
if (std::rand() % 15 == 0) { // NOLINT
scale_bank.set(std::rand() % 20 + 1); // NOLINT
}
const unsigned outbound_port = std::rand() % outbound.size(); // NOLINT
outbound[outbound_port].set(inbound.get());
}

friend LoadBalancer;
};

Inner _lf_inner;
Reaction process{"process", 1, this, [this]() { Inner::reaction_1(this->inbound, this->scale_bank, this->out); }};

public:
LoadBalancer(const std::string& name, Environment* env)
: Reactor(name, env)
, _lf_inner(this) {
out.reserve(4);
for (size_t _lf_idx = 0; _lf_idx < 4; _lf_idx++) {
out.create_new_port();
}
}
~LoadBalancer() override = default;

ModifableMultiport<Output<unsigned>> out{"out", this}; // NOLINT
std::size_t out_size_ = 0;

Input<unsigned> inbound{"inbound", this}; // NOLINT
Output<unsigned> scale_bank{"scale_bank", this}; // NOLINT

void assemble() override {
for (auto& _lf_port : out) {
process.declare_antidependency(&_lf_port);
}
process.declare_trigger(&inbound);
}
};

#endif // MULTIPORT_MUTATION_LOAD_BALANCER_HH
92 changes: 92 additions & 0 deletions examples/multiport_mutation/main.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright (C) 2025 TU Dresden
* All rights reserved.
*
* Authors:
* Tassilo Tanneberger
*/

#include <iostream>
#include <memory>

#include <reactor-cpp/reactor-cpp.hh>

#include "./consumer.hh"
#include "./load_balancer.hh"
#include "./multiport_to_bank.hh"
#include "./producer.hh"

class Deployment final : public Reactor { // NOLINT

std::unique_ptr<Producer> producer_;
std::unique_ptr<LoadBalancer> load_balancer_;
std::vector<std::unique_ptr<Consumer>> consumers_;

Reaction scale_bank{"scale_bank", 1, this,
[this]() { this->_inner.reaction_1(this->scale, this->consumers_, load_balancer_->out); }};

class Inner : public MutableScope {
int state = 0;

public:
explicit Inner(Reactor* reactor)
: MutableScope(reactor) {}
void reaction_1(const Input<unsigned>& scale, std::vector<std::unique_ptr<Consumer>>& reactor_bank,
ModifableMultiport<Output<unsigned>>& load_balancer) {
std::size_t new_size = *scale.get();

std::function lambda = [](Environment* env, std::size_t index) {
std::string _lf_inst_name = "consumer_" + std::to_string(index);
return std::make_unique<Consumer>(_lf_inst_name, env, index);
};

std::function get_input_port = [](const std::unique_ptr<Consumer>& consumer) { return &consumer->in; };
const auto rescale = std::make_shared<ResizeMultiportToBank<unsigned, Consumer>>(
&load_balancer, &reactor_bank, get_input_port, lambda, new_size);

add_to_transaction(rescale);

commit_transaction(true);
}

friend LoadBalancer;
};

Inner _inner;

public:
Deployment(const std::string& name, Environment* env)
: Reactor(name, env)
, _inner(this)
, producer_(std::make_unique<Producer>("producer", environment()))
, load_balancer_(std::make_unique<LoadBalancer>("load_balancer", environment())) {
std::cout << "creating instance of deployment" << '\n';
consumers_.reserve(4);
for (size_t _lf_idx = 0; _lf_idx < 4; _lf_idx++) {
std::string _lf_inst_name = "consumer_" + std::to_string(_lf_idx);
consumers_.push_back(std::make_unique<Consumer>(_lf_inst_name, environment(), _lf_idx));
}
}
~Deployment() override = default;

Input<unsigned> scale{"scale", this}; // NOLINT

void assemble() override {
for (size_t _lf_idx = 0; _lf_idx < 4; _lf_idx++) {
environment()->draw_connection(load_balancer_->out[_lf_idx], consumers_[_lf_idx]->in, ConnectionProperties{});
environment()->draw_connection(producer_->value, load_balancer_->inbound, ConnectionProperties{});
}
environment()->draw_connection(load_balancer_->scale_bank, scale, ConnectionProperties{});
scale_bank.declare_trigger(&this->scale);
}
};

auto main() -> int {
Environment env{4, true};
auto deployment = std::make_unique<Deployment>("c1", &env);
env.optimize();
env.assemble();
auto thread = env.startup();
thread.join();
return 0;
}
95 changes: 95 additions & 0 deletions examples/multiport_mutation/multiport_to_bank.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright (C) 2025 TU Dresden
* All rights reserved.
*
* Authors:
* Tassilo Tanneberger
*/

#ifndef MULTIPORT_MUTATION_MULTIPORT_TO_BANK_HH
#define MULTIPORT_MUTATION_MULTIPORT_TO_BANK_HH

#include <reactor-cpp/multiport.hh>
#include <reactor-cpp/mutations.hh>
#include <reactor-cpp/mutations/bank.hh>
#include <reactor-cpp/mutations/connection.hh>
#include <reactor-cpp/mutations/multiport.hh>
#include <reactor-cpp/port.hh>
#include <reactor-cpp/reactor.hh>

#include "../../lib/mutations/bank.cc"
#include "../../lib/mutations/connection.cc"
#include "../../lib/mutations/multiport.cc"

#include <functional>

namespace reactor {

template <class PortType, class ReactorType> class ResizeMultiportToBank : public Mutation {
ModifableMultiport<Output<PortType>>* multiport_;
std::vector<std::unique_ptr<ReactorType>>* bank_;
std::function<Input<PortType>*(const std::unique_ptr<ReactorType>&)> get_input_port_;
std::function<std::unique_ptr<ReactorType>(Environment* env, std::size_t index)> create_lambda_;
std::size_t new_size_ = 0;

public:
ResizeMultiportToBank(ModifableMultiport<Output<PortType>>* multiport,
std::vector<std::unique_ptr<ReactorType>>* bank,
std::function<Input<PortType>*(const std::unique_ptr<ReactorType>&)> get_input_port,
std::function<std::unique_ptr<ReactorType>(Environment* env, std::size_t index)> create_lambda,
std::size_t new_size)
: multiport_(multiport)
, bank_(bank)
, get_input_port_(get_input_port)
, create_lambda_(create_lambda)
, new_size_(new_size) {}

~ResizeMultiportToBank() = default;
auto run() -> MutationResult {
if (multiport_->size() != bank_->size()) {
return NotMatchingBankSize;
}
auto old_size = multiport_->size();

if (new_size_ > old_size) {
auto change_multiport_size = std::make_shared<MutationChangeOutputMultiportSize<unsigned>>(multiport_, new_size_);

change_multiport_size->run();

auto change_bank_size = std::make_shared<MutationChangeBankSize<std::unique_ptr<ReactorType>>>(
bank_, (*bank_)[0]->environment(), new_size_, create_lambda_);

change_bank_size->run();

for (auto i = old_size; i < new_size_; i++) {
auto add_conn = std::make_shared<MutationAddConnection<Output<PortType>, Input<PortType>>>(
&(*multiport_)[i], get_input_port_((*bank_)[i]), (*bank_)[0]->environment(), true);

add_conn->run();
}
} else if (new_size_ < old_size) {
for (auto i = old_size - 1; i >= new_size_; i--) {
auto add_conn = std::make_shared<MutationAddConnection<Output<PortType>, Input<PortType>>>(
&(*multiport_)[i], get_input_port_((*bank_)[i]), (*bank_)[0]->environment(), false);

add_conn->run();
}

auto change_multiport_size = std::make_shared<MutationChangeOutputMultiportSize<unsigned>>(multiport_, new_size_);

change_multiport_size->run();

auto change_bank_size = std::make_shared<MutationChangeBankSize<std::unique_ptr<ReactorType>>>(
bank_, (*bank_)[0]->environment(), new_size_, create_lambda_);

change_bank_size->run();
}

return Success;
}

auto rollback() -> MutationResult { return Success; }
};
} // namespace reactor

#endif // MULTIPORT_MUTATION_MULTIPORT_TO_BANK_HH
55 changes: 55 additions & 0 deletions examples/multiport_mutation/producer.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2025 TU Dresden
* All rights reserved.
*
* Authors:
* Tassilo Tanneberger
*/

#ifndef MULTIPORT_MUTATION_PRODUCER_HH
#define MULTIPORT_MUTATION_PRODUCER_HH

#include <reactor-cpp/reactor-cpp.hh>

using namespace reactor;
using namespace std::chrono_literals;

class Producer final : public Reactor { // NOLINT
private:
Timer timer{"timer", this, 1s, 1s};
Reaction r_timer{"r_timer", 1, this, [this]() { _lf_inner.reaction_1(this->value); }};

class Inner : public Scope {
unsigned int counter_ = 0;

void reaction_1([[maybe_unused]] Output<unsigned>& out) {
// std::cout << "producing value:" << counter_ << "\n";
out.set(counter_++);
}

explicit Inner(Reactor* reactor)
: Scope(reactor) {}

friend Producer;
};

Inner _lf_inner;

public:
Producer(const std::string& name, Environment* env)
: Reactor(name, env)
, _lf_inner(this) {
std::cout << "creating instance of producer\n";
}
Producer() = delete;
~Producer() override = default;

Output<unsigned> value{"value", this}; // NOLINT

void assemble() override {
r_timer.declare_trigger(&timer);
r_timer.declare_antidependency(&value);
}
};

#endif // MULTIPORT_MUTATION_PRODUCER_HH
Loading
Loading