Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/01_batman/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,4 @@ int main()
DefaultFigure::draw_box(bi, { Color::black(), Color::red(0.4) });
}
#endif
}
}
2 changes: 1 addition & 1 deletion examples/03_sivia/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ int main()
{
VectorVar x(2);
AnalyticFunction f { {x}, sqr(x[0])*sin(sqr(x[0])+sqr(x[1]))-sqr(x[1]) };
auto p = sivia({{-5,5},{-4,4}}, f, {0,oo}, 1e-2, true);
auto p = sivia_multithread({{-5,5},{-4,4}}, f, {0,oo}, 1e-2, true);
DefaultFigure::draw_paving(p);
}
255 changes: 254 additions & 1 deletion src/core/paver/codac2_pave.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

#include "codac2_pave.h"
#include <chrono>

using namespace std;
using namespace codac2;
Expand All @@ -23,10 +24,18 @@ namespace codac2
PavingOut pave(const IntervalVector& x0, const CtcBase<IntervalVector>& c, double eps, bool verbose)
{
double time = 0;
return pave(x0,c,eps,time,verbose);
return pave(x0, c, eps, time, verbose);
}

PavingOut pave(const IntervalVector& x0, const CtcBase<IntervalVector>& c, double eps, double& time, bool verbose)
{
if (nb_threads()==1)
return pave_monothread(x0, c, eps, time, verbose);
else
return pave_multithread(x0, c, eps, time, verbose);
}

PavingOut pave_monothread(const IntervalVector& x0, const CtcBase<IntervalVector>& c, double eps, double& time, bool verbose)
{
assert_release(eps > 0.);
assert_release(!x0.is_empty());
Expand Down Expand Up @@ -72,13 +81,102 @@ namespace codac2
return p;
}

PavingOut pave_multithread(const IntervalVector& x0, const CtcBase<IntervalVector>& c, double eps, double& time, bool verbose)
{
assert_release(eps > 0.);
assert_release(!x0.is_empty());

auto start_time = std::chrono::high_resolution_clock::now();

int nthreads = nb_threads();

PavingOut p(x0);
// In order to be able to reconstruct the initial box, the first level represents the
// initial domain x0 (the left node is x0, the right one is an empty box).
p.tree()->bisect();
p.tree()->left()->boxes() = { x0 };
get<0>(p.tree()->right()->boxes()).set_empty();

std::shared_ptr<PavingOut_Node> n;
list<std::shared_ptr<PavingOut_Node>> l { p.tree()->left() };

while (l.size() < static_cast<std::size_t>(nthreads))
{
n = l.front();
l.pop_front();

c.contract(get<0>(n->boxes()));

if(!get<0>(n->boxes()).is_empty())
{
if(get<0>(n->boxes()).max_diam() > eps)
{
n->bisect();
l.push_back(n->left());
l.push_back(n->right());
}
}
}

std::vector<std::shared_ptr<PavingOut_Node>> l_vec(l.begin(), l.end());

auto worker = [&](int tid)
{
auto xi = l_vec[tid];
std::list<std::shared_ptr<PavingOut_Node>> li = { xi };
while(!li.empty())
{
auto ni = li.front();
li.pop_front();

c.contract(get<0>(ni->boxes()));

if(!get<0>(ni->boxes()).is_empty())
{
if(get<0>(ni->boxes()).max_diam() > eps)
{
ni->bisect();
li.push_back(ni->left());
li.push_back(ni->right());
}
}
}
};

std::vector<std::thread> threads;
for (int tid = 0; tid < nthreads; tid++)
threads.emplace_back(worker, tid);

for (auto& th : threads) th.join();

std::chrono::duration<double> elapsed = std::chrono::high_resolution_clock::now() - start_time;

time = elapsed.count();

if(verbose)
{
printf("Number of thread used: %d\n", nthreads);
printf("Computation time: %.4fs\n\n", time);
}

return p;
}

PavingInOut pave(const IntervalVector& x0, std::shared_ptr<const SepBase> s,
double eps, bool verbose)
{
return pave(x0, *s, eps, verbose);
}

