Esempio n. 1
0
def apply_trace_net(petri_net, initial_marking, final_marking, trace_net, trace_im, trace_fm, parameters=None):
    """
        Performs the basic alignment search, given a trace net and a net.

        Parameters
        ----------
        trace: :class:`list` input trace, assumed to be a list of events (i.e. the code will use the activity key
        to get the attributes)
        petri_net: :class:`pm4py.objects.petri.net.PetriNet` the Petri net to use in the alignment
        initial_marking: :class:`pm4py.objects.petri.net.Marking` initial marking in the Petri net
        final_marking: :class:`pm4py.objects.petri.net.Marking` final marking in the Petri net
        parameters: :class:`dict` (optional) dictionary containing one of the following:
            Parameters.PARAM_TRACE_COST_FUNCTION: :class:`list` (parameter) mapping of each index of the trace to a positive cost value
            Parameters.PARAM_MODEL_COST_FUNCTION: :class:`dict` (parameter) mapping of each transition in the model to corresponding
            model cost
            Parameters.PARAM_SYNC_COST_FUNCTION: :class:`dict` (parameter) mapping of each transition in the model to corresponding
            synchronous costs
            Parameters.ACTIVITY_KEY: :class:`str` (parameter) key to use to identify the activity described by the events
            Parameters.PARAM_TRACE_NET_COSTS: :class:`dict` (parameter) mapping between transitions and costs

        Returns
        -------
        dictionary: `dict` with keys **alignment**, **cost**, **visited_states**, **queued_states** and **traversed_arcs**
        """
    if parameters is None:
        parameters = {}

    ret_tuple_as_trans_desc = exec_utils.get_param_value(Parameters.PARAM_ALIGNMENT_RESULT_IS_SYNC_PROD_AWARE,
                                                         parameters, False)

    trace_cost_function = exec_utils.get_param_value(Parameters.PARAM_TRACE_COST_FUNCTION, parameters, None)
    model_cost_function = exec_utils.get_param_value(Parameters.PARAM_MODEL_COST_FUNCTION, parameters, None)
    sync_cost_function = exec_utils.get_param_value(Parameters.PARAM_SYNC_COST_FUNCTION, parameters, None)
    trace_net_costs = exec_utils.get_param_value(Parameters.PARAM_TRACE_NET_COSTS, parameters, None)


    if trace_cost_function is None or model_cost_function is None or sync_cost_function is None:
        sync_prod, sync_initial_marking, sync_final_marking = petri.synchronous_product.construct(trace_net, trace_im,
                                                                                                  trace_fm, petri_net,
                                                                                                  initial_marking,
                                                                                                  final_marking,
                                                                                                  utils.SKIP)
        cost_function = utils.construct_standard_cost_function(sync_prod, utils.SKIP)
    else:
        revised_sync = dict()
        for t_trace in trace_net.transitions:
            for t_model in petri_net.transitions:
                if t_trace.label == t_model.label:
                    revised_sync[(t_trace, t_model)] = sync_cost_function[t_model]

        sync_prod, sync_initial_marking, sync_final_marking, cost_function = construct_cost_aware(
            trace_net, trace_im, trace_fm, petri_net, initial_marking, final_marking, utils.SKIP,
            trace_net_costs, model_cost_function, revised_sync)

    max_align_time_trace = exec_utils.get_param_value(Parameters.PARAM_MAX_ALIGN_TIME_TRACE, parameters,
                                                      sys.maxsize)

    return apply_sync_prod(sync_prod, sync_initial_marking, sync_final_marking, cost_function,
                           utils.SKIP, ret_tuple_as_trans_desc=ret_tuple_as_trans_desc,
                           max_align_time_trace=max_align_time_trace)
