Пример #1
0
def cnet_binary_search(log,
                       activity_window=0,
                       exclusive_use_arcs=None,
                       ignored_arcs=None,
                       add_ignored_arcs_to_window=True,
                       upper_bound=-1,
                       randomized_names=True):
    """Finds a C-net for the log [log] using a binary search strategy than
    minimizes the number of arcs. The C-net returned contains a new field
    stpoutput that can be used to derive frequency information, bindings
    sequence, etc.
    [activity_window] Consider for obligation only the n activities around each 
    activity. To consider them all use value 0 (default).
    [exclusive_use_arcs] List of exclusive obligations that can be used.
    [ignored_arcs] List of obligations not considered for arc minimization.
    [upper_bound] Upper bound of binary search, used to override default which 
    is the number of arcs in the immediately follows C-net for [log]."""
    t0 = datetime.datetime.now()
    traces = log.get_uniq_cases()
    activity_positions = log.get_activity_positions()
    logfilename = log.filename if log.filename else 'tmp'
    if (randomized_names):
        sr = [
            random.choice(string.ascii_letters + string.digits)
            for n in xrange(5)
        ]
        logfilename = logfilename.join(sr)
    var_info = cn_stp.boolean_variables(traces, activity_window,
                                        exclusive_use_arcs, ignored_arcs,
                                        add_ignored_arcs_to_window)
    net = immediately_follows_cnet_from_log(log)
    old_stdout = sys.stdout
    logprefix, logfileextension = os.path.splitext(logfilename)
    iteration = 0
    if not ignored_arcs:
        max_bound = net.number_of_arcs() - 1
        #new lower bound
        start_activities = set(
            [words[1] for words in traces if len(words) > 1])
        end_activities = set([words[-2] for words in traces if len(words) > 1])
        #print end_activities
        new_min_bound = (len(start_activities) + len(end_activities) +
                         len(net.activities -
                             (start_activities | end_activities)) - 2 +
                         max(len(start_activities - end_activities),
                             len(end_activities - start_activities)))
        print "General connectivity min bound:", len(
            net.activities), "New min bound:", new_min_bound
        min_bound = max(len(net.activities), new_min_bound)
    else:
        ignored_alphabet = set([x[0] for x in ignored_arcs]) | set(
            [x[1] for x in ignored_arcs])
        #compute new activities in log to derive lower bound
        new_alphabet = log.get_alphabet() - ignored_alphabet
        max_bound = len(net.arcs() - set(ignored_arcs)) - 1
        if len(new_alphabet) == 0:
            min_bound = 0
        else:
            min_bound = len(new_alphabet) + 1
        #min_bound = 0
        #since the start and final activities cannot belong to the new activities
        print 'Some arcs are ignored, setting a conservative lower bound of {0}'.format(
            min_bound)
    if upper_bound >= 0:
        max_bound = min(max_bound, upper_bound)
        print 'Setting manually upper bound to', max_bound
    print "Reducing number of arcs"
    last_fine_net = net
    while min_bound <= max_bound:
        print "Bounds: [{0},{1}]".format(min_bound, max_bound)
        avg_bound = (min_bound + max_bound) / 2
        print "Testing arcs =", avg_bound
        max_global_arcs = avg_bound
        stpfile = logprefix + '.it{0}.stp'.format(iteration)
        print stpfile
        print "Generating STP file ({0})...".format(stpfile)
        try:
            sys.stdout = open(stpfile, "w")
        except Exception as ex:
            print("Error. Cannot open file '%s'. %s" % (stpfile, ex))
            quit()
        cn_stp.generate_stp_from_log(log,
                                     var_info,
                                     max_global_arcs=max_global_arcs)
        sys.stdout = old_stdout
        #call stp solver
        print "Calling STP solver..."
        t0_solver = datetime.datetime.now()
        stpoutput = subprocess.check_output([stp_solver, stpfile])
        delta_t = datetime.datetime.now() - t0_solver
        print "Solver elapsed time:", delta_t.total_seconds(), "s."
        #print stpoutput
        if 'Invalid' in stpoutput:
            print "Model was feasible"
            net = stp_to_cnet.build_cnet_from_stp(stpoutput.split("\n"))
            #            if options.file_output:
            #                cn_file = logprefix+'.it{0}.cn'.format(iteration)
            #                net.save(cn_file)
            last_fine_net = net
            last_fine_net.stpoutput = stpoutput
            #max_bound = avg_bound # if we do not want the hassle of having to perform the extraction
            if avg_bound > net.number_of_arcs():
                print "Number of arcs of found C-net:", net.number_of_arcs()
            if not ignored_arcs:
                if avg_bound < net.number_of_arcs():
                    print "ERROR: equation restricting number of arcs is not working. Found C-net has {0} arcs".format(
                        net.number_of_arcs())
                    quit()
                max_bound = net.number_of_arcs() - 1
            else:
                #                print "found arcs ({0}):".format(len(net.arcs())), net.arcs()
                #                print "ignored arcs ({0}):".format(len(options.ignore_arcs)), set(options.ignore_arcs)
                #                print "bounded arcs ({0}):".format(len(net.arcs() - set(options.ignore_arcs))), net.arcs() - set(options.ignore_arcs)
                max_bound = len(net.arcs() - set(ignored_arcs)) - 1
