Example #1
0
def is_action(places, transitions, m0, i, m_ip, tau_it, space_between_fired):
    '''
    The is_action method used by is_run creates the formula of each instant. Which transition fired ?
    :param places (list) :
    :param transitions (list) :
    :param m0 (marking) : initial marking
    :param i (int) : instant in the run
    :param m_ip (function) : function to get the number of the boolean variables of the markings, see variablesGenerator.
    :param tau_it (function) : function to get the number of the boolean variables of the transitions, see variablesGenerator.
    :return:
    '''
    # only one transition is true at instant i
    or_formulas = []
    for t in transitions:
        or_formulas.append(
            And([tau_it([i, transitions.index(t)])], [
                tau_it([i, transitions.index(t2)])
                for t2 in transitions if t != t2
            ], []))
    formulas = [Or([], [], or_formulas)]
    # if transition t fires at instant i, then we have the good marking
    for t in transitions:
        formulas.append(
            Or([], [tau_it([i, transitions.index(t)])],
               [is_transition(places, t, i, m_ip, space_between_fired)]))
    return And([], [], formulas)
Example #2
0
def initialisation_ReducedForAntiAlignment(transitions, silent_transitions, tau_it, lambda_jia, djiid, j, size_of_run,
                                           wait_transition, max_d):
    '''
   Initialisation of the edit distance reduced for anti-alignmet.
   This is the 3 first axioms of the _Encoding Conformance Checking Artefacts in SAT_ paper
   :param transitions (list) : list of transitions
   :param silent_transitions (list) : list of the silent transitions
   :param tau_it (fun) : function that returns the boolean variable number of the firing transition t at an instant i
   :param lambda_jia (fun) : function that returns the boolean variable number of the letter of trace j at instant i
   :param djiid (fun) : function that returns the boolean variable that says at instant i and i of we have d distance
   :param j (int) : jth trace
   :param size_of_run (int) : maximal size of a run
   :param wait_transition (transition) : to finish words
   :param max_d (int): heuristic
   :return: formula
   '''

    def t(transition):
        return transitions.index(transition)

    positives = []
    # diid is true for d = 0
    for i_m in range(0, size_of_run + 1):
        for i_t in range(0, size_of_run + 1):
            positives.append(djiid([j, i_m, i_t, 0]))

    # diid is false for 1 1 d and d >0
    negatives = [djiid([j, 0, 0, d]) for d in range(1, max_d + 1)]

    formulas = []
    for d in range(0, max_d):
        for i_m in range(0, size_of_run):
            # (i_m <> w and i_m <> tau ) <=> (d im+1 0 d+1 => d im 0 d )
            condition = [tau_it([i_m + 1, t(wait_transition)])]
            for st in silent_transitions:
                condition.append(tau_it([i_m + 1, t(st)]))
            this_condition = condition
            this_condition.append(djiid([j, i_m, 0, d]))
            i_t_null_and_i_m_cost = Or(this_condition, [djiid([j, i_m + 1, 0, d + 1])], [])
            formulas.append(i_t_null_and_i_m_cost)

            # (i_m == w or i_m == tau ) <=> (d im+1 0 d => d im 0 d )
            i_t_null_and_i_m_dont_cost = Or([djiid([j, i_m, 0, d])], [djiid([j, i_m + 1, 0, d])], [
                And([], condition, [])
            ])
            formulas.append(i_t_null_and_i_m_dont_cost)

        for i_t in range(0, size_of_run):
            # i_t <> w <=> (d 0 it+1 d+1 => d 0 it d )
            i_m_null_and_i_t_cost = Or(
                [lambda_jia([j, i_t + 1, t(wait_transition)]), djiid([j, 0, i_t, d])],
                [djiid([j, 0, i_t + 1, d + 1])], [])
            formulas.append(i_m_null_and_i_t_cost)

            # i_t == w <=> (d 0 it+1 d => d 0 it d )
            i_m_null_and_i_t_dont_cost = Or([djiid([j, 0, i_t, d])],
                                            [lambda_jia([j, i_t + 1, t(wait_transition)]),
                                             djiid([j, 0, i_t + 1, d])], [])
            formulas.append(i_m_null_and_i_t_dont_cost)
    return And(positives, negatives, formulas)
Example #3
0
    def __sup_to_minimize_with_distance_function(self, artefact,
                                                 variablesFunction):
        list_of_formula = []
        if artefact == ANTI_ALIGNMENT:
            for d in range(0, self.__max_d + 1):
                list_of_d = []
                for j in range(0, len(self.__traces)):
                    # delta_j1nnd and delta_j2nnd and ... delta_jlnnd
                    list_of_d.append(variablesFunction(j, d))
                # not di or ( dji and dji ... dji)
                not_di_or_list_of_and = Or(
                    [], [self.__vars.get(BOOLEAN_VAR_SUP, [d])],
                    [And(list_of_d, [], [])])
                list_of_formula.append(not_di_or_list_of_and)

        if artefact == MULTI_ALIGNMENT:
            for d in range(0, self.__max_d + 1):
                list_of_d = []
                for j in range(0, len(self.__traces)):
                    # not delta_j1nnd or not delta_j2nnd or ... not delta_jlnnd
                    list_of_d.append(variablesFunction(j, d))
                #  di or ( dji or dji ... dji)
                not_di_or_list_of_and = Or(
                    [self.__vars.get(BOOLEAN_VAR_SUP, [d])], [],
                    [And([], list_of_d, [])])
                list_of_formula.append(not_di_or_list_of_and)
        return list_of_formula
