Skip to content

Commit 20bccb8

Browse files
committed
Merge branch 'master' of https://github.com/dreal/dreal3
2 parents c3144d6 + 284ceef commit 20bccb8

File tree

9 files changed

+359
-2
lines changed

9 files changed

+359
-2
lines changed

src/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8.12)
22
project(DREAL C CXX)
33
set(DREAL_VERSION_MAJOR 3)
44
set(DREAL_VERSION_MINOR 16)
5-
set(DREAL_VERSION_PATCH 07)
5+
set(DREAL_VERSION_PATCH 07.01)
66
set(PACKAGE_NAME dReal)
77
set(PACKAGE_VERSION "${DREAL_VERSION_MAJOR}.${DREAL_VERSION_MINOR}.${DREAL_VERSION_PATCH}")
88
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")

src/dsolvers/nra_solver.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ along with dReal. If not, see <http://www.gnu.org/licenses/>.
4848
#include "util/glpk_wrapper.h"
4949
#include "icp/lp_icp.h"
5050
#endif
51+
#include "icp/scoring_icp.h"
5152

5253
using ibex::IntervalVector;
5354
using nlohmann::json;
@@ -496,6 +497,8 @@ bool nra_solver::check(bool complete) {
496497
} else if (config.nra_lp) {
497498
lp_icp::solve(m_ctc, m_cs, m_stack);
498499
#endif
500+
} else if (config.nra_scoring) {
501+
scoring_icp::solve(m_ctc, m_cs, m_stack);
499502
} else {
500503
naive_icp::solve(m_ctc, m_cs, m_stack);
501504
}

src/icp/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ SET(DREAL_SRCS ${DREAL_SRCS}
33
${CMAKE_CURRENT_LIST_DIR}/icp.cpp
44
${CMAKE_CURRENT_LIST_DIR}/icp_simulation.cpp
55
${CMAKE_CURRENT_LIST_DIR}/lp_icp.cpp
6+
${CMAKE_CURRENT_LIST_DIR}/scoring_icp.cpp
67
PARENT_SCOPE)

