def _poly_weight(variable, coefficients): monomials = [] max_degree = len(coefficients) - 1 for i, coefficient in enumerate(coefficients): exponent = max_degree - i if exponent > 0: monomial = Times( [Real(coefficient), Pow(variable, Real(exponent))]) else: monomial = Real(coefficient) monomials.append(monomial) return Plus(monomials)
def _init_vars(self, t_init): t_vars = [Real(t_init)] x_vars = [] loc_vars = [] aux_vars = [] for k in xrange(self.n_steps + 1): loc_k = [] for l in xrange(len(self.locations)): var = PlanPRAiSE.LOC_NAME.format(k, l) loc_k.append(var) loc_vars.append(loc_k) for k in xrange(self.n_steps): x_vars.append(PlanPRAiSE.JOURNEY_NAME.format(k)) prev = " + ".join(x_vars) tvar = "({} + {})".format(t_init, prev) t_vars.append(tvar) aux_k = [] for p in xrange(len(self.partitions) - 1): if self.use_aux_vars: avar = PlanPRAiSE.AUX_NAME.format(p, k) else: last = (p == len(self.partitions) - 2) partition = (self.partitions[p], self.partitions[p + 1]) avar = IntoInterval(t_vars[k], partition, last) aux_k.append(avar) aux_vars.append(aux_k) return t_vars, x_vars, loc_vars, aux_vars
def compile_knowledge(self, path, t_departure): """Generates the model according to the given path. Keyword arguments: path -- a path in the SRN graph t_departure -- departure time. """ if len(path) <= 1: raise WMIRuntimeException("Path length should be > 1") self.n_steps = len(path) - 1 t_vars, x_vars, aux_vars = self._init_vars(t_departure) variable_definitions = [RealVar(x) for x in x_vars] if self.use_aux_vars: variable_definitions += [ BooleanVar(a) for ak in aux_vars for a in ak ] statements = [] cond_weights = [] # initialize t_0 (in WMI, this is passed as evidence) #time_equations.append(Equals(t_vars[0], str(t_departure))) for k in xrange(self.n_steps): # t^(k+1) = t^k + x^k #teq = Equals(t_vars[k+1], Plus([t_vars[k], x_vars[k]])) #time_equations.append(teq) src, dst = path[k], path[k + 1] # subformula encoding the transition from step k to step k+1 trans_k = self._transition(k, src, dst, t_vars, x_vars, aux_vars) statements.append(trans_k) for p in xrange(len(self.partitions) - 1): poly_var = x_vars[k] coeffs = self.graph[src][dst][p]['coefficients'] weight_f = SRNPRAiSE._poly_weight(poly_var, coeffs) cond_w = Ite(aux_vars[(p, k)], weight_f, Real(1)) cond_weights.append(cond_w) if self.encoding[UNION_CONSTRAINTS]: # bound each t^k to fall into a partition union_interval = self.partitions[0], self.partitions[-1] union_constraints = [ IntoInterval(t_vars[k], union_interval, True) for k in xrange(len(t_vars)) ] statements = statements + union_constraints add_terminator = lambda s: s + ";" statements = map(add_terminator, statements + cond_weights) self.model = "\n".join(variable_definitions + statements) self.time_vars = t_vars
def _transition(self, step, src, dst, t_vars, x_vars, aux_vars): auxiliary_vars = [] auxiliary_defs = [] support_constraints = [] for p in xrange(len(self.partitions) - 1): last = (p == len(self.partitions) - 2) aux = aux_vars[(p, step)] auxiliary_vars.append(aux) pt = (self.partitions[p], self.partitions[p + 1]) if self.use_aux_vars: interval = IntoInterval(t_vars[step], pt, last) if self.encoding[AUX_IFF]: aux_def = Iff(aux, interval) else: aux_def = Implies(interval, aux) auxiliary_defs.append(aux_def) if self.encoding[THEORY_CHAINS] and not last: lb1 = LE(Real(pt[0]), t_vars[step]) lb2 = LE(Real(pt[1]), t_vars[step]) auxiliary_defs.append(Implies(lb2, lb1)) # current time partition defines the range of the weight function # aux_p^k -> (R_p^min <= x^k <= R_p^max) rng = self.graph[src][dst][p]['range'] support_constr = Implies(aux_vars[(p, step)], IntoInterval(x_vars[step], rng, True)) support_constraints.append(support_constr) # bigwedge_p (aux_p^k <-> (P_p^begin <= t^k <= P_p^end)) trans_formula = And(support_constraints) if len(auxiliary_defs) > 0: trans_formula = And([trans_formula, And(auxiliary_defs)]) if self.use_aux_vars: if self.encoding[AUX_CONSTRAINTS] == 'xor': trans_formula = And( [trans_formula, ExactlyOne(auxiliary_vars)]) elif self.encoding[AUX_CONSTRAINTS] == 'or': trans_formula = And([trans_formula, Or(auxiliary_vars)]) return trans_formula
def _compute_weights(self, subgraph, edges, aux_vars, loc_vars, x_vars): conditionals = [] for i in xrange(self.n_steps): for src, dst in edges: l1 = self.locations.index(src) l2 = self.locations.index(dst) cond = And([loc_vars[i][l1], loc_vars[i + 1][l2]]) subconditionals = [] for p in xrange(len(self.partitions) - 1): subcond = aux_vars[i][p] poly_var = x_vars[i] coeffs = subgraph[src][dst][p]['coefficients'] weight_f = PlanPRAiSE._poly_weight(poly_var, coeffs) subconditionals.append(Ite(subcond, weight_f, Real(1))) conditional = Ite(cond, Times(subconditionals), Real(1)) conditionals.append(conditional) return conditionals
def departing_at(self, time): return Equals(self.time_vars[0], Real(time))
def arriving_before(self, time, index=-1): return LE(self.time_vars[index], Real(time))
def arriving_after(self, time, index=-1): return Not(LE(self.time_vars[index], Real(time)))
def compile_knowledge(self, subgraph, n_steps, init_location, final_location, t_departure): """Generates the model according to the path length, initial and final locations. Keyword arguments: subgraph -- subpart of the road network n_steps -- path length init_location -- str final_location -- str t_departure -- departure time """ if n_steps < 1: raise WMIRuntimeException("Path length should be > 0") self.n_steps = n_steps self.locations = subgraph.nodes() t_vars, x_vars, loc_vars, aux_vars = self._init_vars(t_departure) variable_definitions = [RealVar(x) for x in x_vars] + \ [BooleanVar(l) for lk in loc_vars for l in lk] if self.use_aux_vars: variable_definitions += [ BooleanVar(a) for ak in aux_vars for a in ak ] subformulas = [] for k in xrange(self.n_steps + 1): # exactly one location at each step subformulas.append(ExactlyOne(loc_vars[k])) relevant_edges = set() for k in xrange(self.n_steps): # each x^k should be nonnegative nonneg_x_k = LE(Real(0), x_vars[k]) subformulas.append(nonneg_x_k) if self.use_aux_vars: if self.encoding[AUX_CONSTRAINTS] == 'xor': subformulas.append(ExactlyOne(aux_vars[k])) elif self.encoding[AUX_CONSTRAINTS] == 'or': subformulas.append(Or(aux_vars[k])) #step_xor = set() for l in xrange(len(self.locations)): src = self.locations[l] cond = loc_vars[k][l] subsubformulas = [] for p in xrange(len(self.partitions) - 1): nxt = self.conditional_plan[(src, p, final_location)] if nxt in self.locations: nxt_expr = loc_vars[k + 1][self.locations.index(nxt)] if src != nxt: relevant_edges.add((src, nxt)) rng = subgraph[src][nxt][p]['range'] rng_expr = IntoInterval(x_vars[k], rng, True) else: rng_expr = Equals(x_vars[k], Real(0)) ssf = Implies(aux_vars[k][p], And([rng_expr, nxt_expr])) subsubformulas.append(ssf) if len(subsubformulas) > 0: subformulas.append(Implies(cond, And(subsubformulas))) for p in xrange(len(self.partitions) - 1): last = (p == len(self.partitions) - 2) partition = (self.partitions[p], self.partitions[p + 1]) if self.use_aux_vars: interval = IntoInterval(t_vars[k], partition, last) if self.encoding[AUX_IFF]: subformulas.append(Iff(aux_vars[k][p], interval)) else: subformulas.append(Implies(interval, aux_vars[k][p])) if self.encoding[THEORY_CHAINS] and not last: lb1 = LE(Real(partition[0]), t_vars[k]) lb2 = LE(Real(partition[1]), t_vars[k]) subformulas.append(Implies(lb2, lb1)) # initialization subformulas.append(loc_vars[0][self.locations.index(init_location)]) subformulas.append( loc_vars[self.n_steps][self.locations.index(final_location)]) if self.encoding[UNION_CONSTRAINTS]: # bound each t^k to fall into a partition union_interval = self.partitions[0], self.partitions[-1] union_constraints = [ IntoInterval(t_vars[k], union_interval, True) for k in xrange(len(t_vars)) ] subformulas.append(And(union_constraints)) cond_weights = self._compute_weights(subgraph, relevant_edges, aux_vars, loc_vars, x_vars) add_terminator = lambda s: s + ";" subformulas = map(add_terminator, subformulas + cond_weights) self.model = "\n".join(variable_definitions + subformulas) self.time_vars = t_vars
def arriving_before(self, time): return LE(self.time_vars[-1], Real(time))