Commit 8d62bb9b authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files

Implement breadth first search

parent 35674081
...@@ -152,17 +152,34 @@ def compute_choice_combinations(asn1_ty, pool): ...@@ -152,17 +152,34 @@ def compute_choice_combinations(asn1_ty, pool):
yield '{}: {}'.format(discr, each) yield '{}: {}'.format(discr, each)
def myproduct(*iterables):
''' Custom implementation of itertools.product - standard product
has to consume the iterables completely before making the product,
meaning it is useless with large iterable due to memory usage '''
if len(iterables) == 0:
raise StopIteration
else:
for item in iterables[0]():
for items in myproduct(*iterables[1:]):
yield (item, ) + items
def compute_sequence_combinations(asn1_ty, pool): def compute_sequence_combinations(asn1_ty, pool):
''' Generator returning all combinations of SEQUENCE types ''' ''' Generator returning all combinations of SEQUENCE types '''
# Prepare generators to compute combinations of each field # Prepare generators to compute combinations of each field
elems = (compute_combinations(sort, pool) elems = [lambda: compute_combinations(sort, pool)
for sort in asn1_ty.Children.viewvalues()) for sort in asn1_ty.Children.viewvalues()]
# Combine all field generators to get the complete set of values # Combine all field generators to get the complete set of values
for each in itertools.product(*elems): elems_lambda = [lambda: elem() for elem in elems]
# This is not quite right. XXX
#for each in itertools.product(*elems):
for each in myproduct(*elems_lambda):
# "each" contains a generator per field in the SEQUENCE
# each is a tuple with values for the sequence, join with fieldnames # each is a tuple with values for the sequence, join with fieldnames
pairs = itertools.izip(asn1_ty.Children.viewkeys(), each) pairs = itertools.izip(asn1_ty.Children.viewkeys(), each)
res = ('{} {}'.format(name, value) for name, value in pairs) res = ('{} {}'.format(name, value) for name, value in pairs)
yield '{{ {} }}'.format(', '.join(res)) res_yield = '{{ {} }}'.format(', '.join(res))
yield res_yield
def compute_sequenceof_combinations(asn1_ty, pool): def compute_sequenceof_combinations(asn1_ty, pool):
...@@ -172,4 +189,5 @@ def compute_sequenceof_combinations(asn1_ty, pool): ...@@ -172,4 +189,5 @@ def compute_sequenceof_combinations(asn1_ty, pool):
for _ in xrange(size): for _ in xrange(size):
elems.append(compute_combinations(asn1_ty, pool)) elems.append(compute_combinations(asn1_ty, pool))
for each in itertools.product(*elems): for each in itertools.product(*elems):
yield '{{ {} }}'.format(', '.join(each)) res = '{{ {} }}'.format(', '.join(each))
yield res
...@@ -25,6 +25,7 @@ import ctypes ...@@ -25,6 +25,7 @@ import ctypes
import random import random
from functools import partial from functools import partial
from itertools import chain from itertools import chain
from collections import deque
from PySide.QtGui import (QDockWidget, QPushButton, QGridLayout, QListWidget, from PySide.QtGui import (QDockWidget, QPushButton, QGridLayout, QListWidget,
QUndoStack, QUndoCommand, QToolButton, QTableWidget, QUndoStack, QUndoCommand, QToolButton, QTableWidget,
...@@ -535,9 +536,8 @@ class sdlHandler(QObject): ...@@ -535,9 +536,8 @@ class sdlHandler(QObject):
self.log_area.addItem('Sent {}({})'.format(tc_name, self.log_area.addItem('Sent {}({})'.format(tc_name,
param or '')) param or ''))
if check_ppty: if check_ppty:
# When doing undo, dont check propertis again # When doing undo, dont check properties again
self.check_properties(new_hash) self.check_properties(new_hash)
#self.check_properties(new_hash)
return new_hash return new_hash
def update_button_state(self, tc_name=None): def update_button_state(self, tc_name=None):
...@@ -673,7 +673,9 @@ class sdlHandler(QObject): ...@@ -673,7 +673,9 @@ class sdlHandler(QObject):
''' For all combinations of a given interface parameter, execute ''' For all combinations of a given interface parameter, execute
the PI, save the resulting state, undo, and yield the state ''' the PI, save the resulting state, undo, and yield the state '''
if asn1_ty: if asn1_ty:
print 'Exhausting', name
for arg in compute_combinations(asn1_ty, self.proc.dataview): for arg in compute_combinations(asn1_ty, self.proc.dataview):
#print name, arg
self.click_tc(name, arg) self.click_tc(name, arg)
new_hash = self.current_hash new_hash = self.current_hash
self.undo() self.undo()
...@@ -691,56 +693,87 @@ class sdlHandler(QObject): ...@@ -691,56 +693,87 @@ class sdlHandler(QObject):
sort = inp.get('type', None) sort = inp.get('type', None)
if sort: if sort:
asn1_ty = self.proc.dataview[sort.ReferencedTypeName] asn1_ty = self.proc.dataview[sort.ReferencedTypeName]
exhaust_interface(name, ty) for each in exhaust_interface(name, asn1_ty):
yield each
def breadth_first(self, max_states=100):
''' Create and explore the state graph with breadth first '''
# Fifo contains the hash, and a tuple (PI, Param) to reach it
fifo = deque([(self.current_hash, (None, None))])
visited = deque(fifo)
scenario = deque()
nb_states = 0
while fifo:
state, (trans_name, trans_param) = fifo.popleft()
if trans_name:
scenario.append((trans_name, trans_param))
self.restore_global_state(state)
for sibling, (trans_name, trans_param) in self.children_states():
if sibling not in visited:
visited.append(sibling)
if not self.stop_conditions:
# Cut branch if there are stop conditions
fifo.append((sibling, (trans_name, trans_param)))
else:
scenario.append((trans_name, trans_param))
print 'Stop conditions met:', self.stop_conditions
print 'Scenario:'
for (pi, arg) in scenario:
print (' {} ({})'.format(pi, arg))
nb_states += 1
if nb_states >= max_states:
return
def exhaustive_simulation(self): def exhaustive_simulation(self):
''' Model checker - try all combinations of all inputs in all ''' Model checker - try all combinations of all inputs in all
possible states, and verify properties on the fly ''' possible states, and verify properties on the fly '''
# DEPRECATED FUNCTION # DEPRECATED FUNCTION
print 'Exhaustive simulation (Breadth first)' print 'Exhaustive simulation (Breadth first)'
next_level = [] self.breadth_first()
self.sim_param['state'] = 'exhaustive'
total_err = 0 # next_level = []
# self.sim_param['state'] = 'exhaustive'
def exhaust_interface(name, asn1_ty): # total_err = 0
''' Send all combinations of an input signal and return #
a list of new states (should be doing this in a worker thread) ''' # def exhaust_interface(name, asn1_ty):
error = 0 # ''' Send all combinations of an input signal and return
new_hashes = [] # a list of new states (should be doing this in a worker thread) '''
if asn1_ty: # error = 0
for arg in compute_combinations(asn1_ty, self.proc.dataview): # new_hashes = []
QApplication.processEvents() # if asn1_ty:
if self.sim_param['state'] != 'exhaustive': # for arg in compute_combinations(asn1_ty, self.proc.dataview):
return new_hashes, error # QApplication.processEvents()
self.click_tc(name, arg) # if self.sim_param['state'] != 'exhaustive':
if self.new_state_created: # return new_hashes, error
# Create new state only if no stop conditions # self.click_tc(name, arg)
if not self.stop_conditions: # if self.new_state_created:
new_hashes.append((name, arg, self.current_hash)) # # Create new state only if no stop conditions
else: # if not self.stop_conditions:
# TODO: generate scenario # new_hashes.append((name, arg, self.current_hash))
error += 1 # else:
self.undo() # # TODO: generate scenario
else: # error += 1
self.click_tc(name) # self.undo()
if self.new_state_created: # else:
new_hashes.append((name, None, self.current_hash)) # self.click_tc(name)
self.undo() # if self.new_state_created:
return new_hashes, error # new_hashes.append((name, None, self.current_hash))
for name in self.active_tc: # self.undo()
ty = None # return new_hashes, error
for inp in self.proc.input_signals: # for name in self.active_tc:
if inp['name'].lower() == name.lower(): # ty = None
sort = inp.get('type', None) # for inp in self.proc.input_signals:
if sort: # if inp['name'].lower() == name.lower():
typename = sort.ReferencedTypeName.replace('-', '_') # sort = inp.get('type', None)
ty = self.proc.dataview[sort.ReferencedTypeName] # if sort:
next_states, error_count = exhaust_interface(name, ty) # typename = sort.ReferencedTypeName.replace('-', '_')
total_err += error_count # ty = self.proc.dataview[sort.ReferencedTypeName]
next_level.extend(next_states) # next_states, error_count = exhaust_interface(name, ty)
print 'length of next level: ', len(next_level) # total_err += error_count
# next_level.extend(next_states)
print 'Number of stop conditions reached:', total_err # print 'length of next level: ', len(next_level)
#
# print 'Number of stop conditions reached:', total_err
def random_simulation(self): def random_simulation(self):
''' Random simulator - read the config from the checker_table and ''' Random simulator - read the config from the checker_table and
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment