def addition_n(size): f = Function("add").returns(Int()) for i in range(size): f.takes(Int()) code = "+".join(p.name for p in f.params) f.code("return {};".format(code)) return f
def multiplication_n(size): f = Function("mul").returns(Int()) for i in range(size): f.takes(Int()) code = "*".join(p.name for p in f.params) f.code("return {};".format(code)) return f
def first(self, if_empty_value=None): f = Function(("iterator_first", self), returns=self.element_type) if if_empty_value is None: f.code( """ {{itype}} iterator; {{reset_fn}}(iterator); assert ({{is_valid_fn}}(iterator)); return {{value_fn}}(iterator); """, itype=self.itype, reset_fn=self.reset_fn, is_valid_fn=self.is_valid_fn, value_fn=self.value_fn) else: f.code( """ {{itype}} iterator; {{reset_fn}}(iterator); if ({{is_valid_fn}}(iterator)) { return {{value_fn}}(iterator); } else { return {{if_empty_value}}; } """, itype=self.itype, reset_fn=self.reset_fn, is_valid_fn=self.is_valid_fn, value_fn=self.value_fn, if_empty_value=self.element_type.value(if_empty_value)) return f()
def reduce(self, function): f = Function(("reduce", self), returns=self.element_type) f.code( """ {{itype}} iterator; {{reset_fn}}(iterator); if (!({{is_valid_fn}}(iterator))) { fprintf(stderr, "Reduce on empty iterator\\n"); exit(1); } {{type}} value = {{value_fn}}(iterator); {{next_fn}}(iterator); while({{is_valid_fn}}(iterator)) { value = {{function}}(value, {{value_fn}}(iterator)); {{next_fn}}(iterator); } return value; """, function=function, itype=self.itype, type=self.element_type, value_fn=self.value_fn, next_fn=self.next_fn, reset_fn=self.reset_fn, is_valid_fn=self.is_valid_fn) return f()
def __init__(self, start, end=None, step=1): if end is None: end = start start = 0 start = Int().value(start) end = Int().value(end) step = Int().value(step) iterator = RangeIterator(start, end, step) generator = rand_int(start, end) if (start.is_constructor() and start.value == 0 and step.is_constructor() and step.value == 1): size = end indexer = identity else: size = range_size(start, end, step) indexer = Function().returns(Int()) indexer.takes(Int(), "_v") indexer.code("return (_v - {{start}}) / {{step}};", start=start, step=step) super().__init__(Int(), iterator, generator, size, indexer)
def is_nonempty(self): f = Function(("is_iterator_nonempty", self), returns=Bool()) f.code( """ {{itype}} iterator; {{reset_fn}}(iterator); return {{is_valid_fn}}(iterator); """, itype=self.itype, reset_fn=self.reset_fn, is_valid_fn=self.is_valid_fn) return f()
def __init__(self, type, values): values = tuple(type.value(v) for v in values) iterator = ValuesIterator(type, values) generator = Function().returns(type) generator.code(""" switch({{rand_int}}(0, {{_size}})) { {%- for i, v in _values %} case {{i}}: return {{b(v)}}; {%- endfor %} default: assert(0); } """, _values=enumerate(values), _size=len(values), rand_int=rand_int) generator.uses(values) super().__init__(type, iterator, generator())
def first_maybe(self): maybe = Maybe(self.element_type) f = Function(("iterator_first_maybe", self), returns=maybe) f.code( """ {{itype}} iterator; {{reset_fn}}(iterator); if ({{is_valid_fn}}(iterator)) { return {{maybe}}(Just, {{value_fn}}(iterator)); } else { return {{maybe}}(Nothing); } """, itype=self.itype, reset_fn=self.reset_fn, is_valid_fn=self.is_valid_fn, value_fn=self.value_fn, maybe=maybe) return f()
def to_vector(self): vector = Vector(self.element_type) f = Function(returns=vector) f.code( """ {{vector}} output; {{itype}} iterator; {{reset_fn}}(iterator); while({{is_valid_fn}}(iterator)) { output.push_back({{value_fn}}(iterator)); {{next_fn}}(iterator); }; return output; """, itype=self.itype, reset_fn=self.reset_fn, next_fn=self.next_fn, is_valid_fn=self.is_valid_fn, value_fn=self.value_fn, vector=vector) return f()
def _make_generator(self, type, domains, ratios): generators = tuple(d.generator for d in domains) f = Function(returns=type) f.code(""" qint s = 0; {%- for r in _ratios %} s += {{b(r)}}; {%- if not loop.last %} qint r{{loop.index0}} = s; {%- endif %} {%- endfor %} qint r = {{rand_int}}(0, s); {%- for g in _generators %} {%- if not loop.last %} if (r < r{{loop.index0}}) {% endif %} { return {{b(g)}}; } {%- endfor %} """, _generators=generators, _ratios=ratios, rand_int=rand_int) f.uses(generators + ratios) return f()
def __init__(self, iterator, ascending=True, cmp_fn=None): itype = Int() * Vector(iterator.element_type) super().__init__(itype, iterator.element_type) if cmp_fn is None: cmp_fn = Function("compare").takes(iterator.element_type, "e1")\ .takes(iterator.element_type, "e2")\ .returns(Bool()) cmp_fn.code("return e1 < e2;") # Since iter.v1 is never changed, we use it to detect # if reset_fn is called for the first time, # or if reset is used to restart existing iterator self.reset_fn.code(""" iter.v0 = 0; if (iter.v1.size() == 0) { iter.v1 = {{vector}}; std::sort(iter.v1.begin(), iter.v1.end(), {{compare}}); } """, vector=iterator.to_vector(), compare=cmp_fn) self.next_fn.code("iter.v0++;"); self.is_valid_fn.code("return iter.v0 < iter.v1.size();"); self.value_fn.code("return iter.v1[iter.v0];");
size = range_size(start, end, step) indexer = Function().returns(Int()) indexer.takes(Int(), "_v") indexer.code("return (_v - {{start}}) / {{step}};", start=start, step=step) super().__init__(Int(), iterator, generator, size, indexer) range_size = Function() range_size.takes(Int(), "start") range_size.takes(Int(), "end") range_size.takes(Int(), "step") range_size.returns(Int()) range_size.code("return (end - start) / step;") class RangeIterator(Iterator): def __init__(self, start, end, step): itype = Int() super().__init__(itype, Int()) self.reset_fn.code("iter = {{start}};", start=start) self.next_fn.code("iter+={{step}};", step=step) self.is_valid_fn.code("return iter < {{end}};", end=end) self.value_fn = identity
def key_fn(self): f = Function().takes(self, "keyval").returns(self.types[0]) f.code("return keyval.key;") return f
def value_fn(self): f = Function().takes(self, "keyval").returns(self.types[1]) f.code("return keyval.value;") return f
def min_fn(self): f = Function().takes(self, "keyval1").takes(self, "keyval2") f.returns(self) f.code("return keyval1.value > keyval2.value ? keyval2 : keyval1;") return f
from qit.base.function import Function from qit.base.int import Int rand_int = Function("rand_int") rand_int.takes(Int(), "from").takes(Int(), "to") rand_int.returns(Int()) rand_int.code("return std::uniform_int_distribution<qint>(from, to - 1)(QIT_GENERATOR);")
mul = multiplication_n(2) def addition_n(size): f = Function("add").returns(Int()) for i in range(size): f.takes(Int()) code = "+".join(p.name for p in f.params) f.code("return {};".format(code)) return f add = addition_n(2) # Naive way of making power, but it is sufficient for now power = Function("power").takes(Int(), "base").takes(Int(), "power").returns(Int()) power.code(""" int result = 1; int p = power; while(p > 0) { result *= base; p--; } return result; """) identity = Function("identity") identity.takes(Int(), "a").returns(Int()).code("return a;") subtract = Function("subtract") subtract.takes(Int(), "a").takes(Int(), "b").returns(Int()) subtract.code("return a - b;")
def __init__(self, system, depth, return_depth): state_type = system.state_type sas_type = system.sas_type if return_depth: element_type = system.sas_depth_type else: element_type = sas_type eq_states_fn = system.eq_states_fn if eq_states_fn is None: eq_states_fn = Function("eq_states").takes(state_type, "s1")\ .takes(state_type, "s2")\ .returns(Bool()) eq_states_fn.code("return s1 == s2;") cmp_states_fn = system.cmp_states_fn if cmp_states_fn is None: cmp_states_fn = Function("compare_states").takes(state_type, "s1")\ .takes(state_type, "s2")\ .returns(Bool()) cmp_states_fn.code("return s1 < s2;") depth = Int().value(depth) state_ids_type = Map(state_type, Int(), cmp_states_fn) itype = Struct((state_ids_type, "state_ids"), (Vector(state_type), "current"), (Vector(state_type), "next"), (Vector(sas_type), "buff_values"), (sas_type, "value"), (Int(), "rule"), (Int(), "depth"), (Int(), "gen_state_id")) super().__init__(itype, element_type) functions = tuple(rule.function for rule in system.rules) action_type1 = None action_type2 = None new_value_fn = None new_values_fn = None if functions: action_type1 = Functor("atype1", state_type, (state_type, "s")) new_value_fn = Function("compute_new_value")\ .takes(itype, "iter", const=False)\ .takes(state_type, "current")\ .takes(system.action_names, "action_name")\ .takes(action_type1, "action_fn")\ .returns(Vector(sas_type)) new_value_fn.code(""" {{state}} new_state = action_fn(current); auto it = iter.state_ids.find(new_state); if (it == iter.state_ids.end()) { iter.state_ids[new_state] = ++iter.gen_state_id; iter.next.push_back(new_state); } return { {{sas}}(iter.state_ids[current], action_name, iter.state_ids[new_state]) }; """, state=state_type, sas=sas_type) action_type2 = Functor( "atype1", Vector(state_type), (state_type, "s")) new_values_fn = Function("compute_new_values")\ .takes(itype, "iter", const=False)\ .takes(state_type, "current")\ .takes(system.action_names, "action_name")\ .takes(action_type2, "action_fn")\ .returns(Vector(sas_type)) new_values_fn.code(""" std::vector<{{sas}} > buff; std::vector<{{state}} > new_states = action_fn(current); for ({{state}} &s : new_states) { auto s_it = iter.state_ids.find(s); if (s_it == iter.state_ids.end()) { iter.state_ids[s] = ++iter.gen_state_id; iter.next.push_back(s); } {{sas}} value(iter.state_ids[current], action_name, iter.state_ids[s]); auto sas_it = std::find(buff.begin(), buff.end(), value); if (sas_it == buff.end()) { buff.push_back(value); } } std::reverse(buff.begin(), buff.end()); return buff; """, state=state_type, sas=sas_type) functions += (new_value_fn, new_values_fn) self.reset_fn.code(""" iter.gen_state_id = 0; iter.rule = 0; iter.depth = 0; iter.state_ids = {{states_empty_map}}; iter.current = {{vector}}; if (iter.current.size() > 1) { std::sort(iter.current.begin(), iter.current.end()); // same initial states are reducet to only one auto it = std::unique(iter.current.begin(), iter.current.end(), {{eq_states}}); iter.current.resize(std::distance( iter.current.begin(), it)); } for (auto &e : iter.current) { iter.state_ids[e] = ++iter.gen_state_id; } iter.next.clear(); {# first call of the next function fills first values, if there are some #} {{next_fn}}(iter); if (iter.buff_values.size() == 0) { iter.current.clear(); } """, vector=system.state_iterator.to_vector(), states_empty_map=state_ids_type.value( {} ), eq_states=eq_states_fn, next_fn=self.next_fn) self.next_fn.code(""" {%- if _new_value is not none %} if (iter.buff_values.size() > 0) { iter.buff_values.pop_back(); // remove the previous one // set value if there is some if (iter.buff_values.size() > 0) { iter.value = iter.buff_values[iter.buff_values.size()-1]; return; } } for (;;) { if (iter.current.size() == 0) { if (iter.next.size() == 0 || iter.depth >= {{depth}}) { iter.next.clear(); return; } iter.depth++; std::swap(iter.current, iter.next); } switch(iter.rule) { {%- for rule in _rules %} case {{loop.index0}}: { {# different functions for types one value and more values #} {%- if rule.rule_type == 0 %} iter.buff_values = {{b(_new_value)}}( iter, iter.current[iter.current.size()-1], {{action}}(iter.rule), {{b(rule.function)}}); {%- endif %} {%- if rule.rule_type == 1 %} iter.buff_values = {{b(_new_values)}}( iter, iter.current[iter.current.size()-1], {{action}}(iter.rule), {{b(rule.function)}}); {%- endif %} iter.rule++; if (iter.buff_values.size() > 0) { iter.value = iter.buff_values[iter.buff_values.size()-1]; return; } } {%- endfor %} default: iter.rule = 0; iter.current.pop_back(); } } {%- endif %} """, _rules=system.rules, _new_value=new_value_fn, _new_values=new_values_fn, action=system.action_names, depth=depth).uses(functions) self.is_valid_fn.code(""" return !(iter.current.size() == 0 && iter.next.size() == 0 && iter.buff_values.size() == 0); """) if return_depth: self.value_fn.code( "return { iter.value, iter.depth };") else: self.value_fn.code( "return iter.value;")