PavingInOut pave(const IntervalVector& x0, const SepBase& s, double eps, bool verbose)
{
if (nb_threads()==1)
return pave_monothread(x0, s, eps, verbose);
else
return pave_multithread(x0, s, eps, verbose);
}

PavingInOut pave_monothread(const IntervalVector& x0, const SepBase& s, double eps, bool verbose)
{
assert_release(eps > 0.);
assert_release(!x0.is_empty());
Expand Down Expand Up @@ -111,6 +209,75 @@ namespace codac2
return p;
}

PavingInOut pave_multithread(const IntervalVector& x0, const SepBase& s, double eps, bool verbose)
{
assert_release(eps > 0.);
assert_release(!x0.is_empty());

auto start_time = std::chrono::high_resolution_clock::now();

int nthreads = nb_threads();

PavingInOut p(x0);
std::shared_ptr<PavingInOut_Node> n;
list<std::shared_ptr<PavingInOut_Node>> l { p.tree() };

while (l.size() < static_cast<std::size_t>(nthreads))
{
n = l.front();
l.pop_front();

auto xs = s.separate(get<0>(n->boxes()));
auto boundary = (xs.inner & xs.outer);
n->boxes() = { xs.outer, xs.inner };

if(!boundary.is_empty() && boundary.max_diam() > eps)
{
n->bisect();
l.push_back(n->left());
l.push_back(n->right());
}
}

std::vector<std::shared_ptr<PavingInOut_Node>> l_vec(l.begin(), l.end());

auto worker = [&](int tid)
{
auto xi = l_vec[tid];
std::list<std::shared_ptr<PavingInOut_Node>> li = { xi };
while(!li.empty())
{
auto ni = li.front();
li.pop_front();

auto xs = s.separate(get<0>(ni->boxes()));
auto boundary = (xs.inner & xs.outer);
ni->boxes() = { xs.outer, xs.inner };

if(!boundary.is_empty() && boundary.max_diam() > eps)
{
ni->bisect();
li.push_back(ni->left());
li.push_back(ni->right());
}
}
};

std::vector<std::thread> threads;
for (int tid = 0; tid < nthreads; tid++)
threads.emplace_back(worker, tid);

for (auto& th : threads) th.join();

if(verbose)
{
printf("Number of thread used: %d\n", nthreads);
std::chrono::duration<double> elapsed = std::chrono::high_resolution_clock::now() - start_time;
printf("Computation time: %.4fs\n\n", elapsed.count());
}
return p;
}

PavingInOut regular_pave(const IntervalVector& x0,
const std::function<BoolInterval(const IntervalVector&)>& test,
double eps, bool verbose)
Expand Down Expand Up @@ -156,6 +323,92 @@ namespace codac2
return p;
}

PavingInOut regular_pave_multithread(const IntervalVector& x0,
const std::function<BoolInterval(const IntervalVector&)>& test,
double eps, bool verbose)
{
assert_release(eps > 0.);
assert_release(!x0.is_empty());

auto start_time = std::chrono::high_resolution_clock::now();

int nthreads = nb_threads();

PavingInOut p(x0);
std::list<std::shared_ptr<PavingInOut_Node>> l { p.tree() };

while (l.size() < static_cast<std::size_t>(nthreads))
{
auto n = l.front();
l.pop_front();

auto b = test(std::get<1>(n->boxes()));
switch(b)
{
case BoolInterval::TRUE:
std::get<1>(n->boxes()).set_empty();
break;

case BoolInterval::FALSE:
std::get<0>(n->boxes()).set_empty();
break;

default:
n->bisect();
l.push_back(n->left());
l.push_back(n->right());
}
}

std::vector<std::shared_ptr<PavingInOut_Node>> l_vec(l.begin(), l.end());

auto worker = [&](int tid)
{
auto xi = l_vec[tid];
std::list<std::shared_ptr<PavingInOut_Node>> li = { xi };
while(!li.empty())
{
auto ni = li.front();
li.pop_front();

auto b = test(std::get<1>(ni->boxes()));
switch(b)
{
case BoolInterval::TRUE:
std::get<1>(ni->boxes()).set_empty();
break;

case BoolInterval::FALSE:
std::get<0>(ni->boxes()).set_empty();
break;

default:
if(ni->unknown().max_diam() > eps)
{
ni->bisect();
li.push_back(ni->left());
li.push_back(ni->right());
}
}
}
};

std::vector<std::thread> threads;
for (int tid = 0; tid < nthreads; tid++)
threads.emplace_back(worker, tid);

for (auto& th : threads) th.join();

if (verbose)
{
printf("Number of thread used: %d\n", nthreads);
std::chrono::duration<double> elapsed = std::chrono::high_resolution_clock::now() - start_time;
printf("Computation time: %.4fs\n\n", elapsed.count());
}

return p;
}

