Skip to content

Commit

Permalink
Interface extended
Browse files Browse the repository at this point in the history
  • Loading branch information
zfoxer committed Nov 21, 2020
1 parent e9219a2 commit 77ba68d
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 52 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ License: GNU GPL Version 3

## About the project

The shortest path problem is solved by many methods. Heuristics offer lower complexity in expense of accuracy. There are many use cases where the lower accuracy is acceptable in return of lower consumption of computing resources.
The shortest path problem is solved by many methods. Heuristics offer lower complexity in expense of accuracy. There are many use-cases where the lower accuracy is acceptable in return of lower consumption of computing resources.

Learning Automata (LA) are adaptive mechanisms requiring feedback from the executing environment to converge to certain states. In the context of network routing, LA residing at intermediate nodes along a path, exploit feedback from the destination node for reducing, e.g., path's length. This is the case since each Automaton after several iterations (depending on topology’s resources) starts pointing with higher probability to a neighbouring node which leads to a shorter path. Specifically, each LA that resides in a node, evaluates all physical neighbours with a probability number. After each feedback value from a destination node, this LA increases the probability number of the node leading to the destination and decreases all other probabilities of neighbouring nodes. So, subsequent tries (iterations) to reach the same destination have more chances to follow shorter routes. When all LA converge to certain neighbours, the path that is formed carries the properties that stem from the feedback value, e.g., low number of hops, leading to shorter paths.

Expand Down Expand Up @@ -39,7 +39,7 @@ The probability updating scheme Linear Reward-Inaction Algorithm [1] updates the
## Changelog

<pre>
1.0.2 2020-11-21 Interface for edge insertion improvement
1.0.1 2020-11-16 Execution time improvement

1.0 2020-11-10 Initial public release
</pre>
</pre>
30 changes: 23 additions & 7 deletions adaptivesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ void AdaptiveSystem::initTopo(const std::string& filename)
if(!std::strcmp(it->first.c_str(), "number_of_nodes"))
continue;

int edgeId = 0;
ptree::const_iterator end2 = it->second.end();
for(ptree::const_iterator it2 = it->second.begin(); it2 != end2; ++it2)
{
Expand All @@ -112,12 +111,29 @@ void AdaptiveSystem::initTopo(const std::string& filename)
length = it3->second.get_value<int>();
}

Edge edge;
edge.edgeStart = src;
edge.edgeEnd = dest;
edge.weight = static_cast<double>(length);
edge.id = ++edgeId;
edges.push_back(edge);
insertEdge(src, dest, static_cast<double>(length));
}
}
}

/**
* Inserts an edge.
*
* @param src Source node
* @param dest Destination node
* @param weight Weight for the edge
*/
void AdaptiveSystem::insertEdge(int src, int dest, double weight) noexcept(false)
{
AdaptiveSystem::Edge edge;
edge.edgeStart = src;
edge.edgeEnd = dest;
edge.weight = weight;
edge.id = ++edgeIdCnt;
edges.push_back(edge);
}

/**
* Used for producing edge IDs.
*/
int AdaptiveSystem::edgeIdCnt = 0;
4 changes: 4 additions & 0 deletions adaptivesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,15 @@ class AdaptiveSystem
AdaptiveSystem();
virtual ~AdaptiveSystem();
virtual std::vector<int> path(int, int) = 0;
virtual void insertEdge(int, int, double) noexcept(false);
virtual void clear() = 0;

protected:
virtual void initTopo(const std::string&);
std::vector<Edge> edges;

private:
static int edgeIdCnt;
};

#endif // ADAPTIVESYSTEM_H
97 changes: 59 additions & 38 deletions lasystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ LA::LA(std::initializer_list<int> neighs)
LA::~LA() { }

/**
* Updates all probabilities. Increases the one of the given item and decreases all others.
* Summary before and after the increase is equal to 1. The sum of the decrease per item is
* the amount of the increase for the input item.
* Updates all probabilities. Increases the input item and decreases all others.
* Sum of all items before and after the increase is equal to 1. The sum of the
* decrease of the rest items is equal to the amount of input item's increase.
*
* @param node The item whose probability will be increased
* @param time The timestamp of the increase
* @param node Item whose probability will be increased
* @param time Timestamp of the increase
* @param feedback Environment's response to the item
* @throws std::out_of_range The item is unknown to this LA
*/
Expand All @@ -75,7 +75,7 @@ void LA::updateProbs(int node, double time, double feedback) noexcept(false)
double l = 0.15;
double sumPj = 0;
// The value of 'l' determines the convergence speed to the actual
// demand probabilities and 'a' makes low priority neighbours not reach zero value
// demand and 'a' makes low priority neighbours not reach zero value
for(auto& nodeProb : probs)
if(nodeProb.first != node)
{
Expand All @@ -84,17 +84,17 @@ void LA::updateProbs(int node, double time, double feedback) noexcept(false)
- l * feedback * (probs[nodeProb.first] - a));
}

// The amount that was subtracted from the other items, will be added to this one.
// The amount that was subtracted from the other items will be added to this one
probs[node] = (probs[node] + l * feedback * sumPj);
lastTimes[node] = time;
}

/**
* Updates the time the given item was last selected.
* Updates the time the input item was last selected.
*
* @param item The item whose "last selected time" will be updated
* @param time The timestamp
* @throws std::out_of_range The item is unknown to this LA
* @param time Timestamp
* @throws std::out_of_range Unknown item to this LA
*/
void LA::timeChange(int item, double time) noexcept(false)
{
Expand All @@ -105,7 +105,7 @@ void LA::timeChange(int item, double time) noexcept(false)
}

/**
* Fetches all local items.
* Returns all local items.
*
* @return std::list<int> All locally monitored items
*/
Expand All @@ -121,7 +121,7 @@ std::list<int> LA::items()
/**
* Inserts a new item to this LA. Probabilities are updated to be equal.
*
* @param node A new item to be inserted
* @param node The item to be inserted
* @param size Its size
*/
void LA::insertItem(int node, int size)
Expand Down Expand Up @@ -172,17 +172,6 @@ int LA::nextItem(double time)
return chosenNeigh;
}

/**
* Prints all current probability values to the specified output stream.
*
* @param out The STL output stream probabilities will be written to
*/
void LA::dumbProbs(std::ostream& out)
{
for(const auto& pair : probs)
out << "node: " << pair.first << ", prob: " << pair.second << std::endl;
}

/**
* Constructor for the LaSystem.
*
Expand Down Expand Up @@ -211,11 +200,43 @@ LaSystem::LaSystem(const std::string& filename, int iterations)
this->iterations = (iterations > 0) ? iterations : ITERATIONS;
}

/**
* Constructor for the LaSystem.
*
* @param iterations The number of iterations, LAs will use to converge
*/
LaSystem::LaSystem(int iterations)
{
maxLength = 0;
this->iterations = (iterations > 0) ? iterations : ITERATIONS;
}

/**
* Empty destructor.
*/
LaSystem::~LaSystem() { }

/**
* Inserts a new edge to the LA System. Reconstructs the virtual topology internally.
*
* @param src Edge's startpoint
* @param dest Edge's endpoint
* @param weight Edge's weight
*/
void LaSystem::insertEdge(int src, int dest, double weight)
{
AdaptiveSystem::insertEdge(src, dest, weight);
localEdges.clear();
las.clear();
maxLength = 0;
for(auto& edge : edges)
{
insertEdge(edge);
if(edge.weight > maxLength)
maxLength = edge.weight;
}
}

