Example #1
0
def early_execution(network: STN, realization: dict) -> bool:
    ## Bookkeeping for events
    all_uncontrollables = set(network.uncontrollables)
    unused_events = set(network.verts.keys())
    not_scheduled = PriorityQueue()
    final_schedule = {}

    # Mapping from contingent sources to uncontrollables
    contingent_pairs = network.contingentEdges.keys()
    disabled_uncontrollables = {src: sink for (src, sink) in contingent_pairs}

    # Initialize bounds for simulation - starts off with just controllables
    # and zero time point
    controllable_bounds = find_bounds(network)
    true_weight = {}
    for event in controllable_bounds:
        not_scheduled.push(event, controllable_bounds[0])
        true_weight[event] = controllable_bounds[0]
    not_scheduled.addOrDecKey(ZERO_ID, 0)

    # Run simulation
    old_time = 0
    while len(unused_events) > 0:
        current_time, activated_event = not_scheduled.pop()

        # This check ensures that we popped out a valid time_point
        # A better way to deal with this would be to just figure out a way to
        # increase priorities of elements in a heap
        if activated_event in true_weight:
            if true_weight[activated_event] > current_time:
                continue

        unused_events.remove(activated_event)
        final_schedule[activated_event] = current_time

        assert old_time < current_time, "Chronology violated!"

        if activated_event in disabled_uncontrollables:
            # If this is a contingent source, we add the associated uncontrollable sink
            # to the queue
            uncontrollable = disabled_uncontrollables[activated_event]
            delay = realization[uncontrollable]
            not_scheduled.push(uncontrollable, current_time + delay)

        # Update the bounds for all other timepoints
        # We only care about events being moved later in time
        relevant_edges = network.getEdges(activated_event)
        for edge in relevant_edges:
            if (edge.j == activated_event) and (edge.i
                                                not in all_uncontrollables):
                if needs_early_update(edge, activated_event, current_time,
                                      true_weight):
                    lower_bound = current_time - edge.Cij
                    true_weight[edge.i] = lower_bound

        # Keep track of this for next iteration of loop
        old_time = current_time
    # Check if we dispatched succesfully
    return emp.scheduleIsValid(network, final_schedule)