Example #4
0
def bodyHammingDistance(transitions, silent_transitions, vars, nbTraces, size_of_run):
    '''
    Exact formula of hamming distance.
    :param transitions (list) : the transitions
    :param silent_transitions (list) : the silent transitions
    :param variables (variablesGenerator) : to creates the variables numbers
    :param nbTraces (int) : number of traces
    :param size_of_run (int) : maximal size of run
    :return: formula
    '''
    formulas = []
    for j in range(0, nbTraces):
        for i in range(1, size_of_run + 1):
            for t in range(0, len(transitions)):
                if transitions[t] not in silent_transitions:
                    create_diff = Or([],
                                     [],
                                     [
                                         And([vars.get(BOOLEAN_VAR_FIRING_TRANSITION_PN, [i, t])], [], [
                                             Or([vars.get(BOOLEAN_VAR_TRACES_ACTIONS, [j, i, t]),
                                                 vars.get(BOOLEAN_VAR_HAMMING_DISTANCE, [j, i])], [], [])
                                         ]),
                                         And([], [vars.get(BOOLEAN_VAR_FIRING_TRANSITION_PN, [i, t]),
                                                  vars.get(BOOLEAN_VAR_TRACES_ACTIONS, [j, i, t]),
                                                  vars.get(BOOLEAN_VAR_HAMMING_DISTANCE, [j, i])], [])
                                     ])
                else:
                    create_diff = Or([], [vars.get(BOOLEAN_VAR_FIRING_TRANSITION_PN, [i, t]),
                                          vars.get(BOOLEAN_VAR_HAMMING_DISTANCE, [j, i])], [])
                formulas.append(create_diff)
    return formulas
Example #5
0
    def __getDiffTracesCentroids(self, chi_jia, diffl_ji, diffm_ji,
                                 lambda_jia):
        '''
        This function that defines the difference between the traces and its centroid and calls
        __maxDiffTracesCentroids().
        :param chi_jia (function)
        :param diff_ji (function)
        :param lambda_jia (function)
        :return: list of formula
        '''
        formulas = []
        for j in range(0, len(self.__traces)):
            aDiffPerInstant = []
            for i in range(1, self.__size_of_run + 1):
                # for each instant, a transition is true and there is or not a diff
                for t in range(0, len(self.__transitions)):
                    # if silent transition : diffjit is false
                    if self.__transitions[t] in self.__silent_transititons:
                        indexOfWaitModel = self.__transitions.index(
                            self.__wait_transition_model)
                        indexOfWaitTrace = self.__transitions.index(
                            self.__wait_transition_trace)
                        diffjit = Or([
                            diffl_ji([j, i]),
                            lambda_jia([j, i, indexOfWaitModel]),
                            lambda_jia([j, i, indexOfWaitTrace])
                        ], [chi_jia([j, i, t])], [])
                    # chi_jia => lambda_jia or diff_ji
                    elif self.__transitions[t] == self.__wait_transition_model:
                        diffjit = Or([diffl_ji([j, i]),
                                      lambda_jia([j, i, t])],
                                     [chi_jia([j, i, t])], [])
                    elif self.__transitions[t] == self.__wait_transition_trace:
                        diffjit = Or([diffm_ji([j, i])], [chi_jia([j, i, t])],
                                     [])
                    else:
                        indexOfWaitTrace = self.__transitions.index(
                            self.__wait_transition_trace)
                        diffjit = Or([], [], [
                            Or([lambda_jia([j, i, t])], [chi_jia([j, i, t])], [
                                And([diffl_ji([j, i]),
                                     diffm_ji([j, i])], [], [])
                            ]),
                            And([
                                diffm_ji([j, i]),
                                lambda_jia([j, i, indexOfWaitTrace]),
                                chi_jia([j, i, t])
                            ], [], [])
                        ])
                    aDiffPerInstant.append(diffjit)
            diffPerJ = And([], [], aDiffPerInstant)
            formulas.append(diffPerJ)

        # then there is maximal number of diff :
        self.__maxDiffTracesCentroids(formulas)
        return formulas
def maxDistance2(vars, diff1, diff2, max_d, size_of_run):
    list_to_size_of_run = list(range(1, size_of_run * 2 + 1))
    max_distance = max_d
    # IDEA : there are at least max_distance number of false variables
    combinaisons_of_instants = list(
        itertools.combinations(list_to_size_of_run, max_distance))
    distFalseVariables = []
    for instants in combinaisons_of_instants:
        list_distances = []
        for i in instants:
            if i <= size_of_run:
                list_distances.append(diff1([i]))
            else:
                list_distances.append(diff2([i - size_of_run]))
        list_distances2 = []
        for i in range(1, size_of_run * 2 + 1):
            if i not in instants:
                if i <= size_of_run:
                    list_distances2.append(diff1([i]))
                else:
                    list_distances2.append(diff2([i - size_of_run]))

        distFalseVariables.append(
            Or([], list_distances, [And([], list_distances2, [])]))
    return Or([], [], distFalseVariables)
