def label_test_file(test_file_name, label_file_name, viol_formula, duration): # THIS DOES NOT WORK. I WILL FIX IT LATER! f_s = open(test_file_name, 'r') lines = f_s.readlines() f_l = open(label_file_name, 'w') time = 0 # Initialize the checker: stn_viol = STL.SyntaxTreeNode() stn_viol.initialize_node(viol_formula.split(), 0) while time <= duration: # Store the values to the file: kk = [float(f) for f in lines[time].split()[1:6] ] + [int(i) for i in lines[time].split()[6:]] stn_viol.compute_qv( STL.DataPoint(value=[float(f) for f in lines[time].split()[1:6]] + [int(i) for i in lines[time].split()[6:]], time=time)) qual = 1 if stn_viol.qv > 0 else 0 f_l.write("%s %s\n" % (str(time), str(qual))) time += 1 f_s.close() f_l.close() print("Done!")
def generate_basic_traces(folder_name, trace_count, duration): viol_formula = 'x0 < 5' stn_viol = STL.SyntaxTreeNode() stn_viol.initialize_node(viol_formula.split(), 0) tc = 0 while tc < trace_count: f_signal_name = folder_name + "test_" + str(tc) f_label_name = f_signal_name + "_label" f_s = open(f_signal_name, 'w') f_l = open(f_label_name, 'w') time = 0 x = [ random.randint(5, 7) ] # this line is to be uncommented if initial x is wanted to be randomized. #x = [0] while time <= duration: u = [random.choice([-2, 1, 2])] f_s.write( "%s %s %s\n" % (str(time), " ".join([str(x[0])]), " ".join([str(u[0])]))) stn_viol.compute_qv(STL.DataPoint(value=x + u, time=time)) qual = 1 if stn_viol.qv < 0 else 0 f_l.write("%s %s\n" % (str(time), str(qual))) x, _ = basic_example_step_function(x, u) time += 1 f_s.close() f_l.close() print("Done with generate basic traces, trace no" + str(tc)) tc += 1
def controller(folder_name, name, trace_count, duration, viol_formula, cause_formula, step_function, xk_initialized, uk_domain, uk_count, num_to_let=False): """ IMPORTANT!: We make the assumption that an input value (control or system) is ordered in the following way: The first xk_count numbers starting from 0 are for system inputs, the following uk_count ones, starting from xk_count are control inputs. For example, if xk_count = 3 and uk_count = 2, x0,x1 and x2 are system inputs and x3,x4 are control inputs. We also make the assumption that uk_domain is the same for each control input. Args: folder_name: name: trace_count: viol_formula: duration: cause_formula: (prefix) This is None if we are not constructing a controller, has a value otherwise. step_function: a function xk, _ = step(xk,uk) that takes old xk and uk values and returns the new xk value with another unimportant value. uk_domain: (list) of domain of uk values uk_count: the number of control inputs xk_initialized: (tuple, numpy array or list) initialized xk values num_to_let:(bool) if step_function takes xk's in the form of letters a and b instead of numbers 1 and 0, this value must be given as True. This variable is set specifically for traffic network's step function's needs. """ npml = 0 # "no possible modes left" count #viol_cnt = 0 xk_count = len(xk_initialized) iter_uk_crossproduct = product(uk_domain, repeat=uk_count) uk_crossproduct = [] # set list of all possible uk combinations for prod in iter_uk_crossproduct: uk_crossproduct.append(prod) # First construct the traffic network. # In loop, generate trace. check it against the formula, produce the label. Save both tc = 0 while tc < trace_count: f_signal_name = folder_name + "/" + name + "_" + str(tc) f_label_name = f_signal_name + "_label" f_s = open(f_signal_name, 'w') f_l = open(f_label_name, 'w') time = 0 # initialize the states of system inputs xk = xk_initialized xk = xk_tolist(xk) # break the formula into its components formula_list = hf.break_formula(cause_formula) formula_components = hf.give_formula_components(formula_list) # Initialize the checker: stn_viol = STL.SyntaxTreeNode() stn_viol.initialize_node(viol_formula.split(), 0) # Initialize a number representing the last value where uk was not ck for each formula component's left side control_array = np.full((len(formula_list), 1), -1) while time <= duration: # new uk's free values are determined upon old xk and uk values uk_works = False free_control_values = copy.deepcopy(uk_crossproduct) while not uk_works: # set uk randomly from free_control_values rand_index = random.randint( 0, len(free_control_values) - 1) # very weirdly, random.randint(a,b) can give out b uk = list(free_control_values[rand_index]) j = 0 while j in range(len(formula_list)): # check if left side is satisfied by checking if A 1, b-1 (u=c) is satisfied # and if u = c at this randomly generated uk. control_input = formula_components[j][ 0].left_node.metric - xk_count control_input_val = formula_components[j][ 0].left_node.param control_input_length = formula_components[j][ 0].interval.ub + 1 # orjinal formul A 1 1 ise length = 0 if uk[control_input] == control_input_val and ( control_input_length == 0 or time - control_array[j] > control_input_length): # left side is satisfied for A 0 b-2 ( u = c ), check if right formula is satisfied right_side_satisfied = False if formula_components[j][1] == None: right_side_satisfied = True else: copy_stn = copy.deepcopy(formula_components[j][1]) copy_stn.compute_qv( STL.DataPoint(value=xk + uk, time=time)) if copy_stn.qv > 0: right_side_satisfied = True if right_side_satisfied: break j += 1 if j == len(formula_list): uk_works = True else: free_control_values = hf.safe_remove( free_control_values, tuple(uk)) if len(free_control_values) == 0: print("No possible free control combinations left") npml += 1 rand_index = random.randint(0, len(uk_crossproduct) - 1) uk = list(uk_crossproduct[rand_index]) uk_works = True # we found a working uk for the corresponding xk # update all stns and linked_list values with this uk and xk values for i in range(len(formula_list)): if formula_components[i][1] is not None: formula_components[i][1].compute_qv( STL.DataPoint(value=xk + uk, time=time)) control_input = formula_components[i][ 0].left_node.metric - xk_count control_input_val = formula_components[i][0].left_node.param if not uk[control_input] == control_input_val: control_array[ i] = time # en son bu time'da uk[control_input], control_input_val'dan degisikti # compute label, write new xk, uk and label to the file stn_viol.compute_qv(STL.DataPoint(value=xk + uk, time=time)) f_s.write("%s %s\n" % (str(time), " ".join([str(x) for x in xk + uk]))) qual = 0 if stn_viol.qv >= 0 else 1 f_l.write("%s %s\n" % (str(time), str(qual))) # new xk is calculated from this loop's xk and uk values if num_to_let: uk_letters = ['a' if x == 0 else 'b' for x in uk] xk, _ = step_function(xk, uk_letters) else: xk, _ = step_function(xk, uk) xk = xk_tolist(xk) time += 1 f_s.close() f_l.close() print("Done %d" % tc) tc += 1 print("There were no possible modes left for a controller input for " + str(npml) + " times.")
def signal_generator_for_plot(trace_start_index, folder_name, name, traffic_file, trace_count, viol_formula, duration, formula): """ Args: trace_start_index: folder_name: name: traffic_file: trace_count: viol_formula: duration: cause_formula: (prefix) This is None if we are not constructing a controller, has a value otherwise. Returns tuple (metrics,inputs, parameter_domains) where metrics: The list of metrics inputs: A list of controllable metrics (inputs is subset of metrics) parameter_domains: A dictionary containing the domains of parameters Sample return: ([0,1,2], [2], {'p0': [0, 10], 'p1': [0, 10], 'p2': ['a', 'b']}) Note that the domain for the input metrics is always set valued. """ # First construct the traffic network. # In loop, generate trace. check it against the formula, produce the label. Save both link_dict, intersection_dict = read_input.load_from_annotated_file( traffic_file) tn = network.Network(link_dict, intersection_dict, scale=5) tc = 0 while tc < trace_count: index = trace_start_index + tc f_signal_name = folder_name + "/" + name + "_" + str(index) f_label_name = f_signal_name + "_label" f_formula_label_name = f_signal_name + "_formula_label" f_s = open(f_signal_name, 'w') f_l = open(f_label_name, 'w') f_fl = open(f_formula_label_name, 'w') time = 0 # The states of the links xk = np.zeros(tn.get_link_count()) sm = [_ for _ in range(tn.get_intersection_count())] tn.initialize_links(xk, 0.1) tn.set_random_signal_mode(sm) # Initialize the checker: stn_viol = STL.SyntaxTreeNode() stn_viol.initialize_node(viol_formula.split(), 0) stn_cause = STL.SyntaxTreeNode() stn_cause.initialize_node(formula.split(), 0) sm_numbers = [0 if x == 'a' else 1 for x in sm] while time <= duration: # Store the values to the file: stn_viol.compute_qv( STL.DataPoint(value=xk.tolist() + sm_numbers, time=time)) f_s.write("%s %s %s\n" % (str(time), " ".join( [str(x) for x in xk]), " ".join([str(x) for x in sm_numbers]))) qual1 = 0 if stn_viol.qv >= 0 else 1 f_l.write("%s %s\n" % (str(time), str(qual1))) stn_cause.compute_qv( STL.DataPoint(value=xk.tolist() + sm_numbers, time=time)) qual2 = 0 if stn_cause.qv >= 0 else 1 f_fl.write("%s %s\n" % (str(time), str(qual2))) xk, _ = tn.step(xk, sm) tn.set_random_signal_mode(sm) sm_numbers = [0 if x == 'a' else 1 for x in sm] time += 1 f_s.close() f_l.close() f_fl.close() print("Done %d" % index) tc += 1
def traffic_signal_generator(trace_start_index, folder_name, name, traffic_file, trace_count, viol_formula, duration): """ Args: trace_start_index: folder_name: name: traffic_file: trace_count: viol_formula: duration: Returns tuple (metrics,inputs, parameter_domains) where metrics: The list of metrics inputs: A list of controllable metrics (inputs is subset of metrics) parameter_domains: A dictionary containing the domains of parameters Sample return: ([0,1,2], [2], {'p0': [0, 10], 'p1': [0, 10], 'p2': ['a', 'b']}) Note that the domain for the input metrics is always set valued. """ # First construct the traffic network. # In loop, generate trace. check it against the formula, produce the label. Save both link_dict, intersection_dict = read_input.load_from_annotated_file( traffic_file) tn = network.Network(link_dict, intersection_dict, scale=5) tc = 0 while tc < trace_count: index = trace_start_index + tc f_signal_name = folder_name + "/" + name + "_" + str(index) f_label_name = f_signal_name + "_label" f_s = open(f_signal_name, 'w') f_l = open(f_label_name, 'w') time = 0 # The states of the links xk = np.zeros(tn.get_link_count()) sm = [_ for _ in range(tn.get_intersection_count())] tn.initialize_links(xk, 0.1) tn.set_random_signal_mode(sm) # Initialize the checker: stn_viol = STL.SyntaxTreeNode() stn_viol.initialize_node(viol_formula.split(), 0) sm_numbers = [0 if x == 'a' else 1 for x in sm] while time <= duration: # Store the values to the file: stn_viol.compute_qv( STL.DataPoint(value=xk.tolist() + sm_numbers, time=time)) f_s.write("%s %s %s\n" % (str(time), " ".join( [str(x) for x in xk]), " ".join([str(x) for x in sm_numbers]))) qual = 0 if stn_viol.qv >= 0 else 1 f_l.write("%s %s\n" % (str(time), str(qual))) xk, _ = tn.step(xk, sm) tn.set_random_signal_mode(sm) sm_numbers = [0 if x == 'a' else 1 for x in sm] time += 1 f_s.close() f_l.close() print("Done %d" % index) tc += 1 if trace_count == 0: # return the set of metrics link_count = tn.get_link_count() link_metrics = list(range(0, link_count)) intersection_metrics = list(range(tn.get_intersection_count())) intersection_metrics = [ x + tn.get_link_count() for x in intersection_metrics ] # shift the indices c = tn.get_all_intersection_indices_and_modes() parameter_domains = {} for i in range(tn.get_intersection_count()): pi = 'p' + str(i + link_count) parameter_domains[pi] = next( list(x[1].keys()) for x in c if x[0] == i) capacities = tn.np_xcap for i in range(link_count): parameter_domains['p' + str(i)] = [0, capacities[i]] return link_metrics + intersection_metrics, intersection_metrics, parameter_domains # All metrics, set valued metrics, domains for set valued metrics
def evaluate(formula, signal_file_name, label_file_name, stn, return_type, past_results=[]): """ evaluates the given formulas false_positive, false_negative, true_positive, true_negative results in the given files end returns the necessary ones based on the result_type. If there are past_results, all formulas are concatenated with or and the resulting formula's results are returned. Args: formula: prefix formula signal_file_name: label_file_name: stn: return_type: one of the types in stl_constants, determines the valuation best_result will be chosen based on in evaluate_signals. past_results: a list of formula valuations (formulas inside being prefix) If past_results is not empty, formula and the formulas in past_results are concatenated using "or" and evaluation is done based on the concatenated formula. Returns: if return_type is TYPE_RATIO; true positives / # of data points is returned if return_type is TYPE_MISMATCH; # of data points - true positives is returned else; detailed_result (i.e. an array of false_positive, false_negative, true_positive, true_negative is returned """ # Construct syntax tree if stn and past_results == []: stn.clean() else: # create new formula by concatenating the formula with past formulas with or, and compute this formula on tests new_formula = formula for frml in past_results: new_formula = ' | ' + new_formula + ' ' + frml.formula stn = STL.SyntaxTreeNode() stn.initialize_node(new_formula.split(), 0) result = 0 counter = 0 # detailed result is false_positive, false_negative, true_positive, true_negative detailed_result = [0, 0, 0, 0] skip_count = 10 # skip the first 10 data points, not important in monitoring. sc = 0 with open(signal_file_name, 'r') as sf, open(label_file_name, 'r') as lf: for ts, te in zip(sf, lf): s = ts.split() t = s[0] s = s[1:] _, e = te.split() t = float(t) s = [float(x) for x in s] e = float(e) while t > stn.nt: stn.compute_qv(STL.DataPoint(value=s, time=stn.nt)) if sc > skip_count: result += (stn.qv > 0) == ep counter += 1 # label is false if (ep == 0): # if stn.qv > 0 is true then it is false positive # if stn.qv > 0 is false then it is true negative detailed_result = (detailed_result[0] + int( (stn.qv > 0) != ep), detailed_result[1], detailed_result[2], detailed_result[3] + int((stn.qv > 0) == ep)) # label is true else: # if stn.qv > 0 is false then it is false negative # if stn.qv > 0 is true then it is true positive detailed_result = (detailed_result[0], detailed_result[1] + int((stn.qv > 0) != ep), detailed_result[2] + int((stn.qv > 0) == ep), detailed_result[3]) else: sc += 1 stn.compute_qv(STL.DataPoint(time=t, value=s)) if sc > skip_count: result += (stn.qv > 0) == e counter += 1 # label is false if (e == 0): # if stn.qv > 0 is true then it is false positive # if stn.qv > 0 is false then it is true negative detailed_result = (detailed_result[0] + int( (stn.qv > 0) != e), detailed_result[1], detailed_result[2], detailed_result[3] + int((stn.qv > 0) == e)) # label is true else: # if stn.qv > 0 is false then it is false negative # if stn.qv > 0 is true then it is true positive detailed_result = (detailed_result[0], detailed_result[1] + int((stn.qv > 0) != e), detailed_result[2] + int((stn.qv > 0) == e), detailed_result[3]) else: sc += 1 sp = s ep = e if return_type.type == stl_constants.TYPE_RATIO: return float(result) / counter if return_type.type == stl_constants.TYPE_MISMATCH: # return the mismatch count return counter - result else: # return detailed results return detailed_result
import unittest import random from trace_checker import STL from trace_checker import formula_utilities as U import syntactically_cosafe_form as scf _data_points = [ STL.DataPoint(0, [0]), STL.DataPoint(2, [1]), STL.DataPoint(4, [3]), STL.DataPoint(6, [8]) ] class Test_syntactically_cosafe_form(unittest.TestCase): def test_scf(self): formula = 'P 1 1 ( x0 = 1 )' formula_X0, dict0 = 'X p0', {'x0=1.0': 'p0'} sc_formula = scf.return_sc_form(formula, prefix=False) formula_X, dict = scf.turn_inequalities_to_atomic_propositions( sc_formula) self.assertEqual(formula_X, formula_X0) self.assertEqual(dict, dict0) formula = 'P 1 2 ( x0 = 1 )' formula_X0, dict0 = '( X p0 | XX p0 )', {'x0=1.0': 'p0'} sc_formula = scf.return_sc_form(formula, prefix=False) formula_X, dict = scf.turn_inequalities_to_atomic_propositions( sc_formula) self.assertEqual(formula_X, formula_X0) self.assertEqual(dict, dict0)