def apply_trace_net(petri_net, initial_marking, final_marking, trace_net, trace_im, trace_fm, parameters=None):
    if parameters is None:
        parameters = {}

    ret_tuple_as_trans_desc = parameters[
        PARAM_ALIGNMENT_RESULT_IS_SYNC_PROD_AWARE] if PARAM_ALIGNMENT_RESULT_IS_SYNC_PROD_AWARE in parameters else False

    if parameters is None or PARAM_TRACE_COST_FUNCTION not in parameters or PARAM_MODEL_COST_FUNCTION not in parameters or PARAM_SYNC_COST_FUNCTION not in parameters:
        sync_prod, sync_initial_marking, sync_final_marking = petri.synchronous_product.construct(trace_net, trace_im,
                                                                                                  trace_fm, petri_net,
                                                                                                  initial_marking,
                                                                                                  final_marking,
                                                                                                  utils.SKIP)
        cost_function = utils.construct_standard_cost_function(sync_prod, utils.SKIP)
    else:
        revised_sync = dict()
        for t_trace in trace_net.transitions:
            for t_model in petri_net.transitions:
                if t_trace.label == t_model.label:
                    revised_sync[(t_trace, t_model)] = parameters[PARAM_SYNC_COST_FUNCTION][t_model]

        sync_prod, sync_initial_marking, sync_final_marking, cost_function = construct_cost_aware(
            trace_net, trace_im, trace_fm, petri_net, initial_marking, final_marking, utils.SKIP,
            parameters[PARAM_TRACE_NET_COSTS], parameters[PARAM_MODEL_COST_FUNCTION], revised_sync)

    max_align_time_trace = parameters[
        PARAM_MAX_ALIGN_TIME_TRACE] if PARAM_MAX_ALIGN_TIME_TRACE in parameters else DEFAULT_MAX_ALIGN_TIME_TRACE

    return apply_sync_prod(sync_prod, sync_initial_marking, sync_final_marking, cost_function,
                           utils.SKIP, ret_tuple_as_trans_desc=ret_tuple_as_trans_desc,
                           max_align_time_trace=max_align_time_trace)
Esempio n. 3
0
def align_fake_log_stop_marking(fake_log, net, marking, final_marking, parameters=None):
    """
    Align the 'fake' log_skeleton with all the prefixes in order to get the markings in which
    the alignment stops

    Parameters
    -------------
    fake_log
        Fake log_skeleton
    net
        Petri net
    marking
        Marking
    final_marking
        Final marking
    parameters
        Parameters of the algorithm

    Returns
    -------------
    alignment
        For each trace in the log_skeleton, return the marking in which the alignment stops (expressed as place name with count)
    """
    if parameters is None:
        parameters = {}
    align_result = []
    for i in range(len(fake_log)):
        trace = fake_log[i]
        sync_net, sync_initial_marking, sync_final_marking = build_sync_net(trace, net, marking, final_marking,
                                                                            parameters=parameters)
        stop_marking = Marking()
        for pl, count in sync_final_marking.items():
            if pl.name[1] == utils.SKIP:
                stop_marking[pl] = count
        cost_function = utils.construct_standard_cost_function(sync_net, utils.SKIP)

        # perform the alignment of the prefix
        res = precision_utils.__search(sync_net, sync_initial_marking, sync_final_marking, stop_marking, cost_function,
                                       utils.SKIP)

        if res is not None:
            align_result.append([])
            for mark in res:
                res2 = {}
                for pl in mark:
                    # transforms the markings for easier correspondence at the end
                    # (distributed engine friendly!)
                    res2[(pl.name[0], pl.name[1])] = mark[pl]

                align_result[-1].append(res2)
        else:
            # if there is no path from the initial marking
            # replaying the given prefix, then add None
            align_result.append(None)

    return align_result
Esempio n. 4
0
def align_fake_log_stop_marking(fake_log,
                                net,
                                marking,
                                final_marking,
                                parameters=None):
    """
    Align the 'fake' log with all the prefixes in order to get the markings in which
    the alignment stops

    Parameters
    -------------
    fake_log
        Fake log
    net
        Petri net
    marking
        Marking
    final_marking
        Final marking
    parameters
        Parameters of the algorithm

    Returns
    -------------
    alignment
        For each trace in the log, return the marking in which the alignment stops (expressed as place name with count)
    """
    if parameters is None:
        parameters = {}
    max_trace_length = max(len(x) for x in fake_log)
    align_result = []
    for i in range(len(fake_log)):
        trace = fake_log[i]
        sync_net, sync_initial_marking, sync_final_marking = build_sync_net(
            trace, net, marking, final_marking)
        stop_marking = petri.petrinet.Marking()
        for pl, count in sync_final_marking.items():
            if pl.name[1] == utils.SKIP:
                stop_marking[pl] = count
        cost_function = utils.construct_standard_cost_function(
            sync_net, utils.SKIP)

        res = __search(sync_net, sync_initial_marking, sync_final_marking,
                       stop_marking, cost_function, utils.SKIP,
                       max_trace_length)
        res2 = {}

        for pl in res:
            res2[(pl.name[0], pl.name[1])] = res[pl]

        align_result.append(res2)

    return align_result
