예제 #1
0
def get_tangible_reachability_from_log_net_im_fm(log,
                                                 net,
                                                 im,
                                                 fm,
                                                 parameters=None):
    """
    Gets the tangible reachability graph from a log and an accepting Petri net

    Parameters
    ---------------
    log
        Event log
    net
        Petri net
    im
        Initial marking
    fm
        Final marking

    Returns
    ------------
    reachab_graph
        Reachability graph
    tangible_reach_graph
        Tangible reachability graph
    stochastic_info
        Stochastic information
    """
    if parameters is None:
        parameters = {}

    from pm4py.algo.simulation.montecarlo.utils import replay
    stochastic_info = replay.get_map_from_log_and_net(log_converter.apply(
        log,
        variant=log_converter.Variants.TO_EVENT_LOG,
        parameters=parameters),
                                                      net,
                                                      im,
                                                      fm,
                                                      parameters=parameters)

    reachability_graph, tangible_reachability_graph = get_tangible_reachability_from_net_im_sinfo(
        net, im, stochastic_info, parameters=parameters)

    return reachability_graph, tangible_reachability_graph, stochastic_info
예제 #2
0
def apply_playout(net, initial_marking, no_traces=100, max_trace_length=100,
                  case_id_key=xes_constants.DEFAULT_TRACEID_KEY,
                  activity_key=xes_constants.DEFAULT_NAME_KEY, timestamp_key=xes_constants.DEFAULT_TIMESTAMP_KEY,
                  final_marking=None, smap=None, log=None, return_visited_elements=False):
    """
    Do the playout of a Petrinet generating a log

    Parameters
    ----------
    net
        Petri net to play-out
    initial_marking
        Initial marking of the Petri net
    no_traces
        Number of traces to generate
    max_trace_length
        Maximum number of events per trace (do break)
    case_id_key
        Trace attribute that is the case ID
    activity_key
        Event attribute that corresponds to the activity
    timestamp_key
        Event attribute that corresponds to the timestamp
    final_marking
        If provided, the final marking of the Petri net
    smap
        Stochastic map
    log
        Log
    """
    if final_marking is None:
        # infer the final marking from the net
        final_marking = final_marking_discovery.discover_final_marking(net)
    if smap is None:
        if log is None:
            raise Exception("please provide at least one between stochastic map and log")
        smap = replay.get_map_from_log_and_net(log, net, initial_marking, final_marking,
                                               parameters={Parameters.ACTIVITY_KEY: activity_key,
                                                           Parameters.TIMESTAMP_KEY: timestamp_key})
    # assigns to each event an increased timestamp from 1970
    curr_timestamp = 10000000
    all_visited_elements = []

    for i in range(no_traces):
        visited_elements = []
        visible_transitions_visited = []
        marking = copy(initial_marking)

        while len(visible_transitions_visited) < max_trace_length:
            visited_elements.append(marking)

            if not semantics.enabled_transitions(net, marking):  # supports nets with possible deadlocks
                break
            all_enabled_trans = semantics.enabled_transitions(net, marking)
            if final_marking is not None and marking == final_marking:
                en_t_list = list(all_enabled_trans.union({None}))
            else:
                en_t_list = list(all_enabled_trans)

            trans = stochastic_utils.pick_transition(en_t_list, smap)

            if trans is None:
                break

            visited_elements.append(trans)
            if trans.label is not None:
                visible_transitions_visited.append(trans)

            marking = semantics.execute(trans, net, marking)

        all_visited_elements.append(tuple(visited_elements))

    if return_visited_elements:
        return all_visited_elements

    log = log_instance.EventLog()

    for index, visited_elements in enumerate(all_visited_elements):
        trace = log_instance.Trace()
        trace.attributes[case_id_key] = str(index)
        for element in visited_elements:
            if type(element) is PetriNet.Transition and element.label is not None:
                event = log_instance.Event()
                event[activity_key] = element.label
                event[timestamp_key] = datetime.datetime.fromtimestamp(curr_timestamp)
                trace.append(event)
                # increases by 1 second
                curr_timestamp += 1
        log.append(trace)

    return log
