1 /* ****************************************************************************
2  * FILE:         annealing.c
3  * MODULE:       v.labels.sa
4  * AUTHOR(S):    Wolf Bergenheim
5  * PURPOSE:      This file contains functions which have to do with the
6  annealing part of the algorithm.
7  * COPYRIGHT:    (C) 2007 by the GRASS Development Team
8  *
9  *               This program is free software under the GNU General Public
10  *               License (>=v2). Read the file COPYING that comes with GRASS
11  *               for details.
12  *
13  *****************************************************************************/
14 
15 #include "labels.h"
16 #ifndef M_E
17 
18 /**
19  * This is simply Euler's number
20  */
21 # define M_E 2.7182818284590452353602874713526625L
22 #endif
23 
24 /**
25  * How many times to decrease the Temperature T.
26  */
27 #define TEMP_DECS 50
28 
29 static double calc_label_overlap(label_t * label, int cc, int nc);
30 static void do_label_overlap(label_t * label, int cc, int nc);
31 
32 /**
33  * This is just a variable used to show statistics in the end.
34  */
35 static unsigned int overlaps_created = 0;
36 
37 /**
38  * This is just a variable used to show statistics in the end.
39  */
40 static unsigned int overlaps_removed = 0;
41 
42 /**
43  * This funxtion does the actual sumulated annealing process. Each round 30 x
44  * n (the number of labels) a label is picked at random, and placed in a random
45  * new position. Then the dE is calculated, and if dE is > 0 the new position is
46  * reversed with the probablility 1 - e^(-dE / T).
47  @param labels The array of all labels.
48  @param n_labels The size of the labels array.
49  @params The commandline parameters.
50  */
simulate_annealing(label_t * labels,int n_labels,struct params * p)51 void simulate_annealing(label_t * labels, int n_labels, struct params *p)
52 {
53     /* The temperature of the system */
54     double T;
55 
56     /* The change in energy */
57     double dE;
58 
59     T = -1.0 / log(1.0 / 3.0);
60     unsigned int t, tot_better = 0, tot_worse = 0, tot_ign = 0;
61 
62     fprintf(stderr, "Optimizing label positions: ...");
63     for (t = 0; t < TEMP_DECS; t++) {
64 	int i;
65 	unsigned int successes = 0, consec_successes = 0;
66 
67 	for (i = 0; i < (n_labels * 30); i++) {
68 	    int l, c, cc, r;
69 	    label_t *lp;
70 
71 	    /* pick a random label */
72 	    r = rand();
73 	    l = (int)((double)(n_labels) * (r / (RAND_MAX + 1.0)));
74 	    lp = &labels[l];
75 	    /* skip labels without sufficient number of candidates */
76 	    if (lp->n_candidates < 2)
77 		continue;
78 
79 	    cc = lp->current_candidate;
80 	    /*and a random new candidate place */
81 	    c = (int)((double)(lp->n_candidates) *
82 		      (rand() / (RAND_MAX + 1.0)));
83 	    if (c == cc) {
84 		if (c == 0)
85 		    c++;
86 		else
87 		    c--;
88 	    }
89 	    /* calc dE */
90 	    dE = lp->candidates[c].score - lp->candidates[cc].score;
91 	    dE += calc_label_overlap(lp, cc, c);
92 
93 	    /* if dE < 0 accept */
94 	    if (dE < 0.0) {
95 		lp->current_score = lp->candidates[c].score;
96 		do_label_overlap(lp, cc, c);
97 		lp->current_candidate = c;
98 		successes++;
99 		consec_successes++;
100 		tot_better++;
101 	    }
102 	    /* else apply with probability p=e^(-dE/T) */
103 	    else {
104 		double dp, dr;
105 
106 		dp = pow(M_E, -dE / T);
107 		dr = (double)rand() / RAND_MAX;
108 		if (dr <= dp) {
109 		    do_label_overlap(lp, cc, c);
110 		    lp->current_score += lp->candidates[c].score;
111 		    lp->current_candidate = c;
112 		    successes++;
113 		    consec_successes++;
114 		    tot_worse++;
115 		}
116 		else {
117 		    tot_ign++;
118 		    consec_successes = 0;
119 		}
120 	    }
121 	    /* decrease immediately */
122 	    if (consec_successes > (5 * n_labels)) {
123 		consec_successes = 0;
124 		break;
125 	    }
126 	}
127 	G_percent(t, TEMP_DECS, 1);
128 	/* we have found an optimal solution */
129 	if (successes == 0) {
130 	    break;
131 	}
132 	T -= 0.1 * T;
133     }
134     G_percent(TEMP_DECS, TEMP_DECS, 1);
135 }
136 
137 /**
138  * This function calculates the change in E (dE) if the given label would
139  * be moved to the new place. Contrary to the original algorithm this function
140  * requires twice as much energy to overlap two labels then is released by
141  * resolving an overlap. I don't have and scientific fact but it seems to
142  * improve the result.
143  * @param label The label in question
144  * @param cc The current candidate
145  * @param nc The new potential candidate location
146  * @return The dE value.
147  */
calc_label_overlap(label_t * label,int cc,int nc)148 static double calc_label_overlap(label_t * label, int cc, int nc)
149 {
150     int i;
151     double dE = 0.0;
152 
153     /* calculate the overlaps removed */
154     for (i = 0; i < label->candidates[cc].n_intersections; i++) {
155 	label_t *ol;
156 	int oc;
157 
158 	ol = label->candidates[cc].intersections[i].label;
159 	oc = label->candidates[cc].intersections[i].candidate;
160 	if (ol->current_candidate == oc) {
161 	    dE -= LABEL_OVERLAP_WEIGHT;
162 	}
163     }
164 
165     /* calculate the overlaps created */
166     for (i = 0; i < label->candidates[nc].n_intersections; i++) {
167 	label_t *ol;
168 	int oc;
169 
170 	ol = label->candidates[nc].intersections[i].label;
171 	oc = label->candidates[nc].intersections[i].candidate;
172 	if (ol->current_candidate == oc) {
173 	    dE += LABEL_OVERLAP_WEIGHT;
174 	}
175     }
176 
177     return dE;
178 }
179 
180 /**
181  * This function commits the label change to the new location.
182  * @param label The label to move
183  * @param cc The current candidate
184  * @param nc The new potential candidate location
185  */
do_label_overlap(label_t * label,int cc,int nc)186 static void do_label_overlap(label_t * label, int cc, int nc)
187 {
188     int i;
189 
190     /* remove the current label overlaps */
191     for (i = 0; i < label->candidates[cc].n_intersections; i++) {
192 	label_t *ol;
193 	int oc;
194 
195 	ol = label->candidates[cc].intersections[i].label;
196 	oc = label->candidates[cc].intersections[i].candidate;
197 	if (ol->current_candidate == oc) {
198 	    ol->current_score -= LABEL_OVERLAP_WEIGHT;
199 	    label->current_score -= LABEL_OVERLAP_WEIGHT;
200 	    /* ol->candidates[oc].score -= LABEL_OVERLAP_WEIGHT; */
201 	    overlaps_removed++;
202 	}
203     }
204 
205     /* create new overlaps */
206     for (i = 0; i < label->candidates[nc].n_intersections; i++) {
207 	label_t *ol;
208 	int oc;
209 
210 	ol = label->candidates[nc].intersections[i].label;
211 	oc = label->candidates[nc].intersections[i].candidate;
212 	if (ol->current_candidate == oc) {
213 	    ol->current_score += LABEL_OVERLAP_WEIGHT;
214 	    label->current_score += LABEL_OVERLAP_WEIGHT;
215 	    /* ol->candidates[oc]->score += 40; */
216 	    overlaps_created++;
217 	}
218     }
219 }
220