Fix tabbing
[satune.git] / src / Tuner / autotuner.cc
1 #include "autotuner.h"
2 #include "csolver.h"
3 #include "searchtuner.h"
4 #include <math.h>
5 #include <stdlib.h>
6 #include <float.h>
7 #include <iostream>
8 #include <chrono>
9 #include <thread>
10 #include <mutex>
11 #include <condition_variable>
12
13 #define TIMEOUT 1000s
14 #define UNSETVALUE -1
15 #define POSINFINITY 9999999999L
16
17 using namespace std::chrono_literals;
18
19 int solve(CSolver *solver)
20 {
21         try{
22                 return solver->solve();
23         }
24         catch (std::runtime_error &e) {
25                 return UNSETVALUE;
26         }
27 }
28
29 int solveWrapper(CSolver *solver)
30 {
31         std::mutex m;
32         std::condition_variable cv;
33         int retValue;
34
35         std::thread t([&cv, &retValue, solver]()
36                 {
37                                                                 retValue = solve(solver);
38                                                                 cv.notify_one();
39                 });
40
41         t.detach();
42
43         {
44                 std::unique_lock<std::mutex> l(m);
45                 if (cv.wait_for(l, TIMEOUT) == std::cv_status::timeout)
46                         throw std::runtime_error("Timeout");
47         }
48
49         return retValue;
50 }
51
52
53 AutoTuner::AutoTuner(uint _budget) :
54         budget(_budget), result(UNSETVALUE) {
55 }
56
57 void AutoTuner::addProblem(CSolver *solver) {
58         solvers.push(solver);
59 }
60
61 long long AutoTuner::evaluate(CSolver *problem, SearchTuner *tuner) {
62         CSolver *copy = problem->clone();
63         copy->setTuner(tuner);
64         model_print("**********************\n");
65         long long metric = 0L;
66         try {
67                 int sat = solveWrapper(copy);
68                 if (result == UNSETVALUE)
69                         result = sat;
70                 else if (result != sat) {
71                         model_print("&&&&&&&&&&&&&&&&&& Result has changed &&&&&&&&&&&&&\n");
72                         copy->printConstraints();
73                 }
74                 metric = copy->getElapsedTime();
75         }
76         catch (std::runtime_error &e) {
77                 metric = POSINFINITY;
78                 model_print("TimeOut has hit\n");
79         }
80
81         delete copy;
82         return metric;
83 }
84
85 double AutoTuner::evaluateAll(SearchTuner *tuner) {
86         double product = 1;
87         for (uint i = 0; i < solvers.getSize(); i++) {
88                 CSolver *problem = solvers.get(i);
89                 double score = evaluate(problem, tuner);
90                 product *= score;
91         }
92         return pow(product, 1 / ((double)solvers.getSize()));
93 }
94
95 SearchTuner *AutoTuner::mutateTuner(SearchTuner *oldTuner, uint k) {
96         SearchTuner *newTuner = oldTuner->copyUsed();
97         uint numSettings = oldTuner->getSize();
98         uint settingsToMutate = (uint)(AUTOTUNERFACTOR * (((double)numSettings) * (budget - k)) / (budget));
99         if (settingsToMutate < 1)
100                 settingsToMutate = 1;
101         model_print("Mutating %u settings\n", settingsToMutate);
102         while (settingsToMutate-- != 0) {
103                 newTuner->randomMutate();
104         }
105         return newTuner;
106 }
107
108
109 void AutoTuner::tune() {
110         SearchTuner *bestTuner = NULL;
111         double bestScore = DBL_MAX;
112
113         SearchTuner *oldTuner = new SearchTuner();
114         double base_temperature = evaluateAll(oldTuner);
115         double oldScore = base_temperature;
116
117         for (uint i = 0; i < budget; i++) {
118                 SearchTuner *newTuner = mutateTuner(oldTuner, i);
119                 double newScore = evaluateAll(newTuner);
120                 newTuner->printUsed();
121                 model_print("Received score %f\n", newScore);
122                 double scoreDiff = newScore - oldScore; //smaller is better
123                 if (newScore < bestScore) {
124                         if (bestTuner != NULL)
125                                 delete bestTuner;
126                         bestScore = newScore;
127                         bestTuner = newTuner->copyUsed();
128                 }
129
130                 double acceptanceP;
131                 if (scoreDiff < 0) {
132                         acceptanceP = 1;
133                 } else {
134                         double currTemp = base_temperature * (((double)budget - i) / budget);
135                         acceptanceP = exp(-scoreDiff / currTemp);
136                 }
137                 double ran = ((double)random()) / RAND_MAX;
138                 if (ran <= acceptanceP) {
139                         delete oldTuner;
140                         oldScore = newScore;
141                         oldTuner = newTuner;
142                 } else {
143                         delete newTuner;
144                 }
145         }
146         model_print("Best tuner:\n");
147         bestTuner->print();
148         bestTuner->serialize();
149         model_print("Received score %f\n", bestScore);
150         if (bestTuner != NULL)
151                 delete bestTuner;
152         delete oldTuner;
153 }