Example #7
0
 def is_run_for_j(j, size_of_run, places, pn_transitions, trace_transitions,
                  m0, mf, m_ip, tau_it, reach_final):
     '''
     The is_run_for_j method creates run of centroid of trace j, i. e., alignment.
     :param j (int) : index of trace
     :param size_of_run (int): maximal size of the run
     :param places (list) : list of Places
     :param pn_transitions (list) : transitions of the model 'cause needed...
     :param trace_transitions (list) : transitions of the trace
     :param m0 (marking) : initial marking of trace
     :param mf (Marking) : final marking of trace
     :param m_ip (function) : marking boolean variables of the trace
     :param tau_it (function) : transitions boolean variables of the trace, @see variablesGenerator.
     :param reach_final (bool) : true or false to reach final marking
     :return:
     '''
     positives = [m_ip([j, 0, places.index(m)]) for m in m0]
     if reach_final:
         [
             positives.append(m_ip([j, size_of_run,
                                    places.index(m)])) for m in mf
         ]
     negatives = [
         m_ip([j, 0, places.index(m)]) for m in places if m not in m0
     ]
     formulas = [
         is_action_for_j(j, places, pn_transitions, trace_transitions, i,
                         m_ip, tau_it) for i in range(1, size_of_run + 1)
     ]
     run_of_pn = And(positives, negatives, formulas)
     return run_of_pn
Example #8
0
 def is_run_centroid(j, size_of_run, m0, mf, m_jip, tau_jip, c_kt,
                     chi_jk, nb_clusters, transitions, places):
     '''
     Initialization of centroids. There is a run per trace. This run represents alignment of the trace to the
     model. If trace is clusterised then transition of it run are containing in the centroid of its cluster.
     :param j (int) : index of trace
     :param size_of_run (int) : maximal size of the run, prefix
     :param m0 (Marking) : initial marking
     :param m_jip (function) : @see variablesGenerator.py, function chi_jk gets BOOLEAN_VAR_CHI_MARKINGS variables
     :param tau_jip (function) : @see variablesGenerator.py, function chi_jk gets BOOLEAN_VAR_CHI_TRANSITIONS
      variables
     :param c_kt (function) : @see variablesGenerator.py, function chi_jk gets BOOLEAN_VAR_K_CONTAINS_T variables
     :param chi_jk (function) : @see variablesGenerator.py, function chi_jk gets BOOLEAN_VAR_J_IN_K variables
     :param nb_clusters (int) : number of cluster
     :param transitions (list) : list of Transitions
     :param places (list) : list of Places
     :return:
     '''
     positives = [m_jip([j, 0, places.index(m)]) for m in m0]
     for m in mf:
         positives.append(m_jip([j, size_of_run, places.index(m)]))
     negatives = [
         m_jip([j, 0, places.index(m)]) for m in places if m not in m0
     ]
     formulas = [
         is_action_centroid(j, places, transitions, i, m_jip, tau_jip,
                            c_kt, chi_jk, nb_clusters)
         for i in range(1, size_of_run + 1)
     ]
     run_of_pn = And(positives, negatives, formulas)
     return run_of_pn
Example #9
0
def is_run(size_of_run, places, transitions, m0, mf, m_ip, tau_it, reach_final,
           space_between_fired):
    '''
    The is_run method allows one to create the boolean paths of the petri net.
    :param size_of_run (int): maximal size of the run
    :param places (list) :
    :param transitions (list) :
    :param m0 (marking) : initial marking
    :param m_ip (marking) : final marking
    :param tau_it (function) : function to get the number of the boolean variables, see variablesGenerator.
    :param reach_final (bool) : true or false to reach final marking
    :return:
    '''
    positives = [m_ip([0, places.index(m)]) for m in m0]
    if reach_final:
        positives += [m_ip([size_of_run, places.index(m)]) for m in mf]
    negatives = [m_ip([0, places.index(m)]) for m in places if m not in m0]
    formulas = [
        is_action(places, transitions, m0, i, m_ip, tau_it,
                  space_between_fired)
        for i in range(space_between_fired, size_of_run +
                       1, space_between_fired)
    ]
    run_of_pn = And(positives, negatives, formulas)
    return run_of_pn
Example #10
0
def for_hamming_distance_aux_supd_anti(variables,lenTraces,max_d,size_of_run):
    list_of_formula=[]
    list_to_size_of_run= list(range(1,size_of_run+1))
    not_d_or_and_diff=[]
    for j in range (0, lenTraces):
        for d in range(1,min(max_d + 1,size_of_run+1)):
            combinaisons_of_instants=list(itertools.combinations(list_to_size_of_run,d))
            and_sub_instants=[]
            for sub_list_of_instants in combinaisons_of_instants:
                instants_to_combine=[]
                for instant in list(sub_list_of_instants):
                    instants_to_combine.append(variables.get(BOOLEAN_VAR_HAMMING_DISTANCE, [j, instant]))
                and_sub_instants.append(And(instants_to_combine,[],[]))
            not_d_or_and_diff.append(Or([], [variables.get(BOOLEAN_VAR_HAMMING_SUP_AUX, [j, d])], and_sub_instants))
    list_of_formula.append(And([],[],not_d_or_and_diff))
    return list_of_formula
