Example #1
0
def generate_smt_from_cn_and_log(cn,
                                 log,
                                 var_info,
                                 min_unused_bindings=None,
                                 max_global_obligations=0):
    """Main function to generate a CVC file (to stdout) that represents the 
    C-net simulation problem. The file can then be fed to the STP solver.
    Returns the number of potentially unused bindings in the C-net.
    
    [cn] C-net to simulate.
    [log] log to simulate. Must fit inside [cn]
    [min_unused_bindings] Minimum number of required unused bindings.
        If 0, then compute the number of mandatory bindings
        and the number of potentially unused bindings. Use this latter value 
        halfed as required number of minimum unused bindings. Use None
        if no minimum number of bindings is required.
    [max_global_obligations] If > 0, restricts the maximum number of generated
        obligations during the simulation of the log.
    """
    #print the variables
    traces = log.get_uniq_cases()
    activity_positions = log.get_activity_positions()
    variables = var_info.variables
    obligation_dict = var_info.obligation_dict
    print "% Total number of variables:", len(variables)
    var_num = 1
    for var in variables:
        if var_num % 10 == 0 or var_num == len(variables):
            print var, ': BITVECTOR(1);'
        else:
            print var + ',',
        var_num += 1
    #build the constraints
    constraint_number = generate_structural_stp_inout(log, var_info)
    if max_global_obligations > 0:
        constraint_number += generate_stp_max_obligations(
            log, variables, max_global_obligations)
    print "% Structural constraints:", constraint_number
    #restrict input/output bindings to the ones in the given Cnet cn
    constraint_number2, binding_info = generate_stp_cn_choices(
        cn, log, var_info)
    constraint_number += constraint_number2
    in_binding_pos = binding_info.input_binding_positions
    out_binding_pos = binding_info.output_binding_positions
    in_mandatory = binding_info.input_mandatory
    out_mandatory = binding_info.output_mandatory
    total_bindings = (sum([len(ins) for ins in cn.inset.values()]) +
                      sum([len(outs) for outs in cn.outset.values()]))
    total_mandatory = len(in_mandatory) + len(out_mandatory)
    print '%Total bindings:', total_bindings
    print '%Known mandatory bindings:', total_mandatory
    #print in_mandatory
    #print out_mandatory
    potential_unused = total_bindings - total_mandatory
    print '%Min unused bindings', min_unused_bindings
    if min_unused_bindings is not None and min_unused_bindings >= 0:
        if min_unused_bindings == 0:
            #find all non-initial activities without mandatory input bindings
            in_missing = (log.get_alphabet() - set(cn.starting_activities()) -
                          set([x[0] for x in in_mandatory]))
            #find all non-final activities without mandatory output bindings
            out_missing = (log.get_alphabet() - set(cn.final_activities()) -
                           set([x[0] for x in out_mandatory]))
            remaining_mandatory = len(in_missing) + len(out_missing)
            print '%Generic mandatory bindings (due to obliged connectedness):', remaining_mandatory
            total_mandatory += remaining_mandatory
            print '%Total mandatory bindings:', total_mandatory
            potential_unused = total_bindings - total_mandatory
            constraint_number += generate_smt_unused_bindings(
                binding_info, potential_unused / 2)
        else:
            constraint_number += generate_smt_unused_bindings(
                binding_info, min_unused_bindings)
    #print in_binding_pos
    #print out_binding_pos
    print "%Total number of constraints:", constraint_number
    print
    print "QUERY (FALSE);"
    print "COUNTEREXAMPLE;"
    return potential_unused
Example #2
0
def fitting_cases_in_skeleton(log, skeleton):
    """Returns a log containing the sequences that would fit in any C-net
    using the arcs in [skeleton] (regardless of the actual bindings that would
    be required).
    
    To speed up the checking, all sequences whose immediately follows relation
    is inside [skeleton] are automatically accepted. Similarly if none of its
    predecessors or successors appears in the skeleton, then the case is sure
    non-fitting."""
#    Be careful with extended strategies. For instance, assume that we check
#    that, for each activity, it must have a relation with at least one 
#    predecessor activity in the case, and the same for successors). 
#    
#    This is an overapproximation, since activities could 'steal' obligations
#    needed by other occurrences of the same activity. e.g., saa with skeleton
#    (s,a) would pass the check, but will not be really fitting. However,
    cases = log.get_uniq_cases()
    set_skeleton = set(skeleton)
    new_cases = defaultdict(int)
    old_stdout = sys.stdout
    stpfile = 'simulate.stp'
    for case_num, (case, occ) in enumerate(cases.iteritems()):
        imm_follows = True
        for i, act in enumerate(case[:-1]):
            if (act,case[i+1]) not in set_skeleton:
                imm_follows = False
                break
        if not imm_follows:
            #see if it is directly non-fitting
            possible = True
            for i, act in enumerate(case):
                if i < len(case)-1:
                    shared_succ = [(a,b) for a,b in skeleton if a==act and b in case[i+1:]]
                    if not shared_succ:
                        possible = False
                        break
                if i > 0:
                    shared_pred = [(a,b) for a,b in skeleton if b==act and a in case[:i]]
                    if not shared_pred:
                        possible = False
                        break
            if possible:
                #check with SMT
                singleton_log = Log(cases=[case])
                sys.stdout = open(stpfile,'w')
                var_info = boolean_variables({case:1}, exclusive_use_arcs=skeleton)
                variables = var_info.variables
                print "% Total number of variables:", len(variables)
                for i in xrange(0,len(variables),10):
                    print ','.join(variables[i:i+10]),': BITVECTOR(1);'
                generate_structural_stp_inout(singleton_log, var_info)
                print
                print "QUERY (FALSE);"
                print "COUNTEREXAMPLE;"
                sys.stdout = old_stdout
                stpoutput = subprocess.check_output( [stp_solver, stpfile] )
                smt_verified = 'Invalid' in stpoutput
            else:
                print 'Unique case {0} is trivially NON-replayable'.format(case_num)
        else:
            print 'Unique case {0} is trivially replayable'.format(case_num)
        if imm_follows or (possible and smt_verified):
            new_cases[copy.copy(case)] = occ 
    return Log(uniq_cases=new_cases)
