def poission_model(): module = Module("poission process") module.addConstant(Constant('r', None)) # variable definition v = Variable('n', 0, None, int, False) # n: int init 0; module.addVariable(v) # command definition comm = Command('', lambda vs, cs: True, lambda vs, cs: vs['n'].setValue(vs['n'].getValue() + 1), module, module.getConstant("r"), CommandKind.NONE, None) module.addCommand(comm) # 增加label表示n>=4这个ap labels = dict() def nge4(vs, cs): return vs['n'] >= 4 labels['nge4'] = nge4 model = ModulesFile.ModulesFile(ModelType.CTMC, modules=[module], labels=labels) return model
def _s3rmodule(self): config = self.config module = Module('S3R') module.addConstant(config.getParam('S3R_K')) module.addConstant(config.getParam('S3R_A_MU')) module.addConstant(config.getParam('S3R_A_SIGMA')) module.addConstant(config.getParam('S3R_B')) module.addConstant(config.getParam('S3R_DELTAV_THRESHOLD')) module.addVariable(Variable('s3r_status', 1, range(2), int)) def guard(vs, cs): # the sb_status and s3r_status must both be 1 for this transition # to happen return vs['timer_turn'] == False and vs['s3r_status'] == 1 and vs[ 'sb_status'] == 1 and vs['bcr_status'] == 1 and vs[ 'bdr_status'] == 1 def faction(vs, cs): vs['s3r_status'].setValue(0) vs['timer_turn'].setValue(True) def naction(vs, cs): vs['timer_turn'].setValue(True) def f(day_var): def inner(): day = day_var.getValue() dose = module.getConstant('S3R_K') / config.getParam( 'SCREEN_THICKNESS') * (day / 365.0) x = config.getParam('S3R_DELTAV_THRESHOLD') / ( config.getParam('S3R_B') * pow(e, config.getParam('S3R_B') * dose)) std_x = (-config.getParam('S3R_A_MU') + x) / \ config.getParam('S3R_A_SIGMA').getValue() p = 1 - pcf(std_x) logger.info('day:{0}, s3r failure prob:{1}'.format(day, p)) return p return inner def n(day_var): def inner(): ff = f(day_var) return 1 - ff() return inner if not hasattr(self, 'timer'): self.timer = self._timermodule() module.addCommand( Command('s3r_fail_cmd', guard, faction, module, f(self.timer.getVariable('day')))) module.addCommand( Command('s3r_nrl_cmd', guard, naction, module, n(self.timer.getVariable('day')))) return module
def _timermodule(self): config = self.config module = Module('TIME') module.add_variable( BoundedVariable('day', 1, range(1, config.getParam('DURATION_IN_DAY') + 1), int)) module.add_variable( BoundedVariable('timer_turn', False, set([True, False]), bool)) def _timer_action_guard(vs, cs): day_val = vs['day'].get_value() DAY_MAX = self.config.getParam("DURATION_IN_DAY") t_turn = vs['timer_turn'].get_value() return day_val < DAY_MAX and t_turn == True def action(vs, cs): # vs['day'].set_value(vs['day'].get_value() + 1) vs['day'].incr() vs['timer_turn'].set_value(False) module.addCommand( Command('inc day', _timer_action_guard, action, module, lambda: 1.0)) return module
def _sbmodule(self): config = self.config module = Module('SB') module.addConstant(config.getParam('SB_K')) module.addConstant(config.getParam('SB_A_MU')) module.addConstant(config.getParam('SB_A_SIGMA')) module.addConstant(config.getParam('SB_B')) module.addConstant(config.getParam('SB_P_THRESHOLD')) module.addVariable(Variable('sb_status', 1, range(2), int)) def guard(vs, cs): # sb_status and s3r_status must both be 1, e.g. the system has not # failed. return vs['timer_turn'] == False and vs['sb_status'] == 1 and vs[ 's3r_status'] == 1 and vs['bcr_status'] == 1 and vs[ 'bdr_status'] == 1 # failure action def faction(vs, cs): vs['sb_status'].setValue(0) vs['timer_turn'].setValue(True) # normal action def naction(vs, cs): vs['timer_turn'].setValue(True) def f(day_var): def inner(): day = day_var.getValue() dose = module.getConstant('SB_K') * config.getParam( 'SCREEN_THICKNESS') * day / 365.0 x = (-module.getConstant('SB_P_THRESHOLD') + 1) / \ (log(module.getConstant('SB_B') * dose + 1)) std_x = 1.0 / (module.getConstant('SB_A_SIGMA') / (-module.getConstant('SB_A_MU') + x)) return 1 - pcf(std_x) return inner def n(day_var): def inner(): ff = f(day_var) return 1 - ff() return inner if not hasattr(self, 'timer'): self.timer = self._timermodule() module.addCommand( Command('sb_fail_cmd', guard, faction, module, f(self.timer.getVariable('day')))) module.addCommand( Command('sb_nrl_cmd', guard, naction, module, n(self.timer.getVariable('day')))) return module
def _bcrmodule(self): config = self.config module = Module('BCR') module.add_variable(BoundedVariable('bcr_status', 1, range(2), int)) def _module_action_guard(vs, cs): timer_turn = vs['timer_turn'].get_value() sb_status = vs['sb_status'].get_value() s3r_status = vs['s3r_status'].get_value() bcr_status = vs['bcr_status'].get_value() bdr_status = vs['bdr_status'].get_value() return timer_turn == False and sb_status == 1 and s3r_status == 1 and bcr_status == 1 and bdr_status == 1 def faction(vs, cs): vs['bcr_status'].set_value(0) vs['timer_turn'].set_value(True) def naction(vs, cs): vs['timer_turn'].set_value(True) def f(day_var): def inner(): day = day_var.get_value() dose = config.getParam('S3R_K') / config.getParam( 'SCREEN_THICKNESS') * (day / 365.0) x = config.getParam('S3R_DELTAV_THRESHOLD') / ( config.getParam('S3R_B') * pow(e, config.getParam('S3R_B') * dose)) std_x = (-config.getParam('S3R_A_MU') + x) / \ config.getParam('S3R_A_SIGMA').get_value() p = 1 - pcf(std_x) # logger.info('day:{0}, bcr failure prob:{1}'.format(day, p)) return p return inner def n(day_var): def inner(): ff = f(day_var) return 1 - ff() return inner if not hasattr(self, 'timer'): self.timer = self._timermodule() module.addCommand( Command('bcr_fail_cmd', _module_action_guard, faction, module, f(self.timer.getVariable('day')))) module.addCommand( Command('bcr_nrl_cmd', _module_action_guard, naction, module, n(self.timer.getVariable('day')))) return module
class BasicParser(object): FRML_FUNC_PREFIX = "FRML" VAR_FUNC_PREFIX = "VAR" SPLIT = ":" def __init__(self): # 表示当前是否正在解析module模块 # 用途: 值为false时,对boolean_expression的解析不会将结果保存为guard self.moduledefbegin = False ''' 当parser分析到一行Command时,可能最后会解析成多个Command对象 每个Command对象包含以下信息:name, guard, prob, action, module 目前默认不设置Command的name,即name为空 module在每次解析到LB时进行初始化表示当前正在生成的module prob在解析到prob_expr的时候进行设置,prob是一个函数对象,因为需要根据判定对象(变量)的值进行实时计算 最重要的Command对象在解析到prob_update时进行初始化,因为从Command的构成上讲, 一个prob + update就构成了一个Command对象。 之所以要在BasicParser中保存module和guard对象是因为 它们是被多个Command对象所共享的。 ''' self.module = None # 当前正在解析的module对象 self.guard = None # 表示当前Command对象的guard属性 self.binary_op_map = { '+': lambda x, y: x + y, '-': lambda x, y: x - y, '*': lambda x, y: x * y, '/': lambda x, y: x / y } self.func_map = {'stdcdf': pcf} # name : value storage structure for constants self.cmap = defaultdict(lambda: None) # name : func object storage structure for variables and formula self.logger = logging.getLogger("BasicParser logging") self.logger.addHandler( logging.FileHandler(LogHelper.get_logging_root() + "BasicParser.log")) self.logger.setLevel(logging.INFO) self.vcf_map = defaultdict(lambda: None) self.vc_map = defaultdict(lambda: None) def p_statement(self, p): '''statement : model_type_statement | const_value_statement | module_def_begin_statement | module_def_end_statement | module_var_def_statement | module_command_statement | formula_statement | label_statement''' # print "slice: {}".format(p.slice) pass def p_model_type(self, p): '''model_type_statement : DTMC | CTMC''' model_type = ModelType.CTMC if p[1] == 'dtmc': model_type = ModelType.DTMC ModelConstructor.model = ModulesFile(modeltype=model_type) def p_module_def_begin_statement(self, p): '''module_def_begin_statement : MODULE NAME''' self.moduledefbegin = True self.module = Module(p[2]) def p_module_def_end_statement(self, p): '''module_def_end_statement : ENDMODULE''' if self.moduledefbegin: self.moduledefbegin = False ModelConstructor.model.addModule(self.module) def p_const_expression(self, p): '''const_value_statement : CONST INT NAME ASSIGN NUM SEMICOLON | CONST DOUBLE NAME ASSIGN NUM SEMICOLON | CONST BOOL NAME ASSIGN NUM SEMICOLON''' name = p[3] value = self.resolvetype(p[5], p[2]) obj = Constant(name, value) ModelConstructor.model.setConstant(name, obj) self.vcf_map[p[3]] = obj self.logger.info("Constant added: {} = {}".format(name, value)) def p_const_expression1(self, p): '''const_value_statement : CONST INT NAME SEMICOLON | CONST DOUBLE NAME SEMICOLON | CONST BOOL NAME SEMICOLON''' # 支持解析不确定的常量表达式 name = p[3] obj = Constant(name) ModelConstructor.model.addConstant(name, obj) self.vcf_map[name] = obj self.logger.info("Unspecified constant added: {}".format(name)) def p_const_expression2(self, p): '''const_value_statement : CONST INT NAME ASSIGN expr SEMICOLON | CONST DOUBLE NAME ASSIGN expr SEMICOLON | CONST BOOL NAME ASSIGN expr SEMICOLON''' name = p[3] value = self.resolvetype(p[5](), p[2]) obj = Constant(name, value) ModelConstructor.model.addConstant(name, obj) self.vcf_map[name] = obj self.logger.info("Constant added: {} = {}".format(name, value)) def p_module_var_def_statement(self, p): '''module_var_def_statement : NAME COLON LB expr COMMA expr RB INIT NUM SEMICOLON''' # 让var的lowbound和upperbound支持expression tokens = copy.copy(p.slice) min = tokens[4].value() max = tokens[6].value() var = Variable(p[1], p[len(p) - 2], range(min, max + 1), int) # 目前默认变量的类型是int p[index] index不能是负数 self.module.addVariable(var) self.vcf_map[var.getName()] = var self.logger.info( "Variable_{} added to Module_{}. init={}, range=[{}, {}]".format( var.getName(), str(self.module), var.initVal, var.valRange[0], var.valRange[-1])) def p_module_command_statement(self, p): '''module_command_statement : LB RB boolean_expression THEN updates SEMICOLON''' self.logger.info("command.tokens : {}".format(p.slice)) def p_updates(self, p): '''updates : updates ADD prob_update''' pass def p_updates1(self, p): '''updates : prob_update''' pass def p_prob_update(self, p): '''prob_update : DQ NAME DQ expr COLON actions''' prob = p[4] # prob_expr is a function action = p[6] # actions is a function name = copy.copy(p[2]) command = Command(name, self.guard, action, self.module, prob) self.module.addCommand(command) self.logger.info("Command_{} added.".format(name)) def p_actions(self, p): '''actions : actions AND assignment''' f1 = p[1] f2 = p[3] def f(vs, cs): f1(vs, cs) f2(vs, cs) p[0] = f def p_actions2(self, p): '''actions : assignment''' p[0] = p[ 1] # a assignment is a function that udpate the variable in model.localVars def p_assignment(self, p): '''assignment : NAME ASSIGN expr''' update_func = copy.deepcopy(p[3]) var_name = copy.copy(p[1]) def f(vs, cs): var = vs[var_name] if not var or not isinstance(var, Variable): raise Exception("invalid variable name") var.setValue(update_func()) p[0] = f def p_assignment1(self, p): '''assignment : LP NAME ASSIGN expr RP''' update_func = copy.deepcopy(p[4]) key = p[2] def f(vs, cs): var = vs[key] if not var or not isinstance(var, Variable): raise Exception("invalid variable name: {}".format(key)) var.setValue(update_func()) p[0] = f def p_expr(self, p): '''expr : expr ADD term | expr MINUS term''' slice_copy = copy.copy(p.slice) op = slice_copy[2].value def f(): '''binary expression function''' v1 = slice_copy[1].value() v2 = slice_copy[3].value() if op == '-': return v1 - v2 else: return v1 + v2 p[0] = f def p_expr2(self, p): '''expr : term''' p[0] = p[1] # def p_expr3(self, p): # '''expr : LP expr RP''' # p[0] = p[2] def p_term(self, p): '''term : term MUL factor | term DIV factor''' slice_copy = copy.copy(p.slice) op = slice_copy[2].value def f(): v1 = slice_copy[1].value() v2 = slice_copy[3].value() if op == "*": return v1 * v2 else: return v1 / v2 p[0] = f def p_term1(self, p): '''term : factor''' p[0] = p[1] def p_factor(self, p): '''factor : NUM''' num = p[1] def f(): return num f.func_doc = "return {}".format(str(num)) p[0] = f def p_factor1(self, p): '''factor : NAME''' slice_cpy = copy.copy(p.slice) name = slice_cpy[1].value def f(): obj = self.vcf_map[name] if callable(obj): return obj() return obj.getValue() p[0] = f def p_factor2(self, p): '''factor : NAME LP expr RP''' slice = copy.copy(p.slice) func = ExpressionHelper.func_map.get(slice[1].value, None) # if not func: # raise Exception("Not supported function {}".format(slice[1].value)) def f(): return func(slice[3].value()) f.func_doc = "func_{}".format(func.__name__) p[0] = f def p_factor3(self, p): '''factor : LP expr RP''' p[0] = p[2] def p_boolean_expression(self, p): '''boolean_expression : boolean_expression AND boolean_expression_unit | boolean_expression OR boolean_expression_unit | boolean_expression_unit''' print "boolean_expression detached." slices = copy.copy(p.slice) if len(slices) == 4: if slices[2].value == "&": def f(vs, cs): return slices[1].value(vs, cs) and slices[3].value(vs, cs) if slices[2].value == "|": def f(vs, cs): return slices[1].value(vs, cs) or slices[3].value(vs, cs) p[0] = f elif len(p) == 2: p[0] = p[1] if self.moduledefbegin: # 如果当前正在解析command # 否则要么是解析formula,要么是label self.guard = p[0] def p_boolean_expression_unit(self, p): '''boolean_expression_unit : NAME GT NUM | NAME LT NUM | NAME GE NUM | NAME LE NUM | NAME EQ NUM | NAME NEQ NUM''' # 解析单个变量与某个常量进行比较 tokens = copy.copy(p.slice) def f(tokens): def inner(vs, cs): var = vs[tokens[1].value] # if not var or not isinstance(var, Variable): # raise Exception("invalid variable name") val1 = var.getValue() val2 = tokens[3] op = tokens[2] if '<' == op: return val1 < val2 if '>' == op: return val1 > val2 if '>=' == op: return val1 >= val2 if '<=' == op: return val1 <= val2 if '==' == op: return val1 == val2 if '!=' == op: return val1 != val2 return inner p[0] = f(tokens) def p_boolean_expression_unit1(self, p): '''boolean_expression_unit : NAME GT expr | NAME LT expr | NAME GE expr | NAME LE expr | NAME EQ expr | NAME NEQ expr''' # 解析某个变量与一个表达式进行比较 tokens = copy.copy(p.slice) def f(t): # handler is a boolean_expression_resolver : handler(val1, val2, # op) def inner(vs, cs): var = vs[t[1].value] # if not var or not isinstance(var, Variable): # raise Exception("invalid var name") val1 = var.getValue() val2 = t[3].value() op = t[2].value if '<' == op: return val1 < val2 if '>' == op: return val1 > val2 if '>=' == op: return val1 >= val2 if '<=' == op: return val1 <= val2 if '==' == op: return val1 == val2 if '!=' == op: return val1 != val2 return inner p[0] = f(tokens) def p_formula_statement(self, p): '''formula_statement : FORMULA NAME ASSIGN expr SEMICOLON''' slices = copy.copy(p.slice) frml_name = slices[2].value self.vcf_map[frml_name] = slices[4].value self.logger.info("Formula_{} added.".format(slices[2].value)) def p_label_statement(self, p): '''label_statement : LABEL NAME ASSIGN boolean_expression SEMICOLON''' lbl_name = p[2] lbl_func = p[4] ModelConstructor.model.labels[lbl_name] = lbl_func def resolvetype(self, strval, type): if 'int' == type: return int(strval) if 'double' == type: return float(strval) if 'bool' == type: return bool(strval) def resolvenum(self, strval): if strval.find(r"\.") == -1: return int(strval) return float(strval) def parse_model(self, filepath): commentremoved = clear_comment(filepath) self.logger.info("Parsing model file : {}".format(commentremoved)) lines = [] with open(commentremoved) as f: for l in f: lines.append(l) if self.parser: myLexer = MyLexer() lexer = myLexer.lexer for line in lines: # tokens = [] # if line.find("[]") != -1: # lexer.input(line) # for token in lexer: # tokens.append(token) # print tokens self.parser.parse(line, lexer=lexer) def build(self): self.tokens = MyLexer.tokens self.parser = yacc.yacc(module=self)
def sps_model_dtmc(duration): # duration: timer.day的最大值:天数 # timer module of the system timer = Module('timer_module') timer.addConstant(Constant('TIME_LIMIT', duration)) day = BoundedVariable( 'day', 1, range(timer.getConstant('TIME_LIMIT').get_value() + 1), int, True) timer_turn = BoundedVariable('timer_turn', True, set([True, False]), bool, True) timer.add_variable(day) timer.add_variable(timer_turn) def incdayaction(vs, cs): vs['day'].set_value(vs['day'].get_value() + 1) vs['timer_turn'].set_value(False) inc_day = Command( 'inc day', lambda vs, cs: vs['timer_turn'] == True and vs['day'] < timer.getConstant('TIME_LIMIT').get_value(), incdayaction, timer, 1.0) timer.addCommand(inc_day) # solar battery module of the system sb = Module("solar battery module") # set initial value None to denote uncertainty screenthick = Constant('SCREEN_THICKNESS', None) sb.addConstant(screenthick) # the dose of one year: dose = K_SB * thickness sb.addConstant(Constant('SB_K', 0.0039)) sb.addConstant(Constant('SB_B', 12)) sb.addConstant(Constant('SB_P_THRESHOLD', 0.7)) sb.addConstant(Constant('SB_A_MU', 0.1754)) sb.addConstant(Constant('SB_A_SIGMA', 0.02319029 * 21)) # variables sb_status = BoundedVariable('sb_status', 1, range(2), int, True) sb.add_variable(sb_status) def failaction(vs, cs): vs['sb_status'].set_value(0) vs['timer_turn'].set_value(True) # use closure to delay the computation of fail rate def f1(day_var): def failprobsb(): # return the failure probability of solar battery after day-dose niel_dose = sb.getConstant('SB_K').get_value() * sb.getConstant( 'SCREEN_THICKNESS').get_value() * (day_var.get_value() / 365.0) x = (1 - sb.getConstant('SB_P_THRESHOLD').get_value()) / \ log(1 + niel_dose * sb.getConstant('SB_B').get_value()) std_x = (x - sb.getConstant('SB_A_MU').get_value() / sb.getConstant('SB_A_SIGMA').get_value()) temp = pcf(std_x) i = id(day_var) return 1 - temp return failprobsb def f1n(day_var): def normalprobsb(): niel_dose = sb.getConstant('SB_K').get_value() * sb.getConstant( 'SCREEN_THICKNESS').get_value() * (day_var.get_value() / 365.0) x = (1 - sb.getConstant('SB_P_THRESHOLD').get_value()) / \ log(1 + niel_dose * sb.getConstant('SB_B').get_value()) std_x = (x - sb.getConstant('SB_A_MU').get_value() / sb.getConstant('SB_A_SIGMA').get_value()) return pcf(std_x) return normalprobsb comm_fail = Command( 'solar battery failure command', lambda vs, cs: vs['sb_status'] == 1 and vs['timer_turn'] == False, failaction, sb, f1(timer.getVariable('day')), kind=CommandKind.FAILURE) sb.addCommand(comm_fail) comm_normal = Command( 'solar battery stay-normal command', lambda vs, cs: vs['sb_status'] == 1 and vs['timer_turn'] == False, lambda vs, cs: vs['timer_turn'].set_value(True), sb, f1n(timer.getVariable('day'))) sb.addCommand(comm_normal) s3r = Module('S3R模块') s3r.addConstant(screenthick) s3r.addConstant(Constant('S3R_K', 200.5 / 3.0)) # s3r, bdr, bcr三个模块均摊电离能损 s3r.addConstant(Constant('S3R_DELTAV_THRESHOLD', 450)) s3r.addConstant(Constant('S3R_A_MU', 570.8 * 18)) s3r.addConstant(Constant('S3R_A_SIGMA', 6.7471 * 120)) s3r.addConstant(Constant('S3R_B', 0.01731)) s3r_status = BoundedVariable('s3r_status', 1, range(2), int, True) s3r.add_variable(s3r_status) def s3rfailaction(vs, cs): vs['s3r_status'].set_value(0) vs['timer_turn'].set_value(True) def f2(day_var): def failprobs3r(): iel_dose = day_var.get_value() / 365.0 * (s3r.getConstant('S3R_K').get_value() / \ s3r.getConstant('SCREEN_THICKNESS').get_value()) x = s3r.getConstant('S3R_DELTAV_THRESHOLD').get_value() / ( s3r.getConstant('S3R_B').get_value() * pow(e, s3r.getConstant('S3R_B').get_value() * iel_dose)) std_x = (x - s3r.getConstant('S3R_A_MU').get_value()) / \ s3r.getConstant('S3R_A_SIGMA').get_value() return 1 - pcf(std_x) return failprobs3r def f2n(day_var): def normalprobs3r(): iel_dose = day_var.get_value() / 365.0 * (s3r.getConstant('S3R_K').get_value() / \ s3r.getConstant('SCREEN_THICKNESS').get_value()) x = s3r.getConstant('S3R_DELTAV_THRESHOLD').get_value() / ( s3r.getConstant('S3R_B').get_value() * pow(e, s3r.getConstant('S3R_B').get_value() * iel_dose)) std_x = (x - s3r.getConstant('S3R_A_MU').get_value()) / \ s3r.getConstant('S3R_A_SIGMA').get_value() return pcf(std_x) return normalprobs3r s3r_comm_fail = Command( 's3r failure command', lambda vs, cs: vs['s3r_status'] == 1 and vs['timer_turn'] == False, s3rfailaction, s3r, f2(timer.getVariable('day')), CommandKind.FAILURE) s3r.addCommand(s3r_comm_fail) s3r_comm_norm = Command( 's3r normal command', lambda vs, cs: vs['timer_turn'] == False and vs['s3r_status'] == 1, lambda vs, cs: vs['timer_turn'].set_value(True), s3r, f2n(timer.getVariable('day'))) s3r.addCommand(s3r_comm_norm) def failureif(vs, cs): return vs['s3r_status'] == 0 or vs['sb_status'] == 0 labels = dict() labels['up'] = lambda vs, cs: vs['s3r_status'] == 1 and vs['sb_status' ] == 1 labels['failure'] = lambda vs, cs: vs['s3r_status'] == 0 or vs['sb_status' ] == 0 i = id(timer.getVariable('day')) model = ModulesFile.ModulesFile(ModelType.DTMC, modules=[timer, sb, s3r], failureCondition=failureif, labels=labels, stopCondition=failureif) ii = id(model.localVars['day']) assert i == ii return model