Example #11
0
 def __maxDiffTracesCentroids(self, formulas):
     '''
     This function uses self.__max_d that determines the maximal distance of the trace to its centroid.
     Idea of the threshold : there are at least N diff variables false per trace.
     :param formulas (list of formula to fill)
     :return: void
     '''
     # this function uses combinations of itertools to get all the combinations : this is better than parameter
     # at_most of pysat library
     list_to_size_of_run = list(range(1, (self.__size_of_run * 2) + 1))
     max_distance = (self.__size_of_run * 2) - self.__max_d
     # IDEA : there are at least max_distance number of false variables
     combinaisons_of_instants = list(
         itertools.combinations(list_to_size_of_run, max_distance))
     for j in range(0, len(self.__traces)):
         distFalseVariables = []
         for instants in combinaisons_of_instants:
             list_distances = []
             for i in instants:
                 if i <= self.__size_of_run:
                     list_distances.append(
                         self.__vars.get(BOOLEAN_VAR_DIFF_l, [j, i]))
                 else:
                     list_distances.append(
                         self.__vars.get(BOOLEAN_VAR_DIFF_m,
                                         [j, (i - self.__size_of_run)]))
             distFalseVariables.append(And([], list_distances, []))
         formulas.append(Or([], [], distFalseVariables))
Example #12
0
 def is_action_for_j(j, trace_places, pn_transitions, trace_transitions, i,
                     m_ip, tau_it):
     '''
     The is_action method used by is_run creates the formula of each instant. Which transition fired ?
     :param places (list) :
     :param pn_transitions (list) : we need all the alphabet to refuse transitions that aren't in trace
     :param trace_transitions (list) : transitions of the trace
     :param i (int) : instant in the run
     :param m_ip (function) : function to get the number of the boolean variables of the markings, see variablesGenerator.
     :param tau_it (function) : function to get the number of the boolean variables of the transitions, see variablesGenerator.
     :return:
     '''
     # only one transition is true at instant i
     # lazy comment : this verifies that alphabet is complet : all action not executed has to be taken into account
     or_formulas = []
     formulas = []
     label_transitions = [t.label for t in pn_transitions]
     copie_transitions = [t for t in pn_transitions]
     transitions_already_done = []
     for t in trace_transitions:
         if t not in transitions_already_done:
             other_transitions_with_same_label = []
             for t2 in trace_transitions:
                 if t2.label == t.label:
                     other_transitions_with_same_label.append(t2)
                     transitions_already_done.append(t2)
             if t.label in label_transitions:
                 index_of_t = label_transitions.index(t.label)
             else:
                 index_of_t = None  # should never happen
             copie_transitions.remove(
                 pn_transitions[(label_transitions.index(t.label))])
             or_formulas.append(And([tau_it([j, i, index_of_t])], [], []))
             implication = []
             for t2 in other_transitions_with_same_label:
                 implication.append(
                     is_transition_for_j(j, trace_places, t2, i, m_ip))
             formulas.append(
                 Or([], [tau_it([j, i, index_of_t])], implication))
     formulas.append(Or([], [], or_formulas))
     formulas.append(
         And([], [
             tau_it([j, i, pn_transitions.index(r)])
             for r in copie_transitions
         ], []))
     return And([], [], formulas)
Example #13
0
        def is_action_centroid(j, places, transitions, i, m_jip, tau_jip, c_kt,
                               chi_jk, nb_clusters):
            '''
            @see pnToFormula.py, is_action_centroid says if transition is fired.
            :param j (int) : index of trace
            :param places (list) : places of the petri net, indexes are important
            :param transitions (list) : transitions of the petri net, indexes are important
            :param i (int) : instant in the run of the centroid
            :param m_jip (function) : @see variablesGenerator.py, function chi_jk gets BOOLEAN_VAR_CHI_MARKINGS variables
            :param tau_jip (function) : @see variablesGenerator.py, function chi_jk gets BOOLEAN_VAR_CHI_TRANSITIONS
             variables
            :param c_kt (function) : @see variablesGenerator.py, function chi_jk gets BOOLEAN_VAR_K_CONTAINS_T variables
            :param chi_jk (function) : @see variablesGenerator.py, function chi_jk gets BOOLEAN_VAR_J_IN_K variables
            :param nb_clusters (int) : number of cluster
            :return:
            '''
            # a transition fires and only one
            aTransitionPerInstant = [
                And([tau_jip([j, i, t])], [
                    tau_jip([j, i, t2])
                    for t2 in range(len(transitions)) if t != t2
                ], []) for t in range(len(transitions))
            ]
            formulas = [Or([], [], aTransitionPerInstant)]

            # runs is_transition for the fired transition
            indexOfTraceWait = transitions.index(self.__wait_transition_trace)
            for t in range(len(transitions)):
                # WAIT_TRANSITION_TRACE is forbidden for centroid
                if t == indexOfTraceWait:
                    formulas.append(And([], [tau_jip([j, i, t])], []))
                else:
                    formulas.append(
                        Or([], [tau_jip([j, i, t])], [
                            And([], [], [
                                is_transition_centroid(
                                    j, places, transitions[t], i, m_jip),
                                in_cluster_of_j(t, c_kt, j, chi_jk,
                                                nb_clusters)
                            ])
                        ]))
            return And([], [], formulas)