Esempio n. 5
0
    def __init__(self, net: PetriNet, im: Marking, fm: Marking,
                 parameters: Optional[Dict[Any, Any]] = None):
        """
        Constructor

        Parameters
        ---------------
        net
            Petri net
        im
            Initial marking
        fm
            Final marking
        parameters
            Parameters of the algorithm, including:
            - Parameters.CASE_ID_KEY => attribute to use as case identifier
            - Parameters.ACTIVITY_KEY => attribute to use as activity
            - Parameters.COSTS => (if provided) the cost function (otherwise the default cost function is applied)
            - Parameters.INCIDENCE_MATRIX => (if provided) the incidence matrix of the sync product net
            - Parameters.A => (if provided) the A numpy matrix of the incidence matrix
            - Parameters.FULL_BOOTSTRAP_REQUIRED => The preset/postset of places/transitions need to be inserted
        """
        if parameters is None:
            parameters = {}

        costs = exec_utils.get_param_value(Parameters.COSTS, parameters, None)

        if costs is None:
            costs = align_utils.construct_standard_cost_function(net, align_utils.SKIP)

        self.net = net
        self.ini = im
        self.fin = fm
        self.costs = costs
        self.incidence_matrix = exec_utils.get_param_value(Parameters.INCIDENCE_MATRIX, parameters,
                                                           IncidenceMatrix(self.net))
        self.Aeq = exec_utils.get_param_value(Parameters.A, parameters, np.asmatrix(self.incidence_matrix.a_matrix))
        self.full_bootstrap_required = exec_utils.get_param_value(Parameters.FULL_BOOTSTRAP_REQUIRED, parameters, True)

        self.__build_entities()
        self.__build_problem_components()
Esempio n. 6
0
def apply_trace_net(petri_net, initial_marking, final_marking, trace_net,
                    trace_im, trace_fm):
    """
    Apply the alignment to a Petri net with initial and final marking,
    providing the trace net

    Parameters
    -------------
    petri_net
        Model
    initial_marking
        IM of the model
    final_marking
        FM of the model
    trace_net
        Trace net
    trace_im
        IM of the trace net
    trace_fm
        FM of the trace net

    Returns
    -------------
    alignment
        Alignment
    cost_function
        Cost function
    """
    sync_prod, sync_initial_marking, sync_final_marking = petri.synchronous_product.construct(
        trace_net, trace_im, trace_fm, petri_net, initial_marking,
        final_marking, utils.SKIP)
    cost_function = utils.construct_standard_cost_function(
        sync_prod, utils.SKIP)

    return __search(sync_prod, sync_initial_marking, sync_final_marking,
                    cost_function, utils.SKIP), cost_function
def apply(log, net, marking, final_marking, parameters=None):
    """
    Get Align-ET Conformance precision

    Parameters
    ----------
    log
        Trace log
    net
        Petri net
    marking
        Initial marking
    final_marking
        Final marking
    parameters
        Parameters of the algorithm, including:
            pm4py.util.constants.PARAMETER_CONSTANT_ACTIVITY_KEY -> Activity key
    """

    if parameters is None:
        parameters = {}

    activity_key = parameters[
        PARAM_ACTIVITY_KEY] if PARAM_ACTIVITY_KEY in parameters else log_lib.util.xes.DEFAULT_NAME_KEY
    precision = 0.0
    sum_ee = 0
    sum_at = 0

    if not (petri.check_soundness.check_wfnet(net) and
            petri.check_soundness.check_relaxed_soundness_net_in_fin_marking(
                net, marking, final_marking)):
        raise Exception(
            "trying to apply Align-ETConformance on a Petri net that is not a relaxed sound workflow net!!"
        )

    places_corr = {p.name: p for p in net.places}
    prefixes, prefix_count = precision_utils.get_log_prefixes(
        log, activity_key=activity_key)
    prefixes_keys = list(prefixes.keys())
    fake_log = precision_utils.form_fake_log(prefixes_keys,
                                             activity_key=activity_key)
    max_trace_length = max(len(x) for x in fake_log)
    for i in range(len(fake_log)):
        trace = fake_log[i]
        sync_net, sync_initial_marking, sync_final_marking = build_sync_net(
            trace, net, marking, final_marking)
        stop_marking = petri.petrinet.Marking()
        for pl, count in sync_final_marking.items():
            if pl.name[1] == utils.SKIP:
                stop_marking[pl] = count
        cost_function = utils.construct_standard_cost_function(
            sync_net, utils.SKIP)

        res = __search(sync_net, sync_initial_marking, sync_final_marking,
                       stop_marking, cost_function, utils.SKIP,
                       max_trace_length)
        atm = petri.petrinet.Marking()
        for pl, count in res.items():
            if pl.name[0] == utils.SKIP:
                atm[places_corr[pl.name[1]]] = count

        log_transitions = set(prefixes[prefixes_keys[i]])
        activated_transitions_labels = set(
            x.label for x in utils.
            get_visible_transitions_eventually_enabled_by_marking(net, atm)
            if x.label is not None)
        sum_at += len(activated_transitions_labels) * prefix_count[
            prefixes_keys[i]]
        escaping_edges = activated_transitions_labels.difference(
            log_transitions)
        sum_ee += len(escaping_edges) * prefix_count[prefixes_keys[i]]

    if sum_at > 0:
        precision = 1 - float(sum_ee) / float(sum_at)

    return precision
