Skip to content
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
10 changes: 10 additions & 0 deletions exams/AxelRubini/2025-01-09/1/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CC=g++
CFLAGS=-std=c++23 -O3 -Wall

all: main

main: main.cpp
$(CC) $(CFLAGS) main.cpp -o main

clean:
rm -f main *.o
212 changes: 212 additions & 0 deletions exams/AxelRubini/2025-01-09/1/include/DES.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@

#pragma once

#include "Random.hpp"
#include <algorithm>
#include <limits>
#include <memory>
#include <queue>
#include <stdexcept>
#include <vector>

namespace SELib {

// ---------------------------------------------------------------------------
// Messaggio
// ---------------------------------------------------------------------------
struct Message {
double time{0.0};
int sender{-1};
int receiver{-1};
int item{0};
double quantity{0.0};
};

// ---------------------------------------------------------------------------
// Bus di messaggi: process -> network, network -> process
// ---------------------------------------------------------------------------
class MessageBus {
public:
explicit MessageBus(std::size_t n = 0) { resize(n); }

void resize(std::size_t n) {
procToNet_.assign(n, {});
netToProc_.assign(n, {});
}

std::size_t size() const { return procToNet_.size(); }

std::queue<Message> &procToNet(int pid) { return procToNet_.at(pid); }
std::queue<Message> &netToProc(int pid) { return netToProc_.at(pid); }
const std::queue<Message> &procToNet(int pid) const {
return procToNet_.at(pid);
}
const std::queue<Message> &netToProc(int pid) const {
return netToProc_.at(pid);
}

private:
std::vector<std::queue<Message>> procToNet_;
std::vector<std::queue<Message>> netToProc_;
};

// ---------------------------------------------------------------------------
// Processo base a eventi discreti
// ---------------------------------------------------------------------------
class DiscreteEventProcess {
public:
virtual ~DiscreteEventProcess() = default;
virtual void initialize(double startTime) = 0;
virtual double nextEventTime() const = 0;
virtual void handleEvent(double currentTime) = 0;
};

// ---------------------------------------------------------------------------
// NetworkRouter: inoltra i messaggi P->N->P
// ---------------------------------------------------------------------------
class NetworkRouter : public DiscreteEventProcess {
public:
NetworkRouter(MessageBus &bus, RandomGenerator &rng, double scanPeriod = 0.1)
: bus_(bus), rng_(rng), scanPeriod_(scanPeriod), time_(0.0),
nextScanTime_(0.0), scanned_(0) {}

void initialize(double startTime) override {
time_ = startTime;
nextScanTime_ = startTime + scanPeriod_;

const int n = static_cast<int>(bus_.size());
if (n <= 0) {
throw std::runtime_error(
"NetworkRouter: no processes configured in MessageBus");
}

scanner_.resize(n);
for (int i = 0; i < n; ++i) {
scanner_[i] = i;
}
reshuffleScanner();
scanned_ = 0;
}

double nextEventTime() const override { return nextScanTime_; }

void handleEvent(double currentTime) override {
if (currentTime < nextScanTime_)
return;

const int n = static_cast<int>(scanner_.size());
if (n == 0)
return;

if (scanned_ >= n) {
scanned_ = 0;
reshuffleScanner();
}

const int channel = scanner_[scanned_++];
auto &fromQueue = bus_.procToNet(channel);

if (!fromQueue.empty()) {
Message m = fromQueue.front();
fromQueue.pop();

if (m.receiver < 0 || m.receiver >= static_cast<int>(bus_.size())) {
throw std::runtime_error("NetworkRouter: invalid receiver index");
}

bus_.netToProc(m.receiver).push(m);
}

nextScanTime_ = currentTime + scanPeriod_;
}

private:
void reshuffleScanner() {
auto &eng = rng_.engine(); // serve engine() in RandomGenerator
std::shuffle(scanner_.begin(), scanner_.end(), eng);
}

MessageBus &bus_;
RandomGenerator &rng_;

double scanPeriod_;
double time_;
double nextScanTime_;
std::vector<int> scanner_;
int scanned_;
};

// ---------------------------------------------------------------------------
// Sistema DES: collezione di processi
// ---------------------------------------------------------------------------
class DiscreteEventSystem {
public:
template <typename Proc, typename... Args>
Proc &emplaceProcess(Args &&...args) {
auto ptr = std::make_unique<Proc>(std::forward<Args>(args)...);
Proc &ref = *ptr;
processes_.push_back(std::move(ptr));
return ref;
}

void initialize(double startTime = 0.0) {
for (auto &p : processes_) {
p->initialize(startTime);
}
}

double nextEventTime() const {
if (processes_.empty()) {
return std::numeric_limits<double>::infinity();
}

double tMin = std::numeric_limits<double>::infinity();
for (const auto &p : processes_) {
double t = p->nextEventTime();
if (t < tMin)
tMin = t;
}
return tMin;
}

void handleEvent(double currentTime) {
for (auto &p : processes_) {
if (p->nextEventTime() <= currentTime) {
p->handleEvent(currentTime);
}
}
}

private:
std::vector<std::unique_ptr<DiscreteEventProcess>> processes_;
};

// ---------------------------------------------------------------------------
// Simulatore DES
// ---------------------------------------------------------------------------
class DiscreteEventSimulator {
public:
explicit DiscreteEventSimulator(DiscreteEventSystem &system)
: system_(system), currentTime_(0.0) {}

void run(double horizon) {
system_.initialize(0.0);
currentTime_ = 0.0;

while (currentTime_ < horizon) {
double nextTime = system_.nextEventTime();
if (nextTime == std::numeric_limits<double>::infinity())
break;
currentTime_ = nextTime;
system_.handleEvent(currentTime_);
}
}

double currentTime() const { return currentTime_; }

private:
DiscreteEventSystem &system_;
double currentTime_;
};

} // namespace SELib
Loading