def distanceNets(vars, size_of_run, tau1, tau2, pn1_transitions,
                 pn2_transitions, w1, w2):
    formula = []
    vars.add(BOOLEAN_VAR_DIFF1, [(1, size_of_run + 1)])
    vars.add(BOOLEAN_VAR_DIFF2, [(1, size_of_run + 1)])

    for i in range(1, size_of_run + 1):
        for t1 in pn1_transitions:
            '''
            listOfSameLabels=[tau2([i,pn2_transitions.index(t2)]) for t2 in pn2_transitions if t2.label==t1.label]
            listOfSameLabels.append(vars.getFunction(BOOLEAN_VAR_DIFF)([i]))
            formula.append(Or(listOfSameLabels,[tau1([i,pn1_transitions.index(t1)]) ],[]))

            '''
            if t1 != w1:
                listOfSameLabels = [
                    tau2([i, pn2_transitions.index(t2)])
                    for t2 in pn2_transitions if t2.label == t1.label
                ]
                listOfSameLabels.append(tau2([i, pn2_transitions.index(w2)]))
                formula.append(
                    Or(listOfSameLabels,
                       [tau1([i, pn1_transitions.index(t1)])], [
                           And([
                               vars.getFunction(BOOLEAN_VAR_DIFF1)([i]),
                               vars.getFunction(BOOLEAN_VAR_DIFF2)([i])
                           ], [], [])
                       ]))
                formula.append(
                    Or([vars.getFunction(BOOLEAN_VAR_DIFF1)([i])], [
                        tau2([i, pn2_transitions.index(w2)]),
                        tau1([i, pn1_transitions.index(t1)])
                    ], []))
            else:
                formula.append(
                    Or([
                        vars.getFunction(BOOLEAN_VAR_DIFF2)([i]),
                        tau2([i, pn2_transitions.index(w2)])
                    ], [tau1([i, pn1_transitions.index(t1)])], []))

    return And([], [], formula)
Example #15
0
 def __tracesInAClusterOnly(self, inC_j, chi_jk):
     '''
     Verifies that j is in a unique cluster or any
     :param inC_j (function)
     :param chi_jk (function)
     '''
     formulas = []
     for j in range(0, len(self.__traces)):
         inCorNot = []
         for k1 in range(0, self.__nb_clusters):
             # if in k1 then not in other k
             inCorNot.append(
                 And([inC_j([j]), chi_jk([j, k1])], [
                     chi_jk([j, k])
                     for k in range(0, self.__nb_clusters) if k != k1
                 ], []))
         # if in any k, then not inC
         allKNot = [chi_jk([j, k]) for k in range(0, self.__nb_clusters)]
         allKNot.append(inC_j([j]))
         inCorNot.append(And([], allKNot, []))
         formulas.append(Or([], [], inCorNot))
     return formulas
Example #16
0
    def __createSATformula(self, pn, m0, mf, max_d, max_t, traces_xes,
                           nbTraces):
        '''
        This function creates and solve the SAT formula of the clustering problem.
        :param pn (Petrinet)
        :param m0 (Marking)
        :param mf (Marking)
        :param max_d (int)
        :param max_t (int)
        :param traces_xes (Log)
        '''
        # this object creates variable numbers of the SAT formula
        self.__vars = VariablesGenerator()
        # formula version of data event log
        log_to_PN_w_formula, self.__traces = log_to_Petri_with_w(
            traces_xes,
            self.__transitions,
            self.__vars,
            self.__size_of_run,
            self.__wait_transition_trace,
            self.__wait_transition_model,
            label_l=BOOLEAN_VAR_TRACES_ACTIONS,
            max_nbTraces=nbTraces)
        # creates the boolean variables for the next formulas
        self.__createBooleanVariables()
        # formula of centroids
        centroidsFormulasList = self.__createCentroids(m0, mf)
        # formula that describes maximal distance
        diffTracesCentroids = self.__getDiffTracesCentroids(
            self.__vars.getFunction(BOOLEAN_VAR_CHI_TRANSITIONS),
            self.__vars.getFunction(BOOLEAN_VAR_DIFF_l),
            self.__vars.getFunction(BOOLEAN_VAR_DIFF_m),
            self.__vars.getFunction(BOOLEAN_VAR_TRACES_ACTIONS))

        # formula that create BOOLEAN_VAR_COMMON_T variables
        listOfCommonTransitions = self.__commonTransitions(
            self.__vars.getFunction(BOOLEAN_VAR_COMMON_T),
            self.__vars.getFunction(BOOLEAN_VAR_K_CONTAINS_T))
        # formula that describes that a trace belongs to at most one cluster
        aClusterMax = self.__tracesInAClusterOnly(
            self.__vars.getFunction(BOOLEAN_VAR_J_CLUSTERISED),
            self.__vars.getFunction(BOOLEAN_VAR_J_IN_K))
        # concat the formula
        full_formula = And([], [], log_to_PN_w_formula +
                           centroidsFormulasList + diffTracesCentroids +
                           listOfCommonTransitions + aClusterMax)
        # formula to cnf
        cnf = full_formula.operatorToCnf(self.__vars.iterator)

        # CNF is completed with minimisation and solved
        self.__createWCNFWithMinimization(cnf)
