3#ifndef LALA_POWER_SPLIT_STRATEGY_HPP
4#define LALA_POWER_SPLIT_STRATEGY_HPP
6#include "battery/vector.hpp"
7#include "battery/shared_ptr.hpp"
9#include "lala/logic/logic.hpp"
10#include "lala/abstract_deps.hpp"
40template <
class A,
class Allocator =
typename A::allocator_type>
51 constexpr static const bool sequential = sub_type::sequential;
61 constexpr static const char*
name =
"SplitStrategy";
63 template <
class Alloc>
80 template<
class SplitSnapshot>
89 template <
class Alloc2>
93 battery::vector<AVar, Alloc2>
vars;
105 return vars.get_allocator();
108 template <
class StrategyType>
109 CUDA
strategy_type(
const StrategyType& other,
const Alloc2& alloc = Alloc2{})
112 template <
class Alloc3>
116 template <
class Alloc2>
117 using tell_type = battery::vector<strategy_type<Alloc2>, Alloc2>;
119 template <
class A2,
class Alloc2>
123 using universe_type =
typename A::universe_type;
124 using LB =
typename universe_type::LB;
125 using UB =
typename universe_type::UB;
129 battery::vector<strategy_type<allocator_type>,
allocator_type> strategies;
130 int current_strategy;
131 int next_unassigned_var;
133 CUDA
const battery::vector<AVar, allocator_type>& current_vars()
const {
134 return strategies[current_strategy].vars;
137 CUDA NI
void move_to_next_unassigned_var() {
138 while(current_strategy < strategies.size()) {
139 const auto& vars = current_vars();
140 while(next_unassigned_var < vars.size()) {
142 a->project(vars[next_unassigned_var], v);
143 if(dual<UB>(v.lb()) < v.ub()) {
146 next_unassigned_var++;
149 next_unassigned_var = 0;
153 template <
class MapFunction>
154 CUDA NI AVar var_map_fold_left(
const battery::vector<AVar, allocator_type>& vars, MapFunction op) {
155 int i = next_unassigned_var;
157 auto best = op(a->project(vars[i]));
158 for(++i; i < vars.size(); ++i) {
159 const auto& u = a->project(vars[i]);
160 if(dual<UB>(u.lb()) < u.ub()) {
161 if(best.meet(op(u))) {
169 CUDA AVar select_var() {
170 const auto& strat = strategies[current_strategy];
171 const auto& vars = strat.vars;
172 switch(strat.var_order) {
176 case VariableOrder::LARGEST:
return var_map_fold_left(vars, [](
const universe_type& u) {
return dual<LB>(u.ub()); });
177 case VariableOrder::SMALLEST:
return var_map_fold_left(vars, [](
const universe_type& u) {
return dual<UB>(u.lb()); });
178 default: printf(
"BUG: unsupported variable order strategy\n"); assert(
false);
return AVar{};
183 CUDA NI
branch_type make_branch(AVar x, Sig left_op, Sig right_op,
const U& u) {
184 if((u.is_top() && U::preserve_top) || (u.is_bot() && U::preserve_bot)) {
186 printf(
"%% WARNING: Cannot currently branch on unbounded variables.\n");
190 using F = TFormula<allocator_type>;
191 using branch_vector = battery::vector<sub_tell_type, allocator_type>;
192 VarEnv<allocator_type> empty_env{};
193 auto k = u.template deinterpret<F>();
194 IDiagnostics diagnostics;
197 bool res = a->interpret_tell(F::make_binary(F::make_avar(x), left_op, k, x.aty(),
get_allocator()), empty_env, left, diagnostics);
198 res &= a->interpret_tell(F::make_binary(F::make_avar(x), right_op, k, x.aty(),
get_allocator()), empty_env, right, diagnostics);
200 return Branch(branch_vector({std::move(left), std::move(right)},
get_allocator()));
204 else if(left_op != LEQ || right_op != GT) {
205 return make_branch(x, LEQ, GT, u);
208 printf(
"%% WARNING: The subdomain does not support the underlying search strategy.\n");
219 atype(atype), a(a), current_strategy(0), next_unassigned_var(0), strategies(alloc)
222 template<
class A2,
class Alloc2,
class... Allocators>
224 : atype(other.atype),
225 a(deps.template clone<A>(other.a)),
227 current_strategy(other.current_strategy),
228 next_unassigned_var(other.next_unassigned_var)
236 return strategies.get_allocator();
239 template <
class Alloc2 = allocator_type>
244 template <
class Alloc2 = allocator_type>
247 strategies.pop_back();
255 current_strategy = 0;
256 next_unassigned_var = 0;
260 template <
bool diagnose = false,
class F,
class Env,
class Alloc2>
263 && f.eseq().size() >= 2
264 && f.esig() ==
"search"
265 && f.eseq()[0].is(F::ESeq) && f.eseq()[0].eseq().size() == 0
266 && f.eseq()[1].is(F::ESeq) && f.eseq()[1].eseq().size() == 0))
268 RETURN_INTERPRETATION_ERROR(
"SplitStrategy can only interpret predicates of the form `search(input_order, indomain_min, x1, ..., xN)`.");
271 const auto& var_order_str = f.eseq()[0].esig();
272 const auto& val_order_str = f.eseq()[1].esig();
279 RETURN_INTERPRETATION_ERROR(
"This variable order strategy is unsupported.");
281 if(val_order_str ==
"indomain_min") { strat.val_order =
ValueOrder::MIN; }
282 else if(val_order_str ==
"indomain_max") { strat.val_order =
ValueOrder::MAX; }
284 else if(val_order_str ==
"indomain_split") { strat.val_order =
ValueOrder::SPLIT; }
287 RETURN_INTERPRETATION_ERROR(
"This value order strategy is unsupported.");
289 for(
int i = 2; i < f.eseq().size(); ++i) {
290 if(f.eseq(i).is(F::LV)) {
291 strat.vars.push_back(AVar{});
292 if(!env.interpret(f.eseq(i), strat.vars.back(), diagnostics)) {
296 else if(f.eseq(i).is(F::V)) {
297 strat.vars.push_back(f.eseq(i).v());
299 else if(num_vars(f.eseq(i)) > 0) {
300 RETURN_INTERPRETATION_ERROR(
"The predicate `search` only supports variables or constants, but an expression containing a variable was passed to it.");
305 if(strat.vars.size() == 0) {
306 RETURN_INTERPRETATION_WARNING(
"The predicate `search` has no variable, and thus it is ignored.");
308 tell.push_back(std::move(strat));
312 template <IKind kind,
bool diagnose = false,
class F,
class Env,
class I>
313 CUDA
bool interpret(
const F& f, Env& env, I& intermediate, IDiagnostics& diagnostics)
const {
314 static_assert(kind == IKind::TELL);
322 template <
class Alloc2>
324 local::B has_changed =
false;
325 for(
int i = 0; i < t.size(); ++i) {
326 if(t[i].vars.size() > 0) {
327 strategies.push_back(t[i]);
344 move_to_next_unassigned_var();
345 if(current_strategy < strategies.size()) {
346 AVar x = select_var();
347 switch(strategies[current_strategy].val_order) {
348 case ValueOrder::MIN:
return make_branch(x, EQ, GT, a->project(x).lb());
349 case ValueOrder::MAX:
return make_branch(x, EQ, LT, a->project(x).ub());
351 case ValueOrder::SPLIT:
return make_branch(x, LEQ, GT, a->project(x).median().lb());
362 return strategies.size();
Definition split_strategy.hpp:41
static constexpr const bool is_abstract_universe
Definition split_strategy.hpp:50
static constexpr const bool sequential
Definition split_strategy.hpp:51
CUDA allocator_type get_allocator() const
Definition split_strategy.hpp:235
battery::vector< strategy_type< Alloc2 >, Alloc2 > tell_type
Definition split_strategy.hpp:117
CUDA SplitStrategy(const SplitStrategy< A2, Alloc2 > &other, AbstractDeps< Allocators... > &deps)
Definition split_strategy.hpp:223
Allocator allocator_type
Definition split_strategy.hpp:43
static constexpr const bool is_totally_ordered
Definition split_strategy.hpp:52
sub_type::template tell_type< allocator_type > sub_tell_type
Definition split_strategy.hpp:46
CUDA local::B deduce(const tell_type< Alloc2 > &t)
Definition split_strategy.hpp:323
A sub_type
Definition split_strategy.hpp:44
CUDA NI bool interpret_tell(const F &f, Env &env, tell_type< Alloc2 > &tell, IDiagnostics &diagnostics) const
Definition split_strategy.hpp:261
typename sub_type::allocator_type sub_allocator_type
Definition split_strategy.hpp:45
static constexpr const bool preserve_concrete_covers
Definition split_strategy.hpp:59
static constexpr const bool preserve_join
Definition split_strategy.hpp:56
static constexpr const char * name
Definition split_strategy.hpp:61
static constexpr const bool preserve_bot
Definition split_strategy.hpp:53
Branch< sub_tell_type, allocator_type > branch_type
Definition split_strategy.hpp:47
CUDA snapshot_type< Alloc2 > snapshot(const Alloc2 &alloc=Alloc2()) const
Definition split_strategy.hpp:240
CUDA AType aty() const
Definition split_strategy.hpp:231
CUDA SplitStrategy(AType atype, abstract_ptr< A > a, const allocator_type &alloc=allocator_type())
Definition split_strategy.hpp:218
static constexpr const bool preserve_meet
Definition split_strategy.hpp:57
CUDA void reset()
Definition split_strategy.hpp:254
CUDA bool interpret(const F &f, Env &env, I &intermediate, IDiagnostics &diagnostics) const
Definition split_strategy.hpp:313
CUDA void restore(const snapshot_type< Alloc2 > &snap)
Definition split_strategy.hpp:245
CUDA NI branch_type split()
Definition split_strategy.hpp:340
static constexpr const bool preserve_top
Definition split_strategy.hpp:54
CUDA size_t num_strategies() const
Definition split_strategy.hpp:361
static constexpr const bool injective_concretization
Definition split_strategy.hpp:58
VariableOrder
Definition split_strategy.hpp:14
ValueOrder
Definition split_strategy.hpp:28
Definition split_strategy.hpp:64
snapshot_type< Alloc > & operator=(const snapshot_type< Alloc > &)=default
snapshot_type< Alloc > & operator=(snapshot_type< Alloc > &&)=default
snapshot_type(snapshot_type< Alloc > &&)=default
int next_unassigned_var
Definition split_strategy.hpp:67
CUDA snapshot_type(const SplitSnapshot &other, const Alloc &)
Definition split_strategy.hpp:81
snapshot_type(const snapshot_type< Alloc > &)=default
size_t num_strategies
Definition split_strategy.hpp:65
CUDA snapshot_type(size_t num_strategies, int current_strategy, int next_unassigned_var)
Definition split_strategy.hpp:69
int current_strategy
Definition split_strategy.hpp:66
Definition split_strategy.hpp:90
ValueOrder val_order
Definition split_strategy.hpp:92
strategy_type(strategy_type< Alloc2 > &&)=default
strategy_type(const strategy_type< Alloc2 > &)=default
battery::vector< AVar, Alloc2 > vars
Definition split_strategy.hpp:93
CUDA strategy_type(VariableOrder var_order, ValueOrder val_order, battery::vector< AVar, Alloc2 > &&vars)
Definition split_strategy.hpp:100
CUDA strategy_type(const Alloc2 &alloc=Alloc2{})
Definition split_strategy.hpp:95
CUDA strategy_type(const StrategyType &other, const Alloc2 &alloc=Alloc2{})
Definition split_strategy.hpp:109
CUDA allocator_type get_allocator() const
Definition split_strategy.hpp:104
VariableOrder var_order
Definition split_strategy.hpp:91
Alloc2 allocator_type
Definition split_strategy.hpp:103
strategy_type & operator=(strategy_type< Alloc2 > &&)=default