PavingInOut pave_tube(const IntervalVector& x0, const SlicedTube<IntervalVector>& f, double eps, bool verbose)
{
return regular_pave(x0,
Expand Down
31 changes: 29 additions & 2 deletions src/core/paver/codac2_pave.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,50 @@
#include "codac2_AnalyticFunction.h"
#include "codac2_BoolInterval.h"
#include "codac2_SlicedTube.h"
#include "codac2_threading.h"

namespace codac2
{
// eps: accuracy of the paving algorithm, the undefined boxes will have their max_diam <= eps

PavingOut pave(const IntervalVector& x0, std::shared_ptr<const CtcBase<IntervalVector>> c, double eps, bool verbose = false);
PavingOut pave(const IntervalVector& x0, const CtcBase<IntervalVector>& c, double eps, double& time, bool verbose = false);
PavingOut pave(const IntervalVector& x0, std::shared_ptr<const CtcBase<IntervalVector>> c, double eps, bool verbose = false);
PavingOut pave(const IntervalVector& x0, const CtcBase<IntervalVector>& c, double eps, bool verbose = false);
PavingOut pave_monothread(const IntervalVector& x0, const CtcBase<IntervalVector>& c, double eps, double& time, bool verbose = false);
PavingOut pave_multithread(const IntervalVector& x0, const CtcBase<IntervalVector>& c, double eps, double& time, bool verbose = false);

PavingInOut pave(const IntervalVector& x0, std::shared_ptr<const SepBase> s, double eps, bool verbose = false);
PavingInOut pave(const IntervalVector& x0, const SepBase& s, double eps, bool verbose = false);
PavingInOut pave_monothread(const IntervalVector& x0, const SepBase& s, double eps, bool verbose = false);
PavingInOut pave_multithread(const IntervalVector& x0, const SepBase& s, double eps, bool verbose = false);

PavingInOut regular_pave(const IntervalVector& x0, const std::function<BoolInterval(const IntervalVector&)>& test, double eps, bool verbose = false);
PavingInOut regular_pave_multithread(const IntervalVector& x0, const std::function<BoolInterval(const IntervalVector&)>& test, double eps, bool verbose = false);

template<typename Y>
PavingInOut sivia(const IntervalVector& x0, const AnalyticFunction<Y>& f, const typename Y::Domain& y, double eps, bool verbose = false)
{
return regular_pave(x0,
if (nb_threads()==1)
{
return regular_pave(x0,
[&y,&f](const IntervalVector& x)
{
auto eval = f.eval(x);

if(eval.is_subset(y))
return BoolInterval::TRUE;

else if(!eval.intersects(y))
return BoolInterval::FALSE;

else
return BoolInterval::UNKNOWN;
},
eps, verbose);
}
else
{
return regular_pave_multithread(x0,
[&y,&f](const IntervalVector& x)
{
auto eval = f.eval(x);
Expand All @@ -47,6 +73,7 @@ namespace codac2
return BoolInterval::UNKNOWN;
},
eps, verbose);
}
}

PavingInOut pave_tube(const IntervalVector& x0, const SlicedTube<IntervalVector>& f, double eps, bool verbose = false);
Expand Down
Loading