#                print "new max bound:", max_bound
#last_fine_stpoutput = stpoutput
        else:
            print "Model was unfeasible"
            min_bound = avg_bound + 1
        iteration += 1
    last_fine_net.print_cnet()
    print "Number of C-net arcs:", last_fine_net.number_of_arcs()
    print "Total number of iterations:", iteration
    delta_t = datetime.datetime.now() - t0
    print "Elapsed time:", delta_t.total_seconds(), "s."
    #    if options.file_output:
    #        cn_file = logprefix+'.cn'
    #        net.save(cn_file)
    #    if options.interactive_output:
    #        last_fine_net.interactive_output()
    return last_fine_net
Пример #2
0
def cnet_binary_search( log,  
                    activity_window=0, exclusive_use_arcs=None,
                    ignored_arcs=None, add_ignored_arcs_to_window=True, 
                    upper_bound=-1,randomized_names=True):
    """Finds a C-net for the log [log] using a binary search strategy than
    minimizes the number of arcs. The C-net returned contains a new field
    stpoutput that can be used to derive frequency information, bindings
    sequence, etc.
    [activity_window] Consider for obligation only the n activities around each 
    activity. To consider them all use value 0 (default).
    [exclusive_use_arcs] List of exclusive obligations that can be used.
    [ignored_arcs] List of obligations not considered for arc minimization.
    [upper_bound] Upper bound of binary search, used to override default which 
    is the number of arcs in the immediately follows C-net for [log]."""
    t0 = datetime.datetime.now()
    traces = log.get_uniq_cases()
    activity_positions = log.get_activity_positions()
    logfilename = log.filename if log.filename else 'tmp'
    if (randomized_names):
        sr = [random.choice(string.ascii_letters + string.digits) for n in xrange(5)]
        logfilename = logfilename.join(sr) 
    var_info = cn_stp.boolean_variables(traces, activity_window,
                                        exclusive_use_arcs,
                                        ignored_arcs,
                                        add_ignored_arcs_to_window)
    net = immediately_follows_cnet_from_log(log)
    old_stdout = sys.stdout
    logprefix, logfileextension = os.path.splitext(logfilename)
    iteration = 0
    if not ignored_arcs:   
        max_bound = net.number_of_arcs()-1
        #new lower bound
        start_activities = set([words[1] for words in traces if len(words) > 1])
        end_activities = set([words[-2] for words in traces if len(words) > 1])
        #print end_activities
        new_min_bound = (len(start_activities) + len(end_activities) + 
                        len(net.activities - 
                        (start_activities | end_activities)) -
                        2 + max(len(start_activities - end_activities), 
                                len(end_activities - start_activities )))
        print "General connectivity min bound:", len(net.activities),"New min bound:",new_min_bound
        min_bound = max(len(net.activities), new_min_bound)
    else:
        ignored_alphabet = set([x[0] for x in ignored_arcs]) | set([x[1] for x in ignored_arcs])
        #compute new activities in log to derive lower bound
        new_alphabet = log.get_alphabet() - ignored_alphabet
        max_bound = len(net.arcs() - set(ignored_arcs))-1
        if len(new_alphabet) == 0:
            min_bound = 0
        else:
            min_bound = len(new_alphabet)+1
        #min_bound = 0
        #since the start and final activities cannot belong to the new activities
        print 'Some arcs are ignored, setting a conservative lower bound of {0}'.format(min_bound)
    if upper_bound >= 0:
        max_bound = min(max_bound, upper_bound)
        print 'Setting manually upper bound to', max_bound
    print "Reducing number of arcs"
    last_fine_net = net
    while min_bound <= max_bound:
        print "Bounds: [{0},{1}]".format(min_bound, max_bound)
        avg_bound = (min_bound+max_bound)/2
        print "Testing arcs =",avg_bound
        max_global_arcs = avg_bound
        stpfile = logprefix+'.it{0}.stp'.format(iteration)
        print "Generating STP file ({0})...".format(stpfile)
        try:
            sys.stdout = open(stpfile,"w")
        except Exception as ex:
            print("Error. Cannot open file '%s'. %s" % (stpfile, ex))
            quit()
        cn_stp.generate_stp_from_log( log, var_info, 
                                        max_global_arcs=max_global_arcs )
        sys.stdout = old_stdout
        #call stp solver
        print "Calling STP solver..."
        t0_solver = datetime.datetime.now()
        stpoutput = subprocess.check_output( [stp_solver, stpfile] )
        delta_t = datetime.datetime.now() - t0_solver 
        print "Solver elapsed time:", delta_t.total_seconds(),"s."
        #print stpoutput
        if 'Invalid' in stpoutput:
            print "Model was feasible"
            net = stp_to_cnet.build_cnet_from_stp( stpoutput.split("\n") )