/**
* Inserts a new edge to the LA System. Constructs the virtual topology internally.
*
Expand All @@ -224,10 +245,10 @@ LaSystem::~LaSystem() { }
void LaSystem::insertEdge(Edge edge)
{
localEdges.insert(edge);

LA la;
la.insertItem(edge.edgeEnd, sizeFromLength(edge.weight));

// Every node is mapped to a LA. LAs contain its neighbours.
// Every node is mapped to an LA. Each LA contains and evaluates its neighbours.
if(las.find(edge.edgeStart) == las.end())
las[edge.edgeStart] = la;
else
Expand Down Expand Up @@ -257,7 +278,7 @@ int LaSystem::sizeFromLength(double length)
}

/**
* Finds the best path from a source node to destination, using the LA system.
* Finds the best path from source node to destination using the LA system.
*
* @param src Starting node
* @param dest Ending node
Expand All @@ -276,7 +297,7 @@ std::vector<int> LaSystem::path(int src, int dest)
traverse(src, dest, path, time);
if(path.front() != src || path.back() != dest)
{
// Failed to find adequate path
// Failed to find a path
// Path nodes will have their 'chosen' timestamps updated
applyTimeChange(path, time);
time += TIME_SLOT;
Expand Down Expand Up @@ -305,7 +326,7 @@ std::vector<int> LaSystem::path(int src, int dest)
bestPath = path;
}

// Update path's nodes with apropriate feedback
// Update path's nodes with the calculated feedback
applyFeedback(path, time, calcFeedback(path));
time += TIME_SLOT;
}
Expand Down Expand Up @@ -337,7 +358,7 @@ double LaSystem::pathLength(const std::list<int>& path) const noexcept(false)
// For every path segment
for(int i = 0; i < (int)vecPath.size() - 1; ++i)
{
// Find the edges that start with current trace node using the next lambda function
// Find the edges that start with current node using the next lambda function
std::for_each(localEdges.cbegin(), localEdges.cend(),
[&vecPath, i, &weightSum](Edge edge)
{
Expand All @@ -350,19 +371,19 @@ double LaSystem::pathLength(const std::list<int>& path) const noexcept(false)
}

/**
* Applies a feedback value to path's nodes.
* Applies a feedback value to a path's nodes.
*
* @param path The path containing the nodes
* @param time The current update time
* @param feedback The feedback value (range 0-1)
* @param feedback The feedback value in range [0-1]
*/
void LaSystem::applyFeedback(std::list<int>& path, double time, double feedback)
{
std::vector<int> vecPath;
for(int node : path)
vecPath.push_back(node);

// Get the right LA for path's nodes and update the probability for the right neighbour
// Get the right LA for path's nodes and update the probability for the neighbour
for(unsigned int i = 0; i < vecPath.size() - 1; ++i)
try
{
Expand Down Expand Up @@ -409,12 +430,12 @@ double LaSystem::calcFeedback(std::list<int>& path)
}

/**
* Brute force method to find a path between two nodes. All valid result are returned.
* Recursive method to find a path between two nodes. All valid results are returned.
*
* @param node The current node
* @param dest The destination to be reached
* @param path The current path nodes
* @param currentTime The current time slot
* @param node Current node
* @param dest Destination to be reached
* @param path Current path node sequence
* @param currentTime Current time slot
*/
void LaSystem::traverse(int node, int dest, std::list<int>& path, double currentTime)
{
Expand Down Expand Up @@ -445,7 +466,7 @@ LA* LaSystem::getLA(int item)
* Detects if a cycle is formed inside the sequence of nodes.
*
* @param items The sequence of nodes
* @return bool The indication of a cyclic sequence
* @return bool Indication of a cyclic sequence
*/
bool LaSystem::detectCycle(const std::list<int>& items)
{
Expand Down
4 changes: 2 additions & 2 deletions lasystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
#include <array>
#include <unordered_set>
#include <unordered_map>
#include <map>
#include <set>
#include <list>

Expand All @@ -50,7 +49,6 @@ class LA
int nextItem(double);
void updateProbs(int, double, double) noexcept(false);
void timeChange(int, double) noexcept(false);
void dumbProbs(std::ostream&);
std::list<int> items();

private:
Expand All @@ -73,8 +71,10 @@ class LaSystem : public AdaptiveSystem
static const int ITERATIONS = 3000;
static const double TIME_SLOT;
LaSystem(const std::string&, int = 0);
LaSystem(int = 0);
virtual ~LaSystem();
virtual std::vector<int> path(int, int);
virtual void insertEdge(int, int, double) noexcept(false);
virtual void clear();

private:
Expand Down
4 changes: 2 additions & 2 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ bool simpleRun()
{
AdaptiveSystem* la = new LaSystem("topology.json", LaSystem::ITERATIONS);
auto nodePath = la->path(0, 19);
for(int n : nodePath)
std::cout << n << " ";
for(int node : nodePath)
std::cout << node << " ";
std::cout << std::endl;
delete la;

Expand Down

0 comments on commit 77ba68d

Please sign in to comment.