Skip to content

Commit

Permalink
new version
Browse files Browse the repository at this point in the history
  • Loading branch information
matplinta committed Jan 14, 2020
1 parent 2ad76e5 commit c0cda14
Show file tree
Hide file tree
Showing 9 changed files with 473 additions and 53 deletions.
83 changes: 59 additions & 24 deletions src/parallel/ant.erl
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
-module (ant).
-export ([initAnts/4, ant/4, initTechnicalAnt/1, technicalAnt/1]).
-export ([initAnts/5, ant/5, initTechnicalAnt/1, technicalAnt/1]).

% 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
-define(Q, 100000).
-define(Q, 210).

% a parameter to control the influence of pheromones
-define(Alfa, 1).
Expand All @@ -17,11 +17,11 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% INITIALIZE ANTS
initAnts(_Master, _N, 0, _NodesPids) -> ok;
initAnts(Master, N, AntsQuantity, NodesPids) ->
Ant = spawn(ant, ant, [Master, NodesPids, 0, []]),
initAnts(_Master, _Iterations, _N, 0, _NodesPids) -> ok;
initAnts(TechnicalAnt, Iterations, N, AntsQuantity, NodesPids) ->
Ant = spawn(ant, ant, [TechnicalAnt, Iterations, NodesPids, 0, []]),
Ant ! {init, {rand:uniform(N)}},
initAnts(Master, N, AntsQuantity - 1, NodesPids).
initAnts(TechnicalAnt, Iterations, N, AntsQuantity - 1, NodesPids).

% UPDATE PHEROMONE LEVEL ON TRAVERSED PATH
updatePheromonesOnPath(_, _, [ _ | []]) -> ok;
Expand Down Expand Up @@ -79,41 +79,47 @@ selectNextNode(DistanceTo, Pheromones, Visited) ->
rouletteWheel(ProbabilitiesOfNTV, SumOfProbabilities).

% ANT PROCESS MESSAGE HANDLING
ant(Master, NodesPids, Distance, Path) ->
ant(TechnicalAnt, Iterations, NodesPids, Distance, Path) ->
receive
{init, {StartNode}} ->
NodePid = maps:get(StartNode, NodesPids),
NodePid ! {where, {self()}},
ant(Master, NodesPids, Distance, [ StartNode | Path]);
ant(TechnicalAnt, Iterations, NodesPids, Distance, [ StartNode | Path]);
{decide, {DistanceTo, Pheromones}} ->
case maps:size(NodesPids) == length(Path) of
true ->
FirstNode = lists:last(Path),
DistToFirst = maps:get(FirstNode, DistanceTo),
self() ! {finish},
ant(Master, NodesPids, Distance + DistToFirst, lists:reverse([ FirstNode | Path]));
ant(TechnicalAnt, Iterations, NodesPids, Distance + DistToFirst, lists:reverse([ FirstNode | Path]));
false ->
NextNode = selectNextNode(DistanceTo, Pheromones, Path),
NextNodePid = maps:get(NextNode, NodesPids),
NextNodePid ! {where, {self()}},
DistToNode = maps:get(NextNode, DistanceTo),
ant(Master, NodesPids, Distance + DistToNode, [ NextNode | Path])
ant(TechnicalAnt, Iterations, NodesPids, Distance + DistToNode, [ NextNode | Path])
end;
{finish} ->
% send to master info of best fitness
Master ! {check, {self(), Distance, Path}},
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))}},
ant(Master, NodesPids, 0, []);
{die} ->
exit(kill);
case Iterations of
0 ->
TechnicalAnt ! {antdied},
exit(kill);
_ -> ant(TechnicalAnt, Iterations - 1, NodesPids, 0, [])
end;
% {die} ->
% io:format("I die\n"),
% exit(kill);
_ ->
ant(Master, NodesPids, Distance, Path)
ant(TechnicalAnt, Iterations, NodesPids, Distance, Path)
end.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Expand All @@ -132,14 +138,43 @@ initTechnicalAnt(NodesPids) ->
spawn(ant, technicalAnt, [NodesPids]).