src/icp/icp.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ void multiprune_icp::solve(contractor & ctc, contractor_status & cs, scoped_vec<
171171
cs.m_box = get<2>(splits);
172172
prune(ctc, cs);
173173
box a2 = cs.m_box;
174-
double const cscore = -a1.volume() - a2.volume(); // TODO(dzufferey): not a good way is some intervales are points
174+
double const cscore = -a1.volume() - a2.volume(); // TODO(dzufferey): not a good way as some intervals are points (volume = 0)
175175
if (cscore > score || bisectdim == -1) {
176176
first = a1;
177177
second = a2;

src/icp/scoring_icp.cpp

+256
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
/*********************************************************************
2+
Author: Damien Zufferey <[email protected]>
3+
4+
dReal -- Copyright (C) 2013 - 2016, the dReal Team
5+
6+
dReal is free software: you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation, either version 3 of the License, or
9+
(at your option) any later version.
10+
11+
dReal is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
GNU General Public License for more details.
15+
16+
You should have received a copy of the GNU General Public License
17+
along with dReal. If not, see <http://www.gnu.org/licenses/>.
18+
*********************************************************************/
19+
20+
#include <algorithm>
21+
#include <atomic>
22+
#include <functional>
23+
#include <limits>
24+
#include <memory>
25+
#include <random>
26+
#include <tuple>
27+
#include <unordered_set>
28+
#include <vector>
29+
#include <cmath>
30+
#include "icp/brancher.h"
31+
#include "icp/scoring_icp.h"
32+
#include "util/logging.h"
33+
#include "util/scoped_vec.h"
34+
#include "util/stat.h"
35+
36+
using std::get;
37+
using std::endl;
38+
using std::shared_ptr;
39+
using std::tuple;
40+
using std::unordered_set;
41+
using std::vector;
42+
43+
namespace dreal {
44+
45+
SizeBrancher scoring_sb;
46+
BranchHeuristic & scoring_icp::defaultHeuristic = scoring_sb;
47+
48+
void scoring_icp::reset_scores() {
49+
for (unsigned int i = 0; i < size; i++) {
50+
scores[i] = 1;
51+
prune_results[i] = 0;
52+
nbr_prune[i] = 0;
53+
}
54+
}
55+
56+
void scoring_icp::compute_scores() {
57+
for (unsigned int i = 0; i < size; i++) {
58+
double new_score = 1;
59+
if (nbr_prune[i] > 0) {
60+
new_score = std::min(1000.0, nbr_prune[i] / prune_results[i]);
61+
nbr_prune[i] = 0;
62+
prune_results[i] = 0;
63+
}
64+
scores[i] = score_update_old_weight * scores[i] +
65+
(1 - score_update_old_weight) * new_score;
66+
DREAL_LOG_INFO << "score of " << cs.m_box.get_name(i) << " is\t" << scores[i];
67+
}
68+
}
69+
70+
int scoring_icp::highest_score() {
71+
int max_idx = -1;
72+
double max_score = 1;
73+
for (unsigned int i = 0; i < size; i++) {
74+
if (cs.m_box.is_bisectable_at(i, cs.m_config.nra_precision)) {
75+
double s = scores[i];
76+
if (s > max_score) {
77+
max_idx = i;
78+
max_score = s;
79+
}
80+
}
81+
}
82+
DREAL_LOG_DEBUG << "highest_score " << max_idx << " with " << max_score;
83+
return max_idx;
84+
}
85+
86+
double scoring_icp::measure(box const & o, box const & n) {
87+
if (n.is_empty()) {
88+
return 0.0;
89+
} else {
90+
unsigned int s = o.size();
91+
double val = 0.0;
92+
for (unsigned int i = 0; i < s; i++) {
93+
double rn = n[i].rad();
94+
double ro = o[i].rad();
95+
if (rn > 0.0) {
96+
val += rn / ro;
97+
} else if (ro <= 0.0) {
98+
val += 1;
99+
}
100+
}
101+
return val / s;
102+
}
103+
}
104+
105+
void scoring_icp::safe_prune(int idx) {
106+
try {
107+
thread_local static box old_box = cs.m_box;
108+
ctc.prune(cs);
109+
if (cs.m_config.nra_use_stat) { cs.m_config.nra_stat.increase_prune(); }
110+
if (idx >= 0) {
111+
prune_results[idx] += measure(old_box, cs.m_box);
112+
nbr_prune[idx] += 1;
113+
}
114+
} catch (contractor_exception & e) {
115+
// Do nothing
116+
}
117+
}
118+
119+
void scoring_icp::prune_split_fixed_point() {
120+
thread_local static box tmp = cs.m_box;
121+
thread_local static box progress = tmp;
122+
unsigned int s = cs.m_box.size();
123+
int n = 0;
124+
do {
125+
if (cs.m_box.is_empty()) {
126+
break;
127+
}
128+
n++;
129+
progress = cs.m_box;
130+
for (unsigned int i = 0; i < s && !cs.m_box.is_empty(); i++) {
131+
if (cs.m_box.is_bisectable_at(i, cs.m_config.nra_precision)) {
132+
tuple<int, box, box> splits = cs.m_box.bisect_at(i);
133+
cs.m_box = get<1>(splits);
134+
safe_prune(i);
135+
tmp = cs.m_box;
136+
cs.m_box = get<2>(splits);
137+
safe_prune(i);
138+
cs.m_box.hull(tmp);
139+
}
140+
}
141+
DREAL_LOG_INFO << measure(progress, cs.m_box) << (cs.m_box.is_empty() ? "\t" : "\t");
142+
} while (measure(progress, cs.m_box) < progress_threshold);
143+
DREAL_LOG_INFO << "prune_split_fixed_point: " << n;
144+
}
145+
146+
void scoring_icp::solve() {
147+
box_stack.emplace(0, cs.m_box);
148+
int last_scoring = -score_update_start;
149+
int scoring_depth; // the last depth at which we did compute the score
150+
do {
151+
DREAL_LOG_INFO << "scoring_icp::solve - loop"
152+
<< "\t" << "box stack Size = " << box_stack.size();
153+
double const prec = cs.m_config.nra_delta_test ? 0.0 : cs.m_config.nra_precision;
154+
tuple<int, box> const branch = box_stack.top();
155+
box_stack.pop();
156+
int depth = get<0>(branch);
157+
cs.m_box = get<1>(branch);
158+
safe_prune(-1);
159+
last_scoring++;
160+
if (!cs.m_box.is_empty()) {
161+
if ( last_scoring < 0 // at the start
162+
|| last_scoring >= score_update_period // periodically recompute
163+
|| depth <= scoring_depth - backtrack_threshold ) { // recompute after backtrack
164+
prune_split_fixed_point();
165+
compute_scores();
166+
last_scoring = std::min(last_scoring, 0);
167+
scoring_depth = depth;
168+
if (cs.m_box.is_empty()) {
169+
continue;
170+
}
171+
}
172+
173+
int split = -1;
174+
if (scoring_vs_brancher <= 0 || last_scoring % scoring_vs_brancher == 0) {
175+
split = highest_score();
176+
}
177+
178+
if (split < 0) {
179+
vector<int> const sorted_dims = brancher.sort_branches(cs.m_box, ctrs, ctc.get_input(), cs.m_config, 1);
180+
if (sorted_dims.size() > 0) {
181+
split = sorted_dims[0];
182+
}
183+
}
184+
if (split >= 0) {
185+
tuple<int, box, box> splits = cs.m_box.bisect_at(split);
186+
if (cs.m_config.nra_use_stat) { cs.m_config.nra_stat.increase_branch(); }
187+
DREAL_LOG_INFO << "[branched on "
188+
<< cs.m_box.get_name(split)
189+
<< "]" << endl;
190+
box const & first = get<1>(splits);
191+
box const & second = get<2>(splits);
192+
int d1 = depth + 1;
193+
if (second.is_bisectable(prec)) {
194+
box_stack.emplace(d1, second);
195+
box_stack.emplace(d1, first);
196+
} else {
197+
box_stack.emplace(d1, first);
198+
box_stack.emplace(d1, second);
199+
}
200+
if (cs.m_config.nra_proof) {
201+
cs.m_config.nra_proof_out << "[branched on "
202+
<< cs.m_box.get_name(split)
203+
<< "]" << endl;
204+
}
205+
} else {
206+
for (unsigned i = 0; i < size; i++) {
207+
assert(!cs.m_box.is_bisectable_at(i, cs.m_config.nra_precision));
208+
}
209+
cs.m_config.nra_found_soln++;
210+
if (cs.m_config.nra_multiple_soln > 1) {
211+
// If --multiple_soln is used
212+
output_solution(cs.m_box, cs.m_config, cs.m_config.nra_found_soln);
213+
}
214+
if (cs.m_config.nra_found_soln >= cs.m_config.nra_multiple_soln) {
215+
break;
216+
}
217+
solns.push_back(cs.m_box);
218+
}
219+
}
220+
} while (box_stack.size() > 0);
221+
222+
if (cs.m_config.nra_multiple_soln > 1 && solns.size() > 0) {
223+
cs.m_box = solns.back();
224+
return;
225+
} else {
226+
assert(!cs.m_box.is_empty() || box_stack.size() == 0);
227+
return;
228+
}
229+
}
230+
231+
scoring_icp::scoring_icp(contractor & _ctc, contractor_status & _cs, scoped_vec<shared_ptr<constraint>> const & _ctrs, BranchHeuristic & _brancher):
232+
ctc(_ctc),
233+
cs(_cs),
234+
brancher(_brancher),
235+
ctrs(_ctrs),
236+
solns(),
237+
box_stack(),
238+
size(_cs.m_box.size()),
239+
scores(new double[_cs.m_box.size()]),
240+
prune_results(new double[_cs.m_box.size()]),
241+
nbr_prune(new unsigned int[_cs.m_box.size()]) {
242+
reset_scores();
243+
}
244+
245+
scoring_icp::~scoring_icp() {
246+
delete[] scores;
247+
delete[] prune_results;
248+
delete[] nbr_prune;
249+
}
250+
251+
void scoring_icp::solve(contractor & ctc, contractor_status & cs, scoped_vec<shared_ptr<constraint>> const & ctrs, BranchHeuristic & brancher) {
252+
scoring_icp icp(ctc, cs, ctrs, brancher);
253+
icp.solve();
254+
}
255+
256+
} // namespace dreal

src/icp/scoring_icp.h

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*********************************************************************
2+
Author: Damien Zufferey <[email protected]>
3+
4+
dReal -- Copyright (C) 2013 - 2016, the dReal Team
5+
6+
dReal is free software: you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation, either version 3 of the License, or
9+
(at your option) any later version.
10+
11+
dReal is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
GNU General Public License for more details.
15+
16+
You should have received a copy of the GNU General Public License
17+
along with dReal. If not, see <http://www.gnu.org/licenses/>.
18+
*********************************************************************/
19+
20+
#pragma once
21+
#include <stack>
22+
#include <tuple>
23+
#include <unordered_set>
24+
#include <vector>
25+
#include "./config.h"
26+
#include "contractor/contractor.h"
27+
#include "icp/brancher.h"
28+
#include "icp/icp.h"
29+
#include "opensmt/smtsolvers/SMTConfig.h"
30+
#include "util/box.h"
31+
#include "util/scoped_vec.h"
32+
33+
// can we make that fit into the BranchHeuristic
34+
namespace dreal {
35+
class scoring_icp {
36+
private:
37+
static BranchHeuristic & defaultHeuristic;
38+
39+
contractor & ctc;
40+
contractor_status & cs;
41+
BranchHeuristic & brancher;
42+
scoped_vec<std::shared_ptr<constraint>> const & ctrs;
43+
44+
std::vector<box> solns;
45+
std::stack<std::tuple<int, box>> box_stack;
46+
47+
unsigned int size;
48+
double * scores;
49+
double * prune_results;
50+
unsigned int * nbr_prune;
51+
52+
void reset_scores();
53+
void compute_scores();
54+
int highest_score();
55+
56+
double measure(box const & o, box const & n);
57+
58+
void safe_prune(int idx);
59+
void prune_split_fixed_point();
60+
61+
// A bunch of magic constants for the scoring heuristic.
62+
// Eventually, these should become options.
63+
64+
static int constexpr score_update_start = 10;
65+
static int constexpr score_update_period = 10;
66+
static double constexpr score_update_old_weight = 0.5;
67+
static double constexpr progress_threshold = 0.9;
68+
static int constexpr backtrack_threshold = 10;
69+
static int constexpr scoring_vs_brancher = 0;
70+
71+
void solve();
72+
73+
public:
74+
scoring_icp(contractor & ctc, contractor_status & cs,
75+
scoped_vec<std::shared_ptr<constraint>> const & ctrs,
76+
BranchHeuristic & heuristic);
77+
~scoring_icp();
78+
79+
static void solve(contractor & ctc, contractor_status & cs,
80+
scoped_vec<std::shared_ptr<constraint>> const & ctrs,
81+
BranchHeuristic & heuristic = defaultHeuristic);
82+
};
83+
} // namespace dreal

0 commit comments

Comments
 (0)