Skip to content

Commit

Permalink
added parallel without master
Browse files Browse the repository at this point in the history
  • Loading branch information
matplinta committed Jan 14, 2020
1 parent c0cda14 commit 7cfb1e7
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 99 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
*.directory
*.dump
ebin/
10.1.1.96.6751.pdf
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,25 @@ Implementation of Ant Colony Optimization (ACO) in Erlang language. Solving trav
Program finds near-optimal solution for travelling salesman problem (TSP) using Ant Colony Optimization algorithm. Structurally program consists of 4 types of processes (besides the main process). These are _node_, which quantity is equal to the number of cities defined in a [TSPLIB data file](http://elib.zib.de/pub/mp-testdata/tsp/tsplib/tsp/index.html), _ant_, which quantity is defined by the user, _technical ant_, which is an ant created solely to give evaporation and die orders to all nodes upon certain conditions met, and lastly _master_ which is a checking process for finding the best solution and other such utilities.

## Usage
To compile: `./compile`.
To run: `./run <path_to_tsplib> <ants> <iterations>`.
To compile and run:
```sh
./run <path_to_tsplib> <ants> <iterations> <method>
```

If you wish to run directly with _Erlang_:
```sh
erl -pz ebin/<method> -s main start problems/oliver30.tsp 30 100
```
erl -pz ebin -s main start problems/oliver30.tsp 30 100
```
or in _Eshell_:
```
or in <span style="color:purple">_Eshell_</span> - go to <span style="color:teal">_src/\<method\>_</span> and execute:
```erlang
Eshell V10.6 (abort with ^G)
1> c(main), c(node), c(reader), c(ant), c(master). % to compile
2> main:start(). % note to change initial parameters in start() method accordingly!
```
Where _method_ is a chosen method from folder _src_.



---

## Mechanizm działania
```erlang
Expand Down
3 changes: 0 additions & 3 deletions compile

This file was deleted.

4 changes: 0 additions & 4 deletions ebin/.gitignore

This file was deleted.

12 changes: 9 additions & 3 deletions run
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
#!/bin/bash

if [ $# -ne 3 ]; then
echo "Usage: <path_to_file> <ants> <iterations>."
if [ $# -ne 4 ]; then
echo "Usage: <path_to_file> <ants> <iterations> <method>."
exit 1
fi

erl -pz ebin -s main start $1 $2 $3
METHOD=$4

mkdir -p ebin/$METHOD

erlc -o ebin/$METHOD src/$METHOD/*.erl

erl -pz ebin/$METHOD -s main start $1 $2 $3
# erl -pz ebin -s main start problems/oliver3.tsp 2 2
90 changes: 62 additions & 28 deletions src/parallel/ant.erl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-module (ant).
-export ([initAnts/5, ant/5, initTechnicalAnt/1, technicalAnt/1]).
-export ([initAnts/5, ant/5, initTechnicalAnt/3, technicalAnt/7]).

% Pheromone level deposition constant; Pheromone deposited on a node = Q/Lk
% where Lk is a cost of the k'th ant tour, typically, in our case, lenght of the tour
Expand Down Expand Up @@ -76,7 +76,7 @@ selectNextNode(DistanceTo, Pheromones, Visited) ->
PheromonesOfNTV = maps:without(Visited, Pheromones),
ProbabilitiesOfNTV = countProbability(DistanceToOfNTV, PheromonesOfNTV),
SumOfProbabilities = sumMap(ProbabilitiesOfNTV),
rouletteWheel(ProbabilitiesOfNTV, SumOfProbabilities).
rouletteWheel(ProbabilitiesOfNTV, SumOfProbabilities).

% ANT PROCESS MESSAGE HANDLING
ant(TechnicalAnt, Iterations, NodesPids, Distance, Path) ->
Expand All @@ -100,20 +100,18 @@ ant(TechnicalAnt, Iterations, NodesPids, Distance, Path) ->
ant(TechnicalAnt, Iterations, NodesPids, Distance + DistToNode, [ NextNode | Path])
end;
{finish} ->
% send to master info of best fitness
TechnicalAnt ! {check, {self(), Distance, Path}},
% UNCOMMENT IF YOU WISH TO SEE EVERY SINGLE ANT'S DISTANCE AND PATH
% io:format("\nAnt: Distance: ~w,\tPath: ~w", [Distance, Path]),
% update pheromone table on path
Addition = ?Q / Distance,
updatePheromonesOnPath(NodesPids, Addition, Path),
% restart ant's journey
self() ! {init, {rand:uniform(maps:size(NodesPids))}},
case Iterations of
0 ->
if
Iterations == 0 ->
TechnicalAnt ! {antdied},
exit(kill);
_ -> ant(TechnicalAnt, Iterations - 1, NodesPids, 0, [])
true -> ant(TechnicalAnt, Iterations - 1, NodesPids, 0, [])
end;
% {die} ->
% io:format("I die\n"),
Expand All @@ -126,6 +124,31 @@ ant(TechnicalAnt, Iterations, NodesPids, Distance, Path) ->
%%%%%%%%%%%%%%%%%%%%%%%% TECHNICAL ANT %%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

iterate(Size, Iterator, MaxKey, MaxVal) ->
case maps:next(Iterator) of
{Key, Val, Iterrator2} ->
if
Size == 0 ->
Key;
Val >= MaxVal ->
iterate(Size, Iterrator2, Key, Val);
true ->
iterate(Size, Iterrator2, MaxKey, MaxVal)
end;
none ->
MaxKey
end.

% SELECT NEXT NODE BASED ON PROBABILITIES BY HIGHEST VALUE
selectNextNodeByHighestValue(DistanceTo, Pheromones, Visited) ->
DistanceToOfNTV = maps:without(Visited, DistanceTo),
PheromonesOfNTV = maps:without(Visited, Pheromones),
ProbabilitiesOfNTV = countProbability(DistanceToOfNTV, PheromonesOfNTV),
Iterator = maps:iterator(ProbabilitiesOfNTV),
iterate(maps:size(ProbabilitiesOfNTV), Iterator, 0, 0.0).



% DISTRIBUTE GIVEN MESSAGE TO ALL NODES METHOD
distributeToNodes(NodesPids, Msg) -> distributeToNodes(NodesPids, Msg, maps:next(maps:iterator(NodesPids))).
distributeToNodes(_, _, none) -> ok;
Expand All @@ -134,47 +157,58 @@ distributeToNodes(NodesPids, Msg, {_, NodePid, NewIterator}) ->
distributeToNodes(NodesPids, Msg, maps:next(NewIterator)).

% INITIALIZE TECHNICAL ANT
initTechnicalAnt(NodesPids) ->
spawn(ant, technicalAnt, [NodesPids]).
initTechnicalAnt(StartTime, AntsQuantity, NodesPids) ->
spawn(ant, technicalAnt, [StartTime, AntsQuantity, NodesPids, 0, [], none, []]).

% TECHNICAL ANT PROCESS MESSAGE HANDLING
technicalAnt(AntsQuantity, Iterations, NodesPids, Distance, Path) ->
technicalAnt(StartTime, AntsQuantity, NodesPids, Distance, Path, BestDistance, BestPath) ->
receive
{init, {StartNode}} ->
NodePid = maps:get(StartNode, NodesPids),
NodePid ! {where, {self()}},
ant(AntsQuantity, Iterations, NodesPids, Distance, [ StartNode | Path]);
technicalAnt(StartTime, AntsQuantity, NodesPids, Distance, [ StartNode | Path], BestDistance, BestPath);
{decide, {DistanceTo, Pheromones}} ->
case maps:size(NodesPids) == length(Path) of
true ->
FirstNode = lists:last(Path),
DistToFirst = maps:get(FirstNode, DistanceTo),
self() ! {finish},
ant(AntsQuantity, Iterations, NodesPids, Distance + DistToFirst, lists:reverse([ FirstNode | Path]));
technicalAnt(StartTime, AntsQuantity, NodesPids, Distance + DistToFirst, lists:reverse([ FirstNode | Path]), BestDistance, BestPath);
false ->
NextNode = selectNextNode(DistanceTo, Pheromones, Path),
NextNode = selectNextNodeByHighestValue(DistanceTo, Pheromones, Path),
NextNodePid = maps:get(NextNode, NodesPids),
NextNodePid ! {where, {self()}},
DistToNode = maps:get(NextNode, DistanceTo),
ant(AntsQuantity, Iterations, NodesPids, Distance + DistToNode, [ NextNode | Path])
end;
technicalAnt(StartTime, AntsQuantity, NodesPids, Distance + DistToNode, [ NextNode | Path], BestDistance, BestPath)
end;
{finish} ->
% send to master info of best fitness
AntsQuantity ! {check, {self(), Distance, Path}},
% UNCOMMENT IF YOU WISH TO SEE EVERY SINGLE ANT'S DISTANCE AND PATH
% io:format("\nAnt: Distance: ~w,\tPath: ~w", [Distance, Path]),
% update pheromone table on path
Addition = ?Q / Distance,
updatePheromonesOnPath(NodesPids, Addition, Path),
% restart ant's journey
self() ! {init, {rand:uniform(maps:size(NodesPids))}},
case Iterations of
0 -> io:format("I die\n"), exit(kill);
_ -> ant(TechnicalAnt, Iterations - 1, NodesPids, 0, [])
% io:format("Ant: Distance: ~w,\tPath: ~w\n", [Distance, Path]),
Time = erlang:convert_time_unit(erlang:monotonic_time() - StartTime, native, millisecond),
if
Distance < BestDistance ->
io:format("New best path: ~s,\tFound after: ~w ms\n", [float_to_list(Distance,[{decimals,3},compact]) , Time]),
% restart ant's journey
self() ! {init, {rand:uniform(maps:size(NodesPids))}},
technicalAnt(StartTime, AntsQuantity, NodesPids, 0, [], Distance, Path);
AntsQuantity == 0 ->
io:format("------------------------------------------------------------------------------------------\n"),
io:format("BEST PATH FOUND: ~s,\nPath: ~w\n", [float_to_list(BestDistance,[{decimals,3},compact]), BestPath]),
self() ! {killnodes},
technicalAnt(StartTime, AntsQuantity, NodesPids, 0, [], BestDistance, BestPath);
true ->
% restart ant's journey
self() ! {init, {rand:uniform(maps:size(NodesPids))}},
technicalAnt(StartTime, AntsQuantity, NodesPids, 0, [], BestDistance, BestPath)
end;

{killnodes} ->
% kill all nodes and also technical ant exits (dies :c)
distributeToNodes(NodesPids, die);
distributeToNodes(NodesPids, die),
io:format("Ants, Nodes and TechnicalAnt exited.\n"),
halt(0);
{antdied} ->
technicalAnt(StartTime, AntsQuantity - 1, NodesPids, Distance, Path, BestDistance, BestPath);
_ ->
ant(TechnicalAnt, Iterations, NodesPids, Distance, Path)
technicalAnt(StartTime, AntsQuantity, NodesPids, Distance, Path, BestDistance, BestPath)
end.
12 changes: 6 additions & 6 deletions src/parallel/main.erl
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
-module (main).
-import(reader, [init/1]).
-import(node, [initNodes/3]).
-import(ant, [initAnts/5, initTechnicalAnt/1]).
-import(master, [initMaster/4]).
-import(ant, [initAnts/5, initTechnicalAnt/3]).
-export([start/1, start/0]).
% -compile(export_all).

Expand All @@ -11,14 +10,15 @@ start([ProblemPath, Ants, Iterations | _]) ->
% % {N, _Map, Adj} = reader:init("../../problems/oliver30.tsp"),
% AntsQuantity = 30,
% StopAfterSingleAntIterations = 100,

{N, _Map, Adj} = reader:init(erlang:atom_to_list(ProblemPath)),
AntsQuantity = erlang:list_to_integer(erlang:atom_to_list(Ants)),
StopAfterSingleAntIterations = erlang:list_to_integer(erlang:atom_to_list(Iterations)),
Nodes = initNodes(N, Adj, AntsQuantity),
TechnicalAnt = initTechnicalAnt(Nodes),
Master = initMaster(erlang:monotonic_time(), StopAfterSingleAntIterations, AntsQuantity, TechnicalAnt),
initAnts(Master, StopAfterSingleAntIterations, N, AntsQuantity, Nodes).
TechnicalAnt = initTechnicalAnt(erlang:monotonic_time(), AntsQuantity, Nodes),
initAnts(TechnicalAnt, StopAfterSingleAntIterations, N, AntsQuantity, Nodes),
TechnicalAnt ! {init, {rand:uniform(N)}},
io:format("\n").

start() ->
usage().
Expand Down
48 changes: 0 additions & 48 deletions src/parallel/master.erl

This file was deleted.

0 comments on commit 7cfb1e7

Please sign in to comment.