FlowArithmeticCalculator 1.0.0
Flow Arithmetic Calculator
Loading...
Searching...
No Matches
BlocksCalculator.cpp
Go to the documentation of this file.
1#include "BlocksCalculator.h"
2
6 : blocksRegistryDelegate(blocksRegistryDelegate) {}
7
9 auto blocks = blocksRegistryDelegate->getBlocks();
10
11 visited.clear();
12 recursionStack.clear();
13
14 // check for cycles first
15 for (const auto& block : blocks) {
16 auto maybeCycle = hasCycle({.block = block.get(), .port = nullptr});
17
18 if (maybeCycle) {
19 throw errors::GraphCycleException(maybeCycle.value());
20 }
21 }
22
23 // calculate values for all blocks
24 calcVisited.clear();
25 for (const auto& block : blocks) {
26 calculateBlockValues(block.get());
27 }
28 }
29
32 if (calcVisited.find(block) != calcVisited.end()) {
33 return;
34 }
35
36 // mark as visited to prevent cycles
37 calcVisited.insert(block);
38
39 // first calculate values for all input blocks
40 for (const auto& [source, destinations] :
42 const auto& sourcePortValue = source.block->getPortValue(source.port);
43
44 for (const auto& dest : destinations) {
45 if (dest.block == block) {
46 calculateBlockValues(source.block);
47
48 // copy value from source output to destination input
49 block->setPortValue(dest.port, sourcePortValue);
50 }
51 }
52 }
53
54 // now calculate this block's output values
55 block->calculateOutputValues();
56 }
57
58 std::optional<std::unordered_set<business_logic::elements::structures::BlocksConnectionSide>>
60 if (std::any_of(recursionStack.begin(), recursionStack.end(), [side](const auto& predSide) {
61 return side.block == predSide.block;
62 })) {
63 // cycle found
64 std::unordered_set<business_logic::elements::structures::BlocksConnectionSide> cycle = {
65 {.block = side.block, .port = nullptr}};
66
67 for (const auto& visitedSide : visited) {
68 cycle.insert(visitedSide);
69 }
70
71 for (const auto& visitedSide : recursionStack) {
72 cycle.insert(visitedSide);
73 }
74
75 return cycle;
76 }
77
78 if (visited.contains(side)) {
79 // block already processed
80 return std::nullopt;
81 }
82
83 // visit the block
84 visited.insert(side);
85 recursionStack.insert(side);
86
87 // check all output connections of the block
88 for (const auto& [source, destinations] :
90 if (source.block == side.block) {
91 for (const auto& dest : destinations) {
92 auto maybeCycle = hasCycle(dest);
93 if (maybeCycle.has_value()) {
94 auto cycle = maybeCycle.value();
95
96 for (const auto& visitedSide : visited) {
97 cycle.insert(visitedSide);
98 }
99
100 for (const auto& visitedSide : recursionStack) {
101 cycle.insert(visitedSide);
102 }
103
104 cycle.insert(dest);
105
106 return cycle;
107 }
108 }
109 }
110 }
111
112 recursionStack.erase(side);
113 return std::nullopt;
114 }
115
116} // namespace business_logic::calculations
void calculateValuesFlow()
Calculates the values flowing through the graph.
business_logic::calculations::delegate::IBlocksRegistryDelegate * blocksRegistryDelegate
The delegate that provides the connections registry.
std::unordered_set< business_logic::elements::structures::BlocksConnectionSide > recursionStack
The stack of recursion to detect cycles.
BlocksCalculator(business_logic::calculations::delegate::IBlocksRegistryDelegate *blocksRegistryDelegate)
std::optional< std::unordered_set< business_logic::elements::structures::BlocksConnectionSide > > hasCycle(elements::structures::BlocksConnectionSide side)
Checks if there is a cycle in the graph.
std::unordered_set< business_logic::elements::structures::BlocksConnectionSide > visited
The set of visited blocks to detect cycles.
void calculateBlockValues(business_logic::elements::blocks::BaseBlock *block)
Calculates the values of the dependencies of a block and then the block itself.
std::unordered_set< business_logic::elements::blocks::BaseBlock * > calcVisited
The set of visited blocks to note which blocks have been visited when calculating their values.
The delegate for the blocks registry, allowing to get connections and blocks.
virtual const std::vector< std::shared_ptr< business_logic::elements::blocks::BaseBlock > > & getBlocks() const =0
Gets the blocks.
virtual const std::unordered_map< business_logic::elements::structures::BlocksConnectionSide, std::unordered_set< business_logic::elements::structures::BlocksConnectionSide > > & getConnectionsRegistry() const =0
Gets the connections registry.
The base class for all blocks, containing common functionality and members.
Definition BaseBlock.h:36
virtual void calculateOutputValues()=0
Calculates the output port values based on input port values.
void setPortValue(const business_logic::elements::structures::Port *port, const FloatingPoint &value)
Sets the value of the port.
Exception thrown when a graph cycle is detected.
Utilities regarding calculation of values for the calculator itself.
business_logic::elements::blocks::BaseBlock * block
The block.