def force_wait_transition(vars, w1, pn1_transitions, adapted_size_of_run,
                          space_between_fired):
    pos = []
    neg = []
    for i in range(0, adapted_size_of_run + 1):
        if i % space_between_fired != 0:
            for t in pn1_transitions:
                if t != w1:
                    neg.append(
                        vars.get(BOOLEAN_VAR_FIRING_TRANSITION_PN_1,
                                 [i, pn1_transitions.index(t)]))
                else:
                    pos.append(
                        vars.get(BOOLEAN_VAR_FIRING_TRANSITION_PN_1,
                                 [i, pn1_transitions.index(t)]))
    return And(pos, neg, [])
Example #18
0
 def in_cluster_of_j(tr, c_kt, j, chi_jk, nb_clusters):
     '''
     Subfunction of __createCentroids. in_cluster_of_j function affects a transition to the cluster of the trace.
     :param tr (Transition)
     :param c_kt (function) : @see variablesGenerator.py, function c_kt(k,t) gets BOOLEAN_VAR_K_CONTAINS_T
     variables
     :param j (int) : index of the current trace
     :param chi_jk (function) : @see variablesGenerator.py, function chi_jk gets BOOLEAN_VAR_J_IN_K variables
     :param nb_clusters (int) : number of cluster
     :return:
     '''
     # BOOLEAN_VAR_J_IN_K => BOOLEAN_VAR_K_CONTAINS_T
     return And([], [], [
         Or([c_kt([k, tr])], [chi_jk([j, k])], [])
         for k in range(0, nb_clusters)
     ])
Example #19
0
def log_to_SAT(traces_xes,
               transitions,
               variablesGenerator,
               size_of_run,
               wait_transition,
               label_l=BOOLEAN_VAR_TRACES_ACTIONS,
               max_nbTraces=None):
    '''
    This method returns the formulas of the Log.
    :param traces_xes:
    :param transitions (list)
    :param variablesGenerator (variablesGenerator) : to add the new boolean variables
    :param size_of_run (int) : to complete smaller words with "wait" transitions
    :param wait_transition (transition) : the "wait" transition
    :param label_l (string) : name of the boolean variables of the log
    :return:
    '''
    traces_multiples = project_traces(traces_xes)
    #traces=list(np.unique(traces_multiples))
    traces = traces_multiples
    traces = traces[:max_nbTraces] if max_nbTraces != None else traces
    variablesGenerator.add(label_l, [(0, len(traces)), (1, size_of_run + 1),
                                     (0, len(transitions))])
    lambda_jia = variablesGenerator.getFunction(label_l)
    positives = []
    negatives = []
    for j in range(0, len(traces)):
        for i in range(1, size_of_run + 1):
            if len(traces[j]) < (i):
                positives.append(
                    lambda_jia([j, i, transitions.index(wait_transition)]))
                for a in transitions:
                    if a != wait_transition:
                        negatives.append(
                            lambda_jia([j, i, transitions.index(a)]))
            else:
                for a in transitions:
                    if str(a) == traces[j][i - 1]:
                        letterFound = True
                        positives.append(
                            lambda_jia([j, i, transitions.index(a)]))
                    else:
                        negatives.append(
                            lambda_jia([j, i, transitions.index(a)]))
    return And(positives, negatives, []), traces
def numberOfWaitInRun(vars, size_of_run, tau1, pn1_transitions, w1, we):
    list_to_size_of_run = list(range(1, size_of_run * 2 + 1))
    minw1 = int((size_of_run) / 2)
    # IDEA : there are at least max_distance number of w1 variables to false
    combinaisons_of_instants = list(
        itertools.combinations(list_to_size_of_run, minw1))
    w1ToTrue = []
    for instants in combinaisons_of_instants:
        listOfW1ToTrue = []
        for i in instants:
            if i <= int(size_of_run):
                listOfW1ToTrue.append(tau1([i, pn1_transitions.index(w1)]))
            else:
                listOfW1ToTrue.append(
                    tau1([i - int(size_of_run),
                          pn1_transitions.index(we)]))
        w1ToTrue.append(And(listOfW1ToTrue, [], []))
    return Or([], [], w1ToTrue)
Example #21
0
    def __createWncf(self, initialisationFormulas, distanceFormula,
                     artefactForMinimization):
        '''
        This method creates the wncf formulas with the weighted variables depending on the distance and artefact.
        :param initialisationFormulas: @see __artefactsInitialisation
        :param distanceFormula: @see __compute_distance
        :param artefactForMinimization: MULTI_ALIGNMENT or ANTI_ALIGNMENT or EXACT_ALIGNMENT
        :return:
        '''
        formulas = initialisationFormulas + distanceFormula + self.__sup_to_minimize(
            artefactForMinimization)
        full_formula = And([], [], formulas)
        cnf = full_formula.operatorToCnf(self.__vars.iterator)
        wcnf = WCNF()
        wcnf.extend(cnf)
        wcnf = self.__createWeights(wcnf, artefactForMinimization)

        self.__formula_time = time.time()
        return wcnf
