def test_parse_assignment(self): pars = updateStatementParser.updateStatementParser("x = s") AST = pars.parseUpdateStatements() AST.visit() pars = updateStatementParser.updateStatementParser("x = s;") AST = pars.parseUpdateStatements() AST.visit()
def analyze_live_variables(self): for t_idx, t in enumerate(self.nta.templates): local_collect_variables = partial(self._collect_variables, t_idx=t_idx) logger.debug("In template %s:", t.name) for l_idx, l in enumerate(t.locations): if l.invariant.value: ast = expressionParser.parse_expression(l.invariant.value) if ast: ast.visit(local_collect_variables) #outgoing transitions for trans in t.transitions: #guard if trans.guard.value: ast = expressionParser.parse_expression(trans.guard.value) ast.visit(local_collect_variables) if trans.assignment.value: myparser = updateStatementParser.updateStatementParser( trans.assignment.value) ast = myparser.parseUpdateStatements() ast.visit(local_collect_variables) logger.debug("Live variables: \n %s", self.live_variables[t_idx])
def analyze_lower_upperbounds(self): """ Location dependent lower-upper bounds analysis, as described in "Static Guard Analysis in Timed Automata Verification" by Gerd Behrmann, Patricia Bouyer, Emmanuel Fleury and Kim G. Larsen and "Lower and Upper Bounds in Zone Based Abstractions of Timed Automata" by Gerd Behrmann, Patricia Bouyer, Kim G. Larsen and Radek Pelanek Uses the more general form of analysis, which is O(n^3). If only certain kinds of clock guards/resets are needed the O(n) algorithm can be implemented. Currently only handles updates of the form x := c, but could be expanded. Assumes all clocks are global. """ #Collect inequalities for t_idx, t in enumerate(self.nta.templates): self.live_clocks[t_idx] = [ c for c in self._clocks if c in self.live_variables[t_idx] ] logging.debug("Live clocks for %s: %s", t.name, self.live_clocks[t_idx]) numclocks = len(self.live_clocks[t_idx]) clocks_reset_proto = {} for c in self.live_clocks[t_idx]: clocks_reset_proto[c] = False #init empty graph numlocs = len(t.locations) logger.debug("Matrix of size %dx%d (%d locations, %d clocks)", numlocs * numclocks + 1, numlocs * numclocks + 1, numlocs, numclocks) lower_eq_graph = numpy.empty( [numlocs * numclocks + 1, numlocs * numclocks + 1], dtype=int) lower_eq_graph.fill(-1) upper_eq_graph = numpy.empty( [numlocs * numclocks + 1, numlocs * numclocks + 1], dtype=int) upper_eq_graph.fill(-1) for l_idx, l in enumerate(t.locations): if not l.invariant.value: continue logger.debug("At loc %s:", l) s = l.invariant.value ast = expressionParser.parse_expression(s) local_collect_comparisons = partial( self._lu_collect_comparisons, t_idx=t_idx, l_idx=l_idx, lower_eq_graph=lower_eq_graph, upper_eq_graph=upper_eq_graph) ast.visit(local_collect_comparisons) #outgoing transitions for trans in t.transitions: source_id = t.locations.index(trans.source) target_id = t.locations.index(trans.target) #guard if trans.guard.value: ast = expressionParser.parse_expression(trans.guard.value) local_collect_comparisons = partial( self._lu_collect_comparisons, t_idx=t_idx, l_idx=source_id, lower_eq_graph=lower_eq_graph, upper_eq_graph=upper_eq_graph) ast.visit(local_collect_comparisons) #dependencies through non-resetting for c in self.live_clocks[t_idx]: lower_eq_graph[self._calc_index(t_idx, source_id, c)][self._calc_index( t_idx, target_id, c)] = -1 upper_eq_graph[self._calc_index(t_idx, source_id, c)][self._calc_index( t_idx, target_id, c)] = -1 if trans.assignment.value: myparser = updateStatementParser.updateStatementParser( trans.assignment.value) ast = myparser.parseUpdateStatements() if ast.children[0] is None: logger.warning( "couldn't parse update \"%s\", doing safe upper approximation", trans.assignment.value) for c in self.live_clocks[t_idx]: lower_eq_graph[self._calc_index(t_idx, source_id, c)] \ [self._calc_index(t_idx, target_id, c)] = 0 upper_eq_graph[self._calc_index(t_idx, source_id, c)] \ [self._calc_index(t_idx, target_id, c)] = 0 else: clocks_reset = dict(clocks_reset_proto) local_collect_resets = partial( self._collect_resets, src_idx=source_id, dst_idx=target_id, clocks_reset=clocks_reset) ast.visit(local_collect_resets) for (c, reset) in clocks_reset.iteritems(): if not reset: lower_eq_graph[self._calc_index(t_idx, source_id, c)] \ [self._calc_index(t_idx, target_id, c)] = 0 upper_eq_graph[self._calc_index(t_idx, source_id, c)] \ [self._calc_index(t_idx, target_id, c)] = 0 else: for c in self.live_clocks[t_idx]: lower_eq_graph[self._calc_index(t_idx, source_id, c)][self._calc_index( t_idx, target_id, c)] = 0 upper_eq_graph[self._calc_index(t_idx, source_id, c)][self._calc_index( t_idx, target_id, c)] = 0 #logger.debug("lower_eq_graph: \n %s", lower_eq_graph) #logger.debug("upper_eq_graph: \n %s", upper_eq_graph) #Invert graph weights, to find longest paths instead lower_eq_graph = lower_eq_graph * -1 upper_eq_graph = upper_eq_graph * -1 #"1" now means no edge lower_eq_graph = self._all_pairs_shortest_path(lower_eq_graph, nan=1) upper_eq_graph = self._all_pairs_shortest_path(upper_eq_graph, nan=1) #invert graph back lower_eq_graph = lower_eq_graph * -1 upper_eq_graph = upper_eq_graph * -1 #logger.debug("lower_eq_graph, longest paths: \n %s", lower_eq_graph) #logger.debug("upper_eq_graph, longest paths: \n %s", upper_eq_graph) #collect output for l_idx, l in enumerate(t.locations): for c in self.live_clocks[t_idx]: #for backwards compatibility self.max_constants[t_idx][l_idx][c] = max( lower_eq_graph[self._calc_index(t_idx, l_idx, c)][0], upper_eq_graph[self._calc_index(t_idx, l_idx, c)][0]) self.lowerbound[t_idx][l_idx][c] = lower_eq_graph[ self._calc_index(t_idx, l_idx, c)][0] self.upperbound[t_idx][l_idx][c] = upper_eq_graph[ self._calc_index(t_idx, l_idx, c)][0] logger.debug("lower bounds: \n %s", self.lowerbound[t_idx]) logger.debug("upper bounds: \n %s", self.upperbound[t_idx])
def test_parse_comma_separated_statements(self): pars = updateStatementParser.updateStatementParser("x = s, t= f();", lexer.lexer) AST = pars.parseUpdateStatements() AST.visit()
def test_parse_comma_separated_statements(self): pars = updateStatementParser.updateStatementParser( "x = s, t= f();", lexer.lexer) AST = pars.parseUpdateStatements() AST.visit()