예제 #3
0
def apply(log, net, im, fm, parameters=None):
    """
    Performs a Monte Carlo simulation of an accepting Petri net without duplicate transitions and where the preset is always
    distinct from the postset (FIFO variant; the semaphores pile up if waiting is needed, and the first in is the first to win
    the semaphore)

    Parameters
    -------------
    log
        Event log
    net
        Accepting Petri net without duplicate transitions and where the preset is always distinct from the postset
    im
        Initial marking
    fm
        Final marking
    parameters
        Parameters of the algorithm:
            PARAM_NUM_SIMULATIONS => (default: 100)
            PARAM_FORCE_DISTRIBUTION => Force a particular stochastic distribution (e.g. normal) when the stochastic map
            is discovered from the log (default: None; no distribution is forced)
            PARAM_ENABLE_DIAGNOSTICS => Enable the printing of diagnostics (default: True)
            PARAM_DIAGN_INTERVAL => Interval of time in which diagnostics of the simulation are printed (default: 32)
            PARAM_CASE_ARRIVAL_RATIO => Case arrival of new cases (default: None; inferred from the log)
            PARAM_PROVIDED_SMAP => Stochastic map that is used in the simulation (default: None; inferred from the log)
            PARAM_MAP_RESOURCES_PER_PLACE => Specification of the number of resources available per place
            (default: None; each place gets the default number of resources)
            PARAM_DEFAULT_NUM_RESOURCES_PER_PLACE => Default number of resources per place when not specified
            (default: 1; each place gets 1 resource and has to wait for the resource to finish)
            PARAM_SMALL_SCALE_FACTOR => Scale factor for the sleeping time of the actual simulation
            (default: 864000.0, 10gg)
            PARAM_MAX_THREAD_EXECUTION_TIME => Maximum execution time per thread (default: 60.0, 1 minute)

    Returns
    ------------
    simulated_log
        Simulated event log
    simulation_result
        Result of the simulation:
            OUTPUT_PLACES_INTERVAL_TREES => inteval trees that associate to each place the times in which it was occupied.
            OUTPUT_TRANSITIONS_INTERVAL_TREES => interval trees that associate to each transition the intervals of time
            in which it could not fire because some token was in the output.
            OUTPUT_CASES_EX_TIME => Throughput time of the cases included in the simulated log
            OUTPUT_MEDIAN_CASES_EX_TIME => Median of the throughput times
            OUTPUT_CASE_ARRIVAL_RATIO => Case arrival ratio that was specified in the simulation
            OUTPUT_TOTAL_CASES_TIME => Total time occupied by cases of the simulated log
    """
    if parameters is None:
        parameters = {}

    timestamp_key = parameters[
        constants.PARAMETER_CONSTANT_TIMESTAMP_KEY] if constants.PARAMETER_CONSTANT_TIMESTAMP_KEY in parameters else xes_constants.DEFAULT_TIMESTAMP_KEY
    no_simulations = parameters[
        PARAM_NUM_SIMULATIONS] if PARAM_NUM_SIMULATIONS in parameters else DEFAULT_NUM_SIMULATIONS
    force_distribution = parameters[PARAM_FORCE_DISTRIBUTION] if PARAM_FORCE_DISTRIBUTION in parameters else None
    enable_diagnostics = parameters[
        PARAM_ENABLE_DIAGNOSTICS] if PARAM_ENABLE_DIAGNOSTICS in parameters else DEFAULT_ENABLE_DIAGNOSTICS
    diagn_interval = parameters[PARAM_DIAGN_INTERVAL] if PARAM_DIAGN_INTERVAL in parameters else DEFAULT_DIAGN_INTERVAL
    case_arrival_ratio = parameters[
        PARAM_CASE_ARRIVAL_RATIO] if PARAM_CASE_ARRIVAL_RATIO in parameters else DEFAULT_CASE_ARRIVAL_RATIO
    smap = parameters[PARAM_PROVIDED_SMAP] if PARAM_PROVIDED_SMAP in parameters else DEFAULT_PROVIDED_SMAP
    resources_per_places = parameters[
        PARAM_MAP_RESOURCES_PER_PLACE] if PARAM_MAP_RESOURCES_PER_PLACE in parameters else DEFAULT_MAP_RESOURCES_PER_PLACE
    default_num_resources_per_places = parameters[
        PARAM_DEFAULT_NUM_RESOURCES_PER_PLACE] if PARAM_DEFAULT_NUM_RESOURCES_PER_PLACE in parameters else DEFAULT_DEFAULT_NUM_RESOURCES_PER_PLACES
    small_scale_factor = parameters[
        PARAM_SMALL_SCALE_FACTOR] if PARAM_SMALL_SCALE_FACTOR in parameters else DEFAULT_SMALL_SCALE_FACTOR
    max_thread_exec_time = parameters[
        PARAM_MAX_THREAD_EXECUTION_TIME] if PARAM_MAX_THREAD_EXECUTION_TIME in parameters else DEFAULT_MAX_THREAD_EXECUTION_TIME

    if case_arrival_ratio is None:
        case_arrival_ratio = case_arrival.get_case_arrival_avg(log, parameters=parameters)
    if resources_per_places is None:
        resources_per_places = {}

    logging.basicConfig()
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.DEBUG)

    places_interval_trees = {}
    transitions_interval_trees = {}
    cases_ex_time = []
    list_cases = {}

    for place in net.places:
        # assign a semaphore to each place.
        if place in resources_per_places:
            place.semaphore = Semaphore(resources_per_places[place])
        else:
            # if the user does not specify the number of resources per place,
            # the default number is used
            place.semaphore = Semaphore(default_num_resources_per_places)
        place.assigned_time = []
        places_interval_trees[place] = IntervalTree()
    for trans in net.transitions:
        transitions_interval_trees[trans] = IntervalTree()

    # when the user does not specify any map from transitions to random variables,
    # a replay operation is performed
    if smap is None:
        if enable_diagnostics:
            logger.info(str(time()) + " started the replay operation.")
        if force_distribution is not None:
            smap = replay.get_map_from_log_and_net(log, net, im, fm, force_distribution=force_distribution,
                                                   parameters=parameters)
        else:
            smap = replay.get_map_from_log_and_net(log, net, im, fm, parameters=parameters)
        if enable_diagnostics:
            logger.info(str(time()) + " ended the replay operation.")

    # the start timestamp is set to 1000000 instead of 0 to avoid problems with 32 bit machines
    start_time = 1000000
    threads = []
    for i in range(no_simulations):
        list_cases[i] = Trace()
        t = SimulationThread(i, net, im, fm, smap, start_time, places_interval_trees, transitions_interval_trees,
                             cases_ex_time, list_cases, enable_diagnostics, diagn_interval, small_scale_factor,
                             max_thread_exec_time)
        t.start()
        threads.append(t)
        start_time = start_time + case_arrival_ratio
        # wait a factor before opening a thread and the next one
        sleep(case_arrival_ratio / small_scale_factor)

    for t in threads:
        t.join()

    i = 0
    while i < len(threads):
        if threads[i].terminated_correctly is False:
            del list_cases[threads[i].id]
            del threads[i]
            del cases_ex_time[i]
            continue
        i = i + 1

    if enable_diagnostics:
        logger.info(str(time()) + " ended the Monte carlo simulation.")

    log = EventLog(list(list_cases.values()))
    min_timestamp = log[0][0][timestamp_key].timestamp()
    max_timestamp = max(y[timestamp_key].timestamp() for x in log for y in x)

    transitions_interval_trees = {t.name: y for t, y in transitions_interval_trees.items()}

    return log, {OUTPUT_PLACES_INTERVAL_TREES: places_interval_trees,
                 OUTPUT_TRANSITIONS_INTERVAL_TREES: transitions_interval_trees, OUTPUT_CASES_EX_TIME: cases_ex_time,
                 OUTPUT_MEDIAN_CASES_EX_TIME: median(cases_ex_time), OUTPUT_CASE_ARRIVAL_RATIO: case_arrival_ratio,
                 OUTPUT_TOTAL_CASES_TIME: max_timestamp - min_timestamp}