Graph API & internal structures redesign
[hypercube:hypercube.git] / CORE / sa.cpp
1 #include <cstdlib>
2 #include <cmath>
3 #include <ctime>
4 #include "vertex.h"
5 #include "graph.h"
6 #include "sa.h"
7 #include "sa_log.h"
8
9
10 static inline float rnd();
11 static inline int crop(int x, int min, int max);
12
13
14 SA::SA()
15 {
16         _nodeDistribution = 8000000;
17         _edgeLength = 4;
18         _edgeCrossings = 100000;
19
20         _initTemp = 10000;
21         _finalTemp = 100;
22         _coolFactor = 0.75;
23         _numSteps = 800;
24
25         LOG_INIT();
26 }
27
28 inline Coordinates SA::newVertexLocation(Graph *g, int v, float temp)
29 {
30         Coordinates offset, location;
31         Coordinates bounds = g->dimensions();
32         Coordinates loc = g->vertex(v)->coordinates();
33         Margin margin = g->margin(v);
34
35         offset.setX((int)((temp / _initTemp) * bounds.x() * (2 * rnd() - 1)));
36         offset.setY((int)((temp / _initTemp) * bounds.y() * (2 * rnd() - 1)));
37         location.setX(crop(loc.x() + offset.x(), margin.lt().x(),
38           bounds.x() - 1 - margin.rb().x()));
39         location.setY(crop(loc.y() + offset.y(), margin.lt().y(),
40           bounds.y() - 1 - margin.rb().y()));
41         LOG_OFFSET(offset);
42
43         return location;
44 }
45
46 inline float SA::evaluateState(Graph *g)
47 {
48         return
49           _nodeDistribution * g->distance()
50           + _edgeLength * g->length()
51           + _edgeCrossings * g->crossings();
52 }
53
54 inline void SA::newState(Graph *g, float temp)
55 {
56         int id;
57         float cost, new_cost, delta, ex, acc;
58
59         cost = evaluateState(g);
60         id = rand() % g->vertex_size();
61         Coordinates location = g->vertex(id)->coordinates();
62         Coordinates new_location = newVertexLocation(g, id, temp);
63         g->vertex(id)->setCoordinates(new_location);
64         new_cost = evaluateState(g);
65
66         delta = (new_cost - cost);
67         ex = rnd();
68         acc = exp(-delta / temp);
69         if ((delta < 0) || (ex < acc))
70                 cost = new_cost;
71         else
72                 g->vertex(id)->setCoordinates(location);
73
74         LOG_ACCEPTANCE(delta, ex, acc);
75 }
76
77 void SA::compute(Graph *g)
78 {
79         float temp = _initTemp;
80         int steps;
81
82         LOG_START();
83
84         do {
85                 steps = _numSteps;
86                 do {
87                         newState(g, temp);
88                         steps--;
89                         LOG_PROGRESS(g);
90                 } while (steps);
91                 temp = temp * _coolFactor;
92         } while (temp > _finalTemp);
93
94         LOG_END();
95 }
96
97
98 static inline float rnd()
99 {
100         return ((float) rand() / (float)RAND_MAX);
101 }
102
103 static inline int crop(int x, int min, int max)
104 {
105         int retval;
106
107         if (x < min)
108                 retval = min;
109         else if (x > max)
110                 retval = max;
111         else
112                 retval = x;
113
114         return retval;
115 }