Example #22
0
def is_transition(places, transition, i, m_ip, space_between_fired):
    '''
    The is_transition method used by is_action creates the formula of a firing transition. Which marking is needed ?
    :param places (list) :
    :param transitions (list) :
    :param i (int) : instant in the run
    :param m_ip (function) : function to get the number of the boolean variables of the markings, see variablesGenerator.
    :return:
    '''
    formulas = []
    prePlaces = [a.source for a in transition.in_arcs]
    postPlaces = [a.target for a in transition.out_arcs]

    for p in places:
        if p in prePlaces and p in postPlaces:
            formulas.append(
                And([
                    m_ip([i, places.index(p)]),
                    m_ip([i - space_between_fired,
                          places.index(p)])
                ], [], []))
        elif p in prePlaces and p not in postPlaces:
            formulas.append(
                And([m_ip([i - space_between_fired,
                           places.index(p)])], [m_ip([i, places.index(p)])],
                    []))
        elif p not in prePlaces and p in postPlaces:
            formulas.append(
                And([m_ip([i, places.index(p)])],
                    [m_ip([i - space_between_fired,
                           places.index(p)])], []))
        elif p not in prePlaces and p not in postPlaces:
            formulas.append(
                Or([], [], [
                    And([
                        m_ip([i, places.index(p)]),
                        m_ip([i - space_between_fired,
                              places.index(p)])
                    ], [], []),
                    And([], [
                        m_ip([i, places.index(p)]),
                        m_ip([i - space_between_fired,
                              places.index(p)])
                    ], [])
                ]))
    return And([], [], formulas)
Example #23
0
 def is_transition_centroid(j, places, tr, i, m_ip):
     '''
     This function verifies marking to fire transition of a centroid.
     :param j (int) : index of centroid
     :param places (list) : list of places
     :param tr (Transition) : transition that wants to fire
     :param i (int) : instant of firing
     :param m_ip (function) : @see @variablesGenerator.py function to get BOOLEAN_VAR_CHI_MARKINGS variables
     '''
     formulas = []
     prePlaces = [a.source for a in tr.in_arcs]
     postPlaces = [a.target for a in tr.out_arcs]
     # token game
     for p in places:
         if p in prePlaces and p in postPlaces:
             formulas.append(
                 And([
                     m_ip([j, i, places.index(p)]),
                     m_ip([j, i - 1, places.index(p)])
                 ], [], []))
         elif p in prePlaces and p not in postPlaces:
             formulas.append(
                 And([m_ip([j, i - 1, places.index(p)])],
                     [m_ip([j, i, places.index(p)])], []))
         elif p not in prePlaces and p in postPlaces:
             formulas.append(
                 And([m_ip([j, i, places.index(p)])],
                     [m_ip([j, i - 1, places.index(p)])], []))
         elif p not in prePlaces and p not in postPlaces:
             formulas.append(
                 Or([], [], [
                     And([
                         m_ip([j, i, places.index(p)]),
                         m_ip([j, i - 1, places.index(p)])
                     ], [], []),
                     And([], [
                         m_ip([j, i, places.index(p)]),
                         m_ip([j, i - 1, places.index(p)])
                     ], [])
                 ]))
     return And([], [], formulas)
Example #24
0
def recursionEditDistance_reducedForMultiAlignment(transitions, silent_transitions, tau_it, lambda_jia, djiid, j,
                                                   size_of_run,
                                                   wait_transition, max_d):
    '''
    Initialisation of the edit distance reduced for multi-alignment.
    This is the 2 lasts axioms of the _Encoding Conformance Checking Artefacts in SAT_ paper
    :param transitions (list) : list of transitions
    :param silent_transitions (list) : list of the silent transitions
    :param tau_it (fun) : function that returns the boolean variable number of the firing transition t at an instant i
    :param lambda_jia (fun) : function that returns the boolean variable number of the letter of trace j at instant i
    :param djiid (fun) : function that returns the boolean variable that says at instant i and i of we have d distance
    :param j (int) : jth trace
    :param size_of_run (int) : maximal size of a run
    :param wait_transition (transition) : to finish words
    :param max_d (int): heuristic
    :return: formula
    '''

    def t(transition):
        return transitions.index(transition)

    formulas = []
    for i_m in range(0, size_of_run):
        for i_t in range(0, size_of_run):
            for d in range(0, max_d):
                # letters are equals i_t+1 == i_m+1 => (d i_t i_m d => d i_t+1 i_m+1 d)
                letters_are_equals = Or([djiid([j, i_m + 1, i_t + 1, d+1])], [djiid([j, i_m, i_t, d+1])],
                                        [And([], [],
                                             [Or([], [tau_it([i_m + 1, t]), lambda_jia([j, i_t + 1, t])], []) for t in
                                              range(0, len(transitions))]
                                             )])
                formulas.append(letters_are_equals)

                # letters are diff : i_t+1 == i_m+1 => (d i_t i_m d => d i_t+1 i_m+1 d)
                condition = [tau_it([i_m + 1, t(wait_transition)]), lambda_jia([j, i_t + 1, t(wait_transition)])]
                for st in silent_transitions:
                    condition.append(tau_it([i_m + 1, t(st)]))
                condition.append(djiid([j, i_m + 1, i_t + 1, d + 1]))
                letters_are_diff = Or(condition,
                                      [djiid([j, i_m + 1, i_t, d]), djiid([j, i_m, i_t + 1, d])],
                                      [And([tau_it([i_m + 1, t]), lambda_jia([j, i_t + 1, t])], [], []) for
                                       t in range(0, len(transitions))])
                formulas.append(letters_are_diff)

                # ( u_t == w and u_m <> w) => ( d i_m i_t d => d i_m+1 i_t d
                finish_run_of_model = Or([tau_it([i_m + 1, t(wait_transition)]), djiid([j, i_m + 1, i_t + 1, d])],
                                         [lambda_jia([j, i_t + 1, t(wait_transition)]), djiid([j, i_m + 1, i_t, d])],
                                         [])
                formulas.append(finish_run_of_model)

                # ( u_m == w and u_t <> w) => ( d i_m i_t d => d i_m i_t+1 d
                condition=[tau_it([i_m + 1, t(wait_transition)])]
                for st in silent_transitions:
                    condition.append(tau_it([i_m + 1, t(st)]))
                finish_run_of_trace = Or(
                    [lambda_jia([j, i_t + 1, t(wait_transition)]), djiid([j, i_m + 1, i_t + 1, d])],
                    [ djiid([j, i_m, i_t + 1, d])], [
                        And([], condition,[])
                    ])
                formulas.append(finish_run_of_trace)
    return formulas