Esempio n. 8
0
    def __init__(self, trace: Trace, sync_net: PetriNet, sync_im: Marking, sync_fm: Marking,
                 parameters: Optional[Dict[Any, Any]] = None):
        """
        Constructor

        Parameters
        ---------------
        trace
            Trace
        sync_net
            Synchronous product net
        sync_im
            Initial marking
        sync_fm
            Final marking
        parameters
            Parameters of the algorithm, including:
            - Parameters.CASE_ID_KEY => attribute to use as case identifier
            - Parameters.ACTIVITY_KEY => attribute to use as activity
            - Parameters.COSTS => (if provided) the cost function (otherwise the default cost function is applied)
            - Parameters.SPLIT_IDX => (if provided) the split points as indices of elements of the trace
                (e.g. for ["A", "B", "C", "D", "E"], specifying [1,3] as split points means splitting at "B" and "D").
                If not provided, some split points at uniform distances are found.
            - Parameters.MAX_K_VALUE => the maximum number of split points that is allowed (trim the specified indexes
                if necessary).
            - Parameters.INCIDENCE_MATRIX => (if provided) the incidence matrix associated to the sync product net
            - Parameters.A => (if provided) the A numpy matrix of the incidence matrix
            - Parameters.CONSUMPTION_MATRIX => (if provided) the consumption matrix associated to the sync product net
            - Parameters.C => (if provided) the C numpy matrix of the consumption matrix
            - Parameters.FULL_BOOTSTRAP_REQUIRED => The preset/postset of places/transitions need to be inserted
        """
        if parameters is None:
            parameters = {}

        activity_key = exec_utils.get_param_value(Parameters.ACTIVITY_KEY, parameters, xes_constants.DEFAULT_NAME_KEY)
        max_k_value = exec_utils.get_param_value(Parameters.MAX_K_VALUE, parameters, 5)
        costs = exec_utils.get_param_value(Parameters.COSTS, parameters, None)
        split_idx = exec_utils.get_param_value(Parameters.SPLIT_IDX, parameters, None)
        self.full_bootstrap_required = exec_utils.get_param_value(Parameters.FULL_BOOTSTRAP_REQUIRED, parameters, True)

        self.trace = [x[activity_key] for x in trace]
        if costs is None:
            costs = align_utils.construct_standard_cost_function(sync_net, align_utils.SKIP)
        if split_idx is None:
            split_idx = [i for i in range(1, len(trace))]
        self.split_idx = split_idx
        if len(self.split_idx) > max_k_value:
            self.split_idx = points_subset.pick_chosen_points_list(max_k_value, self.split_idx)
        self.k = len(self.split_idx) if len(self.split_idx) > 1 else 2
        self.sync_net = sync_net
        self.ini = sync_im
        self.fin = sync_fm
        self.costs = costs
        self.incidence_matrix = exec_utils.get_param_value(Parameters.INCIDENCE_MATRIX, parameters,
                                                           IncidenceMatrix(self.sync_net))
        self.consumption_matrix = exec_utils.get_param_value(Parameters.CONSUMPTION_MATRIX, parameters,
                                                             ConsumptionMatrix(self.sync_net))
        self.A = exec_utils.get_param_value(Parameters.A, parameters, np.asmatrix(self.incidence_matrix.a_matrix))
        self.C = exec_utils.get_param_value(Parameters.C, parameters, np.asmatrix(self.consumption_matrix.c_matrix))

        self.__build_entities()