Example #3
0
                    shared_pred = [(a, b) for a, b in skeleton
                                   if b == act and a in case[:i]]
                    if not shared_pred:
                        possible = False
                        break
            if possible:
                #check with SMT
                singleton_log = Log(cases=[case])
                sys.stdout = open(stpfile, 'w')
                var_info = boolean_variables({case: 1},
                                             exclusive_use_arcs=skeleton)
                variables = var_info.variables
                print "% Total number of variables:", len(variables)
                for i in xrange(0, len(variables), 10):
                    print ','.join(variables[i:i + 10]), ': BITVECTOR(1);'
                generate_structural_stp_inout(singleton_log, var_info)
                print
                print "QUERY (FALSE);"
                print "COUNTEREXAMPLE;"
                sys.stdout = old_stdout
                stpoutput = subprocess.check_output([stp_solver, stpfile])
                smt_verified = 'Invalid' in stpoutput
            else:
                print 'Unique case {0} is trivially NON-replayable'.format(
                    case_num)
        else:
            print 'Unique case {0} is trivially replayable'.format(case_num)
        if imm_follows or (possible and smt_verified):
            new_cases[copy.copy(case)] = occ
    return Log(uniq_cases=new_cases)
Example #4
0
def generate_smt_from_cn_and_log( cn, log, var_info, 
                                    min_unused_bindings=None,
                                    max_global_obligations=0 ):
    """Main function to generate a CVC file (to stdout) that represents the 
    C-net simulation problem. The file can then be fed to the STP solver.
    Returns the number of potentially unused bindings in the C-net.
    
    [cn] C-net to simulate.
    [log] log to simulate. Must fit inside [cn]
    [min_unused_bindings] Minimum number of required unused bindings.
        If 0, then compute the number of mandatory bindings
        and the number of potentially unused bindings. Use this latter value 
        halfed as required number of minimum unused bindings. Use None
        if no minimum number of bindings is required.
    [max_global_obligations] If > 0, restricts the maximum number of generated
        obligations during the simulation of the log.
    """
    #print the variables
    traces = log.get_uniq_cases()
    activity_positions = log.get_activity_positions()
    variables = var_info.variables
    obligation_dict = var_info.obligation_dict
    print "% Total number of variables:", len(variables)
    var_num = 1
    for var in variables:
        if var_num % 10 == 0 or var_num == len(variables):
            print var, ': BITVECTOR(1);'
        else:
            print var+',',
        var_num += 1
    #build the constraints
    constraint_number = generate_structural_stp_inout(log, var_info)
    if max_global_obligations > 0:
        constraint_number += generate_stp_max_obligations( log, variables, 
                                         max_global_obligations )
    print "% Structural constraints:", constraint_number
    #restrict input/output bindings to the ones in the given Cnet cn
    constraint_number2, binding_info = generate_stp_cn_choices( cn, log, var_info )
    constraint_number += constraint_number2
    in_binding_pos = binding_info.input_binding_positions
    out_binding_pos = binding_info.output_binding_positions
    in_mandatory = binding_info.input_mandatory
    out_mandatory = binding_info.output_mandatory
    total_bindings = (sum([len(ins) for ins in cn.inset.values()]) + 
                        sum([len(outs) for outs in cn.outset.values()]))
    total_mandatory = len(in_mandatory)+len(out_mandatory)
    print '%Total bindings:', total_bindings
    print '%Known mandatory bindings:', total_mandatory
    #print in_mandatory
    #print out_mandatory
    potential_unused = total_bindings-total_mandatory
    print '%Min unused bindings', min_unused_bindings
    if min_unused_bindings is not None and min_unused_bindings >= 0:
        if min_unused_bindings == 0:
            #find all non-initial activities without mandatory input bindings
            in_missing = (log.get_alphabet()-set(cn.starting_activities())-
                            set([x[0] for x in in_mandatory]))
            #find all non-final activities without mandatory output bindings
            out_missing = (log.get_alphabet()-set(cn.final_activities())-
                            set([x[0] for x in out_mandatory]))
            remaining_mandatory = len(in_missing) + len(out_missing)
            print '%Generic mandatory bindings (due to obliged connectedness):', remaining_mandatory
            total_mandatory += remaining_mandatory
            print '%Total mandatory bindings:', total_mandatory
            potential_unused = total_bindings-total_mandatory
            constraint_number += generate_smt_unused_bindings( binding_info, 
                                                                potential_unused/2)
        else:
            constraint_number += generate_smt_unused_bindings( binding_info, 
                                                                min_unused_bindings)
    #print in_binding_pos
    #print out_binding_pos
    print "%Total number of constraints:", constraint_number
    print
    print "QUERY (FALSE);"
    print "COUNTEREXAMPLE;"
    return potential_unused