% TECHNICAL ANT PROCESS MESSAGE HANDLING
technicalAnt(NodesPids) ->
technicalAnt(AntsQuantity, Iterations, NodesPids, Distance, Path) ->
receive
{evaporate} ->
distributeToNodes(NodesPids, evaporate),
technicalAnt(NodesPids);
{killnodes} ->
% kill all nodes and also technical ant exits (dies :c)
distributeToNodes(NodesPids, die);
{init, {StartNode}} ->
NodePid = maps:get(StartNode, NodesPids),
NodePid ! {where, {self()}},
ant(AntsQuantity, Iterations, NodesPids, Distance, [ StartNode | Path]);
{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]));
false ->
NextNode = selectNextNode(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;
{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, [])
end;
{killnodes} ->
% kill all nodes and also technical ant exits (dies :c)
distributeToNodes(NodesPids, die);
_ ->
technicalAnt(NodesPids)
end.
ant(TechnicalAnt, Iterations, NodesPids, Distance, Path)
end.
8 changes: 4 additions & 4 deletions src/parallel/main.erl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-module (main).
-import(reader, [init/1]).
-import(node, [initNodes/2]).
-import(ant, [initAnts/4, initTechnicalAnt/1]).
-import(node, [initNodes/3]).
-import(ant, [initAnts/5, initTechnicalAnt/1]).
-import(master, [initMaster/4]).
-export([start/1, start/0]).
% -compile(export_all).
Expand All @@ -15,10 +15,10 @@ start([ProblemPath, Ants, Iterations | _]) ->
{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),
Nodes = initNodes(N, Adj, AntsQuantity),
TechnicalAnt = initTechnicalAnt(Nodes),
Master = initMaster(erlang:monotonic_time(), StopAfterSingleAntIterations, AntsQuantity, TechnicalAnt),
initAnts(Master, N, AntsQuantity, Nodes).
initAnts(Master, StopAfterSingleAntIterations, N, AntsQuantity, Nodes).

start() ->
usage().
Expand Down
18 changes: 5 additions & 13 deletions src/parallel/master.erl
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,21 @@
initMaster(StartTime, StopCondition, AntsQt, TechnicalAnt) ->
spawn(master, master, [StartTime, false, StopCondition, AntsQt, 1, TechnicalAnt, none, []]).

% HANDLE EVAPORATE CONDITION
sendEvaporateOrder(TechnicalAnt, AntsIter, AntsQt) -> sendEvaporateOrder(TechnicalAnt, AntsIter, AntsQt, AntsIter rem AntsQt).
sendEvaporateOrder(TechnicalAnt, AntsIter, AntsQt, 0) ->
io:format("Single ant iteration finished:\t~w\n",[ round(AntsIter/AntsQt) ]),
TechnicalAnt ! {evaporate},
ok;
sendEvaporateOrder(_, _, _, _) -> nok.

% MASTER PROCESS MESSAGE HANDLING
master(StartTime, Stop, StopCondition, AntsQt, AntsIter, TechnicalAnt, BestDistance, BestPath) ->
receive
{check, {Ant, Distance, Path}} ->
% send evaporate message to every node only upon complete, on average, each ant iteration
% meaning: if <every traversal(counting in every ant)> mod <ants quantity> == 0 => evaporate
sendEvaporateOrder(TechnicalAnt, AntsIter, AntsQt),
% sendEvaporateOrder(TechnicalAnt, AntsIter, AntsQt),
if
% if there is only one ant left alive, kill it and tell Technical Ant to kill all nodes and itself also
AntsQt == 1 ->
Ant ! {die},
TechnicalAnt ! {killnodes};
% AntsQt == 1 ->
% Ant ! {die},
% TechnicalAnt ! {killnodes};
% check for stop condition, if on average single ant traversed given number of iterations, send stop signal
AntsIter/AntsQt >= StopCondition ->
Ant ! {die},
% Ant ! {die},
% case structure; only to display "BEST PATH FOUND" sign only once
case Stop of
false ->
Expand Down
30 changes: 18 additions & 12 deletions src/parallel/node.erl
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
-module (node).
-export ([initNodes/2, node/3]).
-export ([initNodes/3, node/5]).

% evaporation coefficient
-define(EvaCo, 0.16842).
-define(EvaCo, 0.05).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%% Node %%%%%%%%%%%%%%%%%%%%%%%
Expand Down Expand Up @@ -34,30 +34,36 @@ initDistanceTo(N, Omit, AdjTable, NodeNo, Acc) ->
% INITIALIZE NODES
% RETURNS #{NodeNo => PID, ...}
% FORMAT: DistanceTo, Pheromones: #{NodeNo => value, ...}
initNodes(N, AdjTable) -> initNodes(N, N, AdjTable, #{}).
initNodes(_N, 0, _AdjTable, Acc) -> Acc;
initNodes(N, NodeNo, AdjTable, Acc) ->
initNodes(N, AdjTable, AntsQuantity) -> initNodes(N, N, AntsQuantity, AdjTable, #{}).
initNodes(_N, 0, _AntsQuantity, _AdjTable, Acc) -> Acc;
initNodes(N, NodeNo, AntsQuantity, AdjTable, Acc) ->
DistanceTo = initDistanceTo(N, NodeNo, AdjTable),
Pheromones = initPheromones(N, NodeNo),
Pid = spawn(node, node, [NodeNo, DistanceTo, Pheromones]),
initNodes(N, NodeNo - 1, AdjTable, maps:put(NodeNo, Pid, Acc)).
Pid = spawn(node, node, [NodeNo, DistanceTo, Pheromones, AntsQuantity, 1]),
initNodes(N, NodeNo - 1, AntsQuantity, AdjTable, maps:put(NodeNo, Pid, Acc)).

% NODE PROCESS MESSAGE HANDLING
node(NodeNo, DistanceTo, Pheromones) ->
node(NodeNo, DistanceTo, Pheromones, AntsQuantity, AntsThatPassedThrough) ->
receive
{where, {Ant}} ->
Ant ! {decide, {DistanceTo, Pheromones}},
node(NodeNo, DistanceTo, Pheromones);
node(NodeNo, DistanceTo, Pheromones, AntsQuantity, AntsThatPassedThrough);
{update, {Next, Addition}} ->
NewPheromoneValue = maps:get(Next, Pheromones) + Addition,
UpdatedPheromones = maps:update(Next, NewPheromoneValue, Pheromones),
node(NodeNo, DistanceTo, UpdatedPheromones);
case AntsThatPassedThrough rem AntsQuantity of
0 ->
self() ! {evaporate};
_ ->
ok
end,
node(NodeNo, DistanceTo, UpdatedPheromones, AntsQuantity, AntsThatPassedThrough + 1);
{evaporate} ->
Evaporate = fun(K, V, Acc) -> maps:put(K, (1 - ?EvaCo) * V, Acc) end,
EvaporatedPheromones = maps:fold(Evaporate, #{}, Pheromones),
node(NodeNo, DistanceTo, EvaporatedPheromones);
node(NodeNo, DistanceTo, EvaporatedPheromones, AntsQuantity, AntsThatPassedThrough);
{die} ->
exit(kill);
_ ->
node(NodeNo, DistanceTo, Pheromones)
node(NodeNo, DistanceTo, Pheromones, AntsQuantity, AntsThatPassedThrough)
end.
Loading

0 comments on commit c0cda14

Please sign in to comment.