#            if options.file_output:
#                cn_file = logprefix+'.it{0}.cn'.format(iteration)
#                net.save(cn_file)
            last_fine_net = net
            last_fine_net.stpoutput = stpoutput
            #max_bound = avg_bound # if we do not want the hassle of having to perform the extraction
            if avg_bound > net.number_of_arcs():
                print "Number of arcs of found C-net:", net.number_of_arcs()
            if not ignored_arcs:
                if avg_bound < net.number_of_arcs():
                    print "ERROR: equation restricting number of arcs is not working. Found C-net has {0} arcs".format(net.number_of_arcs())
                    quit()
                max_bound = net.number_of_arcs() - 1
            else:
#                print "found arcs ({0}):".format(len(net.arcs())), net.arcs()
#                print "ignored arcs ({0}):".format(len(options.ignore_arcs)), set(options.ignore_arcs)
#                print "bounded arcs ({0}):".format(len(net.arcs() - set(options.ignore_arcs))), net.arcs() - set(options.ignore_arcs)
                max_bound = len(net.arcs() - set(ignored_arcs)) - 1
#                print "new max bound:", max_bound
            #last_fine_stpoutput = stpoutput
        else:
            print "Model was unfeasible"
            min_bound = avg_bound + 1
        iteration += 1
    last_fine_net.print_cnet()
    print "Number of C-net arcs:", last_fine_net.number_of_arcs()
    print "Total number of iterations:", iteration
    delta_t = datetime.datetime.now() - t0 
    print "Elapsed time:", delta_t.total_seconds(),"s."
#    if options.file_output:
#        cn_file = logprefix+'.cn'
#        net.save(cn_file)
#    if options.interactive_output:
#        last_fine_net.interactive_output()
    return last_fine_net
Пример #3
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)