def apply(net1, m01, mf1, net2, m02, mf2, size_of_run, d, silent_label=None):

    vars = vg.VariablesGenerator()
    #we=add_wait_net_end(net1,"wf")
    w1 = add_wait_net(net1, "wf")
    adapted_size_of_run = size_of_run * size_of_run + size_of_run
    pn1_formula, pn1_places, pn1_transitions, pn1_silent_transitions = petri_net_to_SAT(
        net1,
        m01,
        mf1,
        vars,
        adapted_size_of_run,
        reach_final=True,
        label_m=BOOLEAN_VAR_MARKING_PN_1,
        label_t=BOOLEAN_VAR_FIRING_TRANSITION_PN_1,
        silent_transition=silent_label,
        space_between_fired=1 + size_of_run)
    print("etape1")

    pn1_force_wait_transitions = force_wait_transition(vars, w1,
                                                       pn1_transitions,
                                                       adapted_size_of_run,
                                                       size_of_run + 1)
    print("etape2")
    w2 = add_wait_net(net2, "wf")
    pn2_formula, pn2_places, pn2_transitions, pn2_silent_transitions = petri_net_to_SAT(
        net2,
        m02,
        mf2,
        vars,
        adapted_size_of_run,
        reach_final=True,
        label_m=BOOLEAN_VAR_MARKING_PN_2,
        label_t=BOOLEAN_VAR_FIRING_TRANSITION_PN_2,
        silent_transition=silent_label)
    dist_formulas = distanceNets(
        vars, adapted_size_of_run,
        vars.getFunction(BOOLEAN_VAR_FIRING_TRANSITION_PN_1),
        vars.getFunction(BOOLEAN_VAR_FIRING_TRANSITION_PN_2), pn1_transitions,
        pn2_transitions, w1, w2)
    print("etape3")

    maxDist_formulas = maxDistance(vars, vars.getFunction(BOOLEAN_VAR_DIFF1),
                                   vars.getFunction(BOOLEAN_VAR_DIFF2), d,
                                   adapted_size_of_run)
    #notTooManyW=numberOfWaitInRun(vars,size_of_run,vars.getFunction(BOOLEAN_VAR_FIRING_TRANSITION_PN_1),pn1_transitions,w1,we)
    print("etape4")
    from pm4py.visualization.petrinet import factory as vizu
    #vizu.apply(net2,m02,mf2).view()
    listOfForAll = vars.getAll(BOOLEAN_VAR_MARKING_PN_1) + vars.getAll(
        BOOLEAN_VAR_FIRING_TRANSITION_PN_1)
    listOfExist = vars.getAll(BOOLEAN_VAR_MARKING_PN_2) + vars.getAll(
        BOOLEAN_VAR_FIRING_TRANSITION_PN_2) + vars.getAll(
            BOOLEAN_VAR_DIFF1) + vars.getAll(BOOLEAN_VAR_DIFF2)

    full_formula = Or([], [], [
        And([], [], [pn1_formula, pn1_force_wait_transitions]).negation(),
        And([], [], [dist_formulas, maxDist_formulas, pn2_formula])
    ])
    print("etape5")
    cnf = full_formula.operatorToCnf(vars.iterator)
    print("etape6")
    listOfExist += list(range(vars.iterator, full_formula.nbVars))
    writeQDimacs(full_formula.nbVars, listOfForAll, listOfExist, cnf)
    print("mais voila")
    runCadet()
    positives, negatives = cadetOutputQDimacs()
    for var in positives:
        if vars.getVarName(var) != None and vars.getVarName(var).startswith(
                "tau1_ia"):
            print(
                vars.getVarName(var), pn1_transitions[int(
                    vars.getVarName(var).split(", ")[1].split("]")[0])])

    print("....")
    for var in negatives:
        if vars.getVarName(var) != None and vars.getVarName(var).startswith(
                "tau1_ia"):
            print(
                vars.getVarName(var), pn1_transitions[int(
                    vars.getVarName(var).split(", ")[1].split("]")[0])])