#include #include #include #include "pns.h" /* MACROS */ #define CHECK_MEMORY_ERROR(result) if (!result) {\ fprintf(stderr, "Out of memory");\ exit(EXIT_FAILURE);\ } #define RESIZE_ARRAY(count, size, value) if (count > size) {\ size = count + count / 5;\ value = realloc(value, size * sizeof(*value));\ CHECK_MEMORY_ERROR(value);\ } #define ADD_ELEMENT(name, count, size, value) {\ name = count++;\ RESIZE_ARRAY(count, size, value)\ } /* UNEXPORTED */ /** IndexArray **/ static void pnsCreateIndexArray(PnsIndexArray* array, size_t count, PnsIndexList* list) { array->count = count; array->indices = malloc(array->count * sizeof(size_t)); array->size = array->count; CHECK_MEMORY_ERROR(array->indices); int ti = 0; while (list) { array->indices[ti] = list->index; ++ti; list = list->next; } } static void pnsCloneIndexArray(PnsIndexArray* array_clone, const PnsIndexArray* array) { array_clone->count = array->count; array_clone->size = array->count; array_clone->indices = malloc(array->count * sizeof(size_t)); CHECK_MEMORY_ERROR(array_clone->indices); memcpy(array_clone->indices, array->indices, array->count * sizeof(size_t)); } /** Node **/ static void pnsCloneNode(PnsNode* node_clone, const PnsNode* node) { pnsCloneIndexArray(&node_clone->prev, &node->prev); pnsCloneIndexArray(&node_clone->next, &node->next); } static void pnsDeleteNode(PnsNode* node) { free(node->prev.indices); free(node->next.indices); *node = (PnsNode) { }; } /** IndexList **/ static void pnsIndexList_push(PnsIndexList** place, size_t index) { PnsIndexList* new_list = malloc(sizeof(PnsIndexList)); CHECK_MEMORY_ERROR(new_list); new_list->index = index; new_list->next = *place; *place = new_list; } static void pnsCloneIndexList(PnsIndexList** clone_place, PnsIndexList* list) { while (list) { PnsIndexList* new_list = malloc(sizeof(PnsIndexList)); CHECK_MEMORY_ERROR(new_list); new_list->index = list->index; new_list->next = NULL; *clone_place = new_list; clone_place = &new_list->next; list = list->next; } } static size_t pnsIndexList_pop(PnsIndexList** place) { size_t tid = (*place)->index; PnsIndexList* next = (*place)->next; free(*place); *place = next; return tid; } static bool pnsIndexList_appendNew(PnsIndexList** place, size_t tid) { start: if (!*place) { pnsIndexList_push(place, tid); return true; } if ((*place)->index == tid) return false; place = &(*place)->next; goto start; } static bool pnsIndexList_remove(PnsIndexList** place, size_t tid) { start: if (!*place) return false; if ((*place)->index == tid) { PnsIndexList* current = *place; *place = (*place)->next; free(current); return true; } place = &(*place)->next; goto start; } static void pnsDestroyIndexList(PnsIndexList* list) { while (list) { PnsIndexList* current = list; list = list->next; free(current); } } static void pnsClearIndexList(PnsIndexList** list) { pnsDestroyIndexList(*list); *list = NULL; } /** Fire Changes **/ static void pnsDestroyFireState(PnsFireState* state) { pnsDestroyIndexList(state->active.transitions); pnsDestroyIndexList(state->added.transitions); pnsDestroyIndexList(state->removed.transitions); } static void PnsFireState_add(PnsFireState* state, size_t tid) { bool added = pnsIndexList_appendNew(&state->active.transitions, tid); state->active.count += added; if (added) { if (pnsIndexList_remove(&state->removed.transitions, tid)) --state->removed.count; else { ++state->added.count; pnsIndexList_push(&state->added.transitions, tid); } } } static void PnsFireState_remove(PnsFireState* state, size_t tid) { bool removed = pnsIndexList_remove(&state->active.transitions, tid); state->active.count -= removed; if (removed) { if (pnsIndexList_remove(&state->added.transitions, tid)) --state->added.count; else { ++state->removed.count; pnsIndexList_push(&state->removed.transitions, tid); } } } /** NodeArray **/ static void pnsCloneNodeArray(PnsNodeArray* array_clone, const PnsNodeArray* array) { array_clone->count = array->count; array_clone->size = array->count; array_clone->nodes = malloc(array->count * sizeof(PnsNode)); CHECK_MEMORY_ERROR(array_clone->nodes); for (size_t tid = 0; tid < array->count; ++tid) { pnsCloneNode(&array_clone->nodes[tid], &array->nodes[tid]); } array_clone->reusable = NULL; pnsCloneIndexList(&array_clone->reusable, array->reusable); } /** helpers **/ /*** Array ***/ static size_t sortIndex(size_t id, size_t count, size_t* ids) { for (size_t i = 0; i < count; ++i) { size_t current_id = ids[i]; if (current_id <= id) continue; ids[i] = id; id = current_id; } return id; } static void removeIndex(size_t id, size_t* count, size_t* ids) { if (!*count) return; --*count; size_t i = 0; if (ids[*count] == id) return; while (i < *count) { if (ids[i] == id) { ids[i] = ids[i + 1]; break; } ++i; } if (i == *count) { ++*count; return; } while (++i < *count) ids[i] = ids[i + 1]; } /*** token calculations ***/ static size_t token_count(const PnsState* state, const PnsNet* net, size_t pid) { return state->tokens.counts[pid] + net->initial_token_counts[pid]; } static void addFireable(PnsState* state, size_t tid) { PnsFireState_add(&state->fire, tid); } static void removeFireable(PnsState* state, size_t tid) { PnsFireState_remove(&state->fire, tid); } static void addUnfireable(PnsState* state, size_t tid) { PnsFireState_add(&state->unfire, tid); } static void removeUnfireable(PnsState* state, size_t tid) { PnsFireState_remove(&state->unfire, tid); } static bool checkFireable(const PnsState* state, const PnsNet* net, PnsNode* transition) { for (size_t pid = 0; pid < transition->prev.count; ++pid) { if (!token_count(state, net, transition->prev.indices[pid])) return false; } return true; } static bool checkUnfireable(const PnsState* state, const PnsNet* net, PnsNode* transition) { for (size_t pid = 0; pid < transition->next.count; ++pid) { if (!token_count(state, net, transition->next.indices[pid])) return false; } return true; } static void recalculate_transition_forward(PnsState* state, const PnsNet* net, size_t tid) { PnsNode* transition = &net->transitions.nodes[tid]; if (checkFireable(state, net, transition)) addFireable(state, tid); else removeFireable(state, tid); } static void recalculate_transition_backward(PnsState* state, const PnsNet* net, size_t tid) { PnsNode* transition = &net->transitions.nodes[tid]; if (checkUnfireable(state, net, transition)) addUnfireable(state, tid); else removeUnfireable(state, tid); } static void calculate_transition_list(PnsState* state, const PnsNet* net) { for (size_t tid = 0; tid < net->transitions.count; ++tid) { PnsNode* transition = &net->transitions.nodes[tid]; if (checkFireable(state, net, transition)) { ++state->fire.active.count; pnsIndexList_push(&state->fire.active.transitions, tid); ++state->fire.added.count; pnsIndexList_push(&state->fire.added.transitions, tid); } if (checkUnfireable(state, net, transition)) { ++state->unfire.active.count; pnsIndexList_push(&state->unfire.active.transitions, tid); ++state->unfire.added.count; pnsIndexList_push(&state->unfire.added.transitions, tid); } } } /* HEADER */ /** Net **/ /*** default ***/ void pnsCreateNet(PnsNet* net) { *net = (PnsNet) { }; } void pnsCloneNet(PnsNet* net_clone, const PnsNet* net) { pnsCloneNodeArray(&net_clone->transitions, &net->transitions); pnsCloneNodeArray(&net_clone->places, &net->places); net_clone->initial_token_counts = malloc(net->places.count * sizeof(size_t)); CHECK_MEMORY_ERROR(net_clone->initial_token_counts); memcpy(net_clone->initial_token_counts, net->initial_token_counts, net->places.count * sizeof(size_t)); } bool pnsLoadNet(PnsNet* net, size_t count, const uint32_t* values) { size_t required_count = 2; if (count < required_count) return false; size_t index = 0; net->places.count = values[index++]; required_count += net->places.count; if (count < required_count) return false; net->places.size = net->places.count; net->places.nodes = malloc(net->places.count * sizeof(PnsNode)); CHECK_MEMORY_ERROR(net->places.nodes); net->initial_token_counts = malloc(net->places.count * sizeof(size_t)); CHECK_MEMORY_ERROR(net->initial_token_counts); for (size_t pid = 0; pid < net->places.count; ++pid) net->initial_token_counts[pid] = values[index++]; net->transitions.count = values[index++]; required_count += 2 * net->transitions.count; if (count < required_count) return false; net->transitions.size = net->transitions.count; net->transitions.nodes = malloc(net->transitions.count * sizeof(PnsNode)); CHECK_MEMORY_ERROR(net->transitions.nodes); net->transitions.reusable = NULL; for (size_t tid = 0; tid < net->transitions.count; ++tid) { PnsNode* transition = &net->transitions.nodes[tid]; transition->next.count = values[index++]; required_count += transition->next.count; if (count < required_count) return false; transition->next.size = transition->next.count; transition->next.indices = malloc(transition->next.count * sizeof(size_t)); CHECK_MEMORY_ERROR(transition->next.indices); for (size_t pi = 0; pi < transition->next.count; ++pi) transition->next.indices[pi] = values[index++]; transition->prev.count = values[index++]; required_count += transition->prev.count; if (count < required_count) return false; transition->prev.size = transition->prev.count; transition->prev.indices = malloc(transition->prev.count * sizeof(size_t)); CHECK_MEMORY_ERROR(transition->prev.indices); for (size_t pi = 0; pi < transition->prev.count; ++pi) transition->prev.indices[pi] = values[index++]; if (!transition->next.count && !transition->prev.count) { pnsIndexList_push(&net->transitions.reusable, tid); } } size_t* place_next_counts = calloc(net->places.count, sizeof(size_t)); CHECK_MEMORY_ERROR(place_next_counts); PnsIndexList** place_next = calloc(net->places.count, sizeof(PnsIndexList*)); CHECK_MEMORY_ERROR(place_next); size_t* place_prev_counts = calloc(net->places.count, sizeof(size_t)); CHECK_MEMORY_ERROR(place_prev_counts); PnsIndexList** place_prev = calloc(net->places.count, sizeof(PnsIndexList*)); CHECK_MEMORY_ERROR(place_prev); net->places.reusable = NULL; for (size_t tid = 0; tid < net->transitions.count; ++tid) { PnsNode* transition = &net->transitions.nodes[tid]; for (size_t pi = 0; pi < transition->next.count; ++pi) { size_t next = transition->next.indices[pi]; ++place_prev_counts[next]; pnsIndexList_push(&place_prev[next], tid); } for (size_t pi = 0; pi < transition->prev.count; ++pi) { size_t prev = transition->prev.indices[pi]; ++place_next_counts[prev]; pnsIndexList_push(&place_next[prev], tid); } } for (size_t pid = 0; pid < net->places.count; ++pid) { PnsNode* place = &net->places.nodes[pid]; pnsCreateIndexArray(&place->next, place_next_counts[pid], place_next[pid]); pnsCreateIndexArray(&place->prev, place_prev_counts[pid], place_prev[pid]); if (!place->next.count && !place->prev.count && !net->initial_token_counts[pid]) { pnsIndexList_push(&net->places.reusable, pid); } } for (size_t pid = 0; pid < net->places.count; ++pid) { pnsDestroyIndexList(place_next[pid]); pnsDestroyIndexList(place_prev[pid]); } free(place_next_counts); free(place_next); free(place_prev_counts); free(place_prev); return true; } void pnsDestroyNet(PnsNet* net) { for (size_t tid = 0; tid < net->transitions.count; ++tid) { PnsNode* transition = &net->transitions.nodes[tid]; pnsDeleteNode(transition); } for (size_t pid = 0; pid < net->places.count; ++pid) { PnsNode* place = &net->places.nodes[pid]; pnsDeleteNode(place); } free(net->transitions.nodes); free(net->places.nodes); free(net->initial_token_counts); pnsDestroyIndexList(net->transitions.reusable); pnsDestroyIndexList(net->places.reusable); } size_t pnsNet_serializeSize(const PnsNet* net) { size_t count = 2 + net->places.count + 2 * net->transitions.count; for (size_t tid = 0; tid < net->transitions.count; ++tid) { PnsNode* transition = &net->transitions.nodes[tid]; count += transition->next.count + transition->prev.count; } return count; } void pnsNet_serialize(const PnsNet* net, uint32_t* values) { size_t index = 0; values[index++] = net->places.count; for (size_t pid = 0; pid < net->places.count; ++pid) values[index++] = net->initial_token_counts[pid]; values[index++] = net->transitions.count; for (size_t tid = 0; tid < net->transitions.count; ++tid) { PnsNode* transition = &net->transitions.nodes[tid]; values[index++] = transition->next.count; for (size_t pi = 0; pi < transition->next.count; ++pi) values[index++] = transition->next.indices[pi]; values[index++] = transition->prev.count; for (size_t pi = 0; pi < transition->prev.count; ++pi) values[index++] = transition->prev.indices[pi]; } } /*** edit ***/ /**** core ****/ static size_t get_pid(PnsNet* net) { size_t pid; start: if (net->places.reusable) { pid = pnsIndexList_pop(&net->places.reusable); PnsNode* place = &net->places.nodes[pid]; if (place->next.count || place->prev.count || net->initial_token_counts[pid]) goto start; } else { pid = net->places.count++; if (net->places.count > net->places.size) { net->places.size = net->places.count + net->places.count / 5; net->places.nodes = realloc(net->places.nodes, net->places.size * sizeof(PnsNode)); CHECK_MEMORY_ERROR(net->places.nodes); net->initial_token_counts = realloc(net->initial_token_counts, net->places.size * sizeof(PnsNode)); CHECK_MEMORY_ERROR(net->initial_token_counts); } } return pid; } static size_t get_tid(PnsNet* net) { size_t tid; start: if (net->transitions.reusable) { tid = pnsIndexList_pop(&net->transitions.reusable); PnsNode* transition = &net->transitions.nodes[tid]; if (transition->next.count || transition->prev.count) goto start; } else ADD_ELEMENT(tid, net->transitions.count, net->transitions.size, net->transitions.nodes) return tid; } size_t pnsNet_addPlace(PnsNet* net) { size_t pid = get_pid(net); PnsNode* node = &net->places.nodes[pid]; *node = (PnsNode) { }; net->initial_token_counts[pid] = 0; return pid; } size_t pnsNet_addTransition(PnsNet* net) { size_t tid = get_tid(net); PnsNode* node = &net->transitions.nodes[tid]; *node = (PnsNode) { }; return tid; } static void removeNode(size_t id, PnsNode* nodes, PnsNode* link_nodes) { PnsNode* node = &nodes[id]; for (size_t i = 0; i < node->prev.count; ++i) { size_t link_id = node->prev.indices[i]; PnsNode* link_node = &link_nodes[link_id]; removeIndex(id, &link_node->next.count, link_node->next.indices); } for (size_t i = 0; i < node->next.count; ++i) { size_t link_id = node->next.indices[i]; PnsNode* link_node = &link_nodes[link_id]; removeIndex(id, &link_node->prev.count, link_node->prev.indices); } pnsDeleteNode(node); } void pnsNet_removePlace(PnsNet* net, size_t pid) { removeNode(pid, net->places.nodes, net->transitions.nodes); net->initial_token_counts[pid] = 0; pnsIndexList_appendNew(&net->places.reusable, pid); } void pnsNet_removeTransition(PnsNet* net, size_t tid) { removeNode(tid, net->transitions.nodes, net->places.nodes); pnsIndexList_appendNew(&net->transitions.reusable, tid); } bool pnsNet_connectPlaceToTransition(PnsNet* net, size_t pid, size_t tid) { PnsNode* transition = &net->transitions.nodes[tid]; PnsNode* place = &net->places.nodes[pid]; for (size_t pi = 0; pi < transition->prev.count; ++pi) { size_t current_pid = transition->prev.indices[pi]; if (current_pid < pid) continue; if (current_pid == pid) return false; transition->prev.indices[pi] = pid; pid = current_pid; } for (size_t ti = 0; ti < place->next.count; ++ti) { size_t current_tid = place->next.indices[ti]; if (current_tid < tid) continue; place->next.indices[ti] = tid; tid = current_tid; } size_t prev_index, next_index; ADD_ELEMENT(prev_index, transition->prev.count, transition->prev.size, transition->prev.indices) ADD_ELEMENT(next_index, place->next.count, place->next.size, place->next.indices) transition->prev.indices[prev_index] = pid; place->next.indices[next_index] = tid; return true; } bool pnsNet_connectTransitionToPlace(PnsNet* net, size_t tid, size_t pid) { PnsNode* transition = &net->transitions.nodes[tid]; PnsNode* place = &net->places.nodes[pid]; for (size_t pi = 0; pi < transition->next.count; ++pi) { size_t current_pid = transition->next.indices[pi]; if (current_pid < pid) continue; if (current_pid == pid) return false; transition->next.indices[pi] = pid; pid = current_pid; } for (size_t ti = 0; ti < place->prev.count; ++ti) { size_t current_tid = place->prev.indices[ti]; if (current_tid < tid) continue; place->prev.indices[ti] = tid; tid = current_tid; } size_t prev_index, next_index; ADD_ELEMENT(next_index, transition->next.count, transition->next.size, transition->next.indices) ADD_ELEMENT(prev_index, place->prev.count, place->prev.size, place->prev.indices) transition->next.indices[next_index] = pid; place->prev.indices[prev_index] = tid; return true; } static void disconnectNodes(size_t first_id, PnsNode* first_nodes, size_t second_id, PnsNode* second_nodes) { PnsNode* first_node = &first_nodes[first_id]; PnsNode* second_node = &second_nodes[second_id]; removeIndex(second_id, &first_node->next.count, first_node->next.indices); removeIndex(first_id, &second_node->prev.count, second_node->prev.indices); } void pnsNet_disconnectPlaceToTransition(PnsNet* net, size_t pid, size_t tid) { disconnectNodes(pid, net->places.nodes, tid, net->transitions.nodes); } void pnsNet_disconnectTransitionToPlace(PnsNet* net, size_t tid, size_t pid) { disconnectNodes(tid, net->transitions.nodes, pid, net->places.nodes); } size_t pnsNet_addInitialTokens(PnsNet* net, size_t pid, size_t count) { return net->initial_token_counts[pid] += count; } /**** utilities ****/ size_t pnsNet_addConnectedPlace(PnsNet* net, size_t input_count, const size_t* input_tids, size_t output_count, const size_t* output_tids) { size_t pid = pnsNet_addPlace(net); for (size_t ti = 0; ti < input_count; ++ti) { size_t tid = input_tids[ti]; pnsNet_connectTransitionToPlace(net, tid, pid); } for (size_t ti = 0; ti < output_count; ++ti) { size_t tid = output_tids[ti]; pnsNet_connectPlaceToTransition(net, pid, tid); } return pid; } size_t pnsNet_addConnectedTransition(PnsNet* net, size_t input_count, const size_t* input_pids, size_t output_count, const size_t* output_pids) { size_t tid = pnsNet_addTransition(net); for (size_t pi = 0; pi < input_count; ++pi) { size_t pid = input_pids[pi]; pnsNet_connectPlaceToTransition(net, pid, tid); } for (size_t pi = 0; pi < output_count; ++pi) { size_t pid = output_pids[pi]; pnsNet_connectTransitionToPlace(net, tid, pid); } return tid; } size_t pnsNet_duplicatePlace(PnsNet* net, size_t pid) { size_t clone_pid = get_pid(net); PnsNode* node = &net->places.nodes[pid]; PnsNode* node_clone = &net->places.nodes[clone_pid]; pnsCloneNode(node_clone, node); net->initial_token_counts[clone_pid] = net->initial_token_counts[pid]; for (size_t ti = 0; ti < node->prev.count; ++ti) { size_t tid = node->prev.indices[ti]; PnsNode* node = &net->transitions.nodes[tid]; size_t new_pid = sortIndex(clone_pid, node->next.count, node->next.indices); size_t id; ADD_ELEMENT(id, node->next.count, node->next.size, node->next.indices) node->next.indices[id] = new_pid; } for (size_t ti = 0; ti < node->next.count; ++ti) { size_t tid = node->next.indices[ti]; PnsNode* node = &net->transitions.nodes[tid]; size_t new_pid = sortIndex(clone_pid, node->prev.count, node->prev.indices); size_t id; ADD_ELEMENT(id, node->prev.count, node->prev.size, node->prev.indices) node->prev.indices[id] = new_pid; } return clone_pid; } size_t pnsNet_duplicateTransition(PnsNet* net, size_t tid) { size_t clone_tid = get_tid(net); PnsNode* node = &net->transitions.nodes[tid]; PnsNode* node_clone = &net->transitions.nodes[clone_tid]; pnsCloneNode(node_clone, node); for (size_t pi = 0; pi < node->prev.count; ++pi) { size_t pid = node->prev.indices[pi]; PnsNode* node = &net->places.nodes[pid]; size_t new_tid = sortIndex(clone_tid, node->next.count, node->next.indices); size_t id; ADD_ELEMENT(id, node->next.count, node->next.size, node->next.indices) node->next.indices[id] = new_tid; } for (size_t pi = 0; pi < node->next.count; ++pi) { size_t pid = node->next.indices[pi]; PnsNode* node = &net->places.nodes[pid]; size_t new_tid = sortIndex(clone_tid, node->prev.count, node->prev.indices); size_t id; ADD_ELEMENT(id, node->prev.count, node->prev.size, node->prev.indices) node->prev.indices[id] = new_tid; } return clone_tid; } /** State **/ /*** helpers ***/ static void pnsFinalizeState(PnsState* state, const PnsNet* net) { state->calls.size = net->transitions.count; state->tokens.size = net->places.count; state->fire = (PnsFireState) { }; state->unfire = (PnsFireState) { }; calculate_transition_list(state, net); } /*** default ***/ void pnsCreateState(PnsState* state, const PnsNet* net) { state->tokens.counts = calloc(net->places.count, sizeof(size_t)); CHECK_MEMORY_ERROR(state->tokens.counts); state->calls.counts = calloc(net->transitions.count, sizeof(size_t)); CHECK_MEMORY_ERROR(state->calls.counts); pnsFinalizeState(state, net); } void pnsCloneState(PnsState* state_clone, const PnsState* state, const PnsNet* net) { state_clone->tokens.counts = malloc(net->places.count * sizeof(size_t)); CHECK_MEMORY_ERROR(state_clone->tokens.counts); memcpy(state_clone->tokens.counts, state->tokens.counts, net->places.count * sizeof(size_t)); state_clone->calls.counts = malloc(net->transitions.count * sizeof(size_t)); CHECK_MEMORY_ERROR(state_clone->calls.counts); memcpy(state_clone->calls.counts, state->calls.counts, net->transitions.count * sizeof(size_t)); pnsFinalizeState(state_clone, net); } bool pnsLoadState(PnsState* state, const PnsNet* net, size_t count, const uint32_t* values) { if (count > net->transitions.count) return false; state->tokens.counts = calloc(net->places.count, sizeof(size_t)); CHECK_MEMORY_ERROR(state->tokens.counts); state->calls.counts = malloc(net->transitions.count * sizeof(size_t)); CHECK_MEMORY_ERROR(state->calls.counts); for (size_t tid = 0; tid < count; ++tid) { size_t value = values[tid]; state->calls.counts[tid] = value; PnsNode* transition = &net->transitions.nodes[tid]; for (size_t pi = 0; pi < transition->prev.count; ++pi) { size_t pid = transition->prev.indices[pi]; state->tokens.counts[pid] -= value; } for (size_t pi = 0; pi < transition->next.count; ++pi) { size_t pid = transition->next.indices[pi]; state->tokens.counts[pid] += value; } } for (size_t tid = count; tid < net->transitions.count; ++tid) { state->calls.counts[tid] = 0; } pnsFinalizeState(state, net); return true; } void pnsDestroyState(PnsState* state) { free(state->tokens.counts); free(state->calls.counts); pnsDestroyFireState(&state->fire); pnsDestroyFireState(&state->unfire); } /*** simulate ***/ PnsTransitionView pnsState_transitions(const PnsState* state) { PnsTransitionView view; view.count = state->fire.active.count; view.transitions = state->fire.active.transitions; return view; } PnsTransitionView pnsState_transitions_backward(const PnsState* state) { PnsTransitionView view; view.count = state->unfire.active.count; view.transitions = state->unfire.active.transitions; return view; } void pnsState_cleanChanges(PnsState* state) { state->fire.added.count = 0; pnsClearIndexList(&state->fire.added.transitions); state->fire.removed.count = 0; pnsClearIndexList(&state->fire.removed.transitions); } void pnsState_cleanChanges_backward(PnsState* state) { state->unfire.added.count = 0; pnsClearIndexList(&state->unfire.added.transitions); state->unfire.removed.count = 0; pnsClearIndexList(&state->unfire.removed.transitions); } static PnsFireChanges pnsFireState_changedTransitions(PnsFireState* fire) { PnsFireChanges result; result.added.count = fire->added.count; result.added.transitions = fire->added.transitions; result.removed.count = fire->removed.count; result.removed.transitions = fire->removed.transitions; fire->added.count = 0; fire->added.transitions = NULL; fire->removed.count = 0; fire->removed.transitions = NULL; return result; } PnsFireChanges pnsState_changedTransitions(PnsState* state) { return pnsFireState_changedTransitions(&state->fire); } PnsFireChanges pnsState_changedTransitions_backward(PnsState* state) { return pnsFireState_changedTransitions(&state->unfire); } static void pnsState_fireTimes(PnsState* state, const PnsNet* net, size_t tid, size_t times) { state->calls.counts[tid] += times; PnsNode* transition = &net->transitions.nodes[tid]; for (size_t pi = 0; pi < transition->prev.count; ++pi) { state->tokens.counts[transition->prev.indices[pi]] -= times; } for (size_t pi = 0; pi < transition->next.count; ++pi) { state->tokens.counts[transition->next.indices[pi]] += times; } PnsIndexList* recalculate_indices_forward = NULL; PnsIndexList* recalculate_indices_backward = NULL; recalculate_transition_backward(state, net, tid); for (size_t pi = 0; pi < transition->prev.count; ++pi) { size_t pid = transition->prev.indices[pi]; PnsNode* place = &net->places.nodes[pid]; for (size_t ti = 0; ti < place->next.count; ++ti) { pnsIndexList_appendNew(&recalculate_indices_forward, place->next.indices[ti]); } for (size_t ti = 0; ti < place->prev.count; ++ti) { pnsIndexList_appendNew(&recalculate_indices_backward, place->prev.indices[ti]); } } for (size_t pi = 0; pi < transition->next.count; ++pi) { size_t pid = transition->next.indices[pi]; PnsNode* place = &net->places.nodes[pid]; for (size_t ti = 0; ti < place->next.count; ++ti) { pnsIndexList_appendNew(&recalculate_indices_forward, place->next.indices[ti]); } for (size_t ti = 0; ti < place->prev.count; ++ti) { pnsIndexList_appendNew(&recalculate_indices_backward, place->prev.indices[ti]); } } while (recalculate_indices_forward) { PnsIndexList* current = recalculate_indices_forward; recalculate_transition_forward(state, net, current->index); recalculate_indices_forward = recalculate_indices_forward->next; free(current); } while (recalculate_indices_backward) { PnsIndexList* current = recalculate_indices_backward; recalculate_transition_backward(state, net, current->index); recalculate_indices_backward = recalculate_indices_backward->next; free(current); } } void pnsState_fire(PnsState* state, const PnsNet* net, size_t tid) { pnsState_fireTimes(state, net, tid, 1); } void pnsState_fire_backward(PnsState* state, const PnsNet* net, size_t tid) { pnsState_fireTimes(state, net, tid, -1); } void pnsState_refresh(PnsState* state, const PnsNet* net) { if (state->tokens.size < net->places.count) RESIZE_ARRAY(net->places.count, state->tokens.size, state->tokens.counts) size_t new_transitions_start = state->calls.size; if (state->calls.size < net->transitions.count) { RESIZE_ARRAY(net->transitions.count, state->calls.size, state->calls.counts) for (size_t tid = new_transitions_start; tid < state->calls.size; ++tid) state->calls.counts[tid] = 0; } for (size_t pid = 0; pid < net->places.count; ++pid) { size_t count = 0; PnsNode* place = &net->places.nodes[pid]; for (size_t ti = 0; ti < place->prev.count; ++ti) { size_t tid = place->prev.indices[ti]; count += state->calls.counts[tid]; } for (size_t ti = 0; ti < place->next.count; ++ti) { size_t tid = place->next.indices[ti]; count -= state->calls.counts[tid]; } state->tokens.counts[pid] = count; } for (size_t tid = 0; tid < net->transitions.count; ++tid) { recalculate_transition_forward(state, net, tid); recalculate_transition_backward(state, net, tid); } } /** Transition View **/ bool pnsTransitionView_next(PnsTransitionView* view, size_t* tid) { if (view->count == 0) return false; --view->count; *tid = view->transitions->index; view->transitions = view->transitions->next; return true; } /** Transition List **/ void pnsDestroyTransitionList(PnsTransitionList* list) { pnsDestroyIndexList(list->transitions); } bool pnsTransitionList_next(PnsTransitionList* list, size_t* tid) { if (list->count == 0) return false; --list->count; *tid = list->transitions->index; PnsIndexList* current = list->transitions; list->transitions = list->transitions->next; free(current); return true; }