-
Notifications
You must be signed in to change notification settings - Fork 3
[Model] NonLivenessFreePetriNet #921
Description
Motivation
NON-LIVENESS OF FREE CHOICE PETRI NETS (GJ A12 MS3). A fundamental NP-complete problem in concurrency theory: given a free-choice Petri net, determine whether it is not live (i.e., whether some transition can never fire again from some reachable marking). Even the well-structured class of free-choice nets has intractable liveness analysis. NP membership (the harder direction) was established by Hack (1972). The NP-completeness applies to general (not necessarily bounded) free-choice nets; bounded free-choice nets have polynomial-time liveness checking (Desel & Esparza, 1995).
Associated reduction rules:
- [Rule] 3SAT to NON-LIVENESS OF FREE CHOICE PETRI NETS #920: 3SAT → NonLivenessFreePetriNet (GJ reference reduction, Jones, Landweber, Lien 1977)
Definition
Name: NonLivenessFreePetriNet
Canonical name: Non-Liveness of Free Choice Petri Nets
Reference: Garey & Johnson, Computers and Intractability, A12 MS3
Mathematical definition:
INSTANCE: A Petri net P = (S, T, F, M₀) where S is a finite set of places, T is a finite set of transitions, F ⊆ (S × T) ∪ (T × S) is the flow relation, and M₀: S → ℕ is the initial marking. P must satisfy the free-choice property: for every place s ∈ S, if |s•| > 1 (s has multiple output transitions), then •t = {s} for every t ∈ s• (each such transition has s as its only input place).
QUESTION: Is P not live? That is, does there exist a transition t ∈ T and a marking M reachable from M₀ such that t can never fire again from M?
Variables
- Count: |T| variables (one per transition)
- Per-variable domain: {0, 1} — whether the transition is eventually dead (1) or always re-enableable (0) from the current reachable marking
- Meaning: The net is "not live" if there exists any reachable marking from which at least one transition can never fire again. The brute-force solver explores the reachability graph to determine whether such a dead transition exists.
Schema (data type)
Type name: NonLivenessFreePetriNet
Variants: none (no type parameters)
Value type: Or (feasibility: is the net not live?)
| Field | Type | Description |
|---|---|---|
num_places |
usize |
Number of places |S| |
num_transitions |
usize |
Number of transitions |T| |
place_to_transition |
Vec<(usize, usize)> |
Arcs from places to transitions: (place_index, transition_index) |
transition_to_place |
Vec<(usize, usize)> |
Arcs from transitions to places: (transition_index, place_index) |
initial_marking |
Vec<usize> |
Initial marking M₀: token count for each place (length = num_places) |
Getters (for overhead expressions):
num_places()→num_placesnum_transitions()→num_transitionsnum_arcs()→place_to_transition.len() + transition_to_place.len()initial_token_sum()→initial_marking.iter().sum()(total tokens in M₀)
Invariant: The net must satisfy the free-choice property: for every place s with |s•| > 1, every transition t ∈ s• has •t = {s}.
Complexity
- Decision complexity: NP-complete (Jones, Landweber, Lien 1977; NP membership by Hack 1972).
- Best known exact algorithm: Explore the reachability graph. The marking space is bounded by the total token count: if M₀ has N total tokens and there are |S| places, the reachable markings are bounded by C(N + |S| - 1, |S| - 1). For a net with N total tokens, this is at most (N+1)^|S|. For each reachable marking, check if any transition is permanently dead. Worst-case: O((N+1)^num_places × num_transitions).
declare_variants!complexity string:"(initial_token_sum + 1) ^ num_places * num_transitions"- Note: For bounded free-choice Petri nets, liveness is decidable in polynomial time via the Rank Theorem (Desel & Esparza, 1995).
Extra Remark
Full book text (GJ A12 MS3):
INSTANCE: Petri net P = (S, T, F, M₀) satisfying the free-choice property.
QUESTION: Is P not live?Reference: [Jones, Landweber, and Lien, 1977]. Transformation from 3-SATISFIABILITY.
Comment: The proof that this problem belongs to NP is nontrivial [Hack, 1972].
How to solve
- It can be solved by (existing) bruteforce. (Explore the reachability graph from M₀ by firing all enabled transitions. For each reachable marking, check if there exists a transition that can never be enabled again from that marking. If such a dead transition is found, the net is not live.)
- It can be solved by reducing to integer programming.
- Other: Structural analysis methods for free-choice nets (Rank Theorem, siphon/trap analysis) can solve bounded cases in polynomial time.
Example Instance
A small free-choice Petri net that is NOT live (answer: YES):
Places: s0, s1, s2 (3 places)
Transitions: t0, t1 (2 transitions)
Arcs place->transition: (s0, t0), (s1, t1)
Arcs transition->place: (t0, s1), (t0, s2), (t1, s0)
Initial marking: M₀ = [1, 0, 0] (one token in s0)
Free-choice property check: s0 has one output transition t0 (|s0•| = 1), s1 has one output transition t1 (|s1•| = 1), s2 has no output transitions (|s2•| = 0). The free-choice property holds trivially since no place has multiple output transitions.
Execution trace:
- M₀ = [1, 0, 0]. Only t0 is enabled (s0 has a token). Fire t0.
- M₁ = [0, 1, 1]. Only t1 is enabled (s1 has a token). Fire t1.
- M₂ = [1, 0, 1]. Only t0 is enabled. Fire t0.
- M₃ = [0, 1, 2]. Only t1 is enabled. Fire t1.
- M₄ = [1, 0, 2]. ...
The net cycles between states but tokens accumulate in s2 (a sink place). Both transitions remain fireable in this cycle, so this net appears live for t0 and t1. Let us try a net that is actually not live:
Corrected example — a net that is NOT live:
Places: s0, s1, s2, s3 (4 places)
Transitions: t0, t1, t2 (3 transitions)
Arcs place->transition: (s0, t0), (s1, t1), (s2, t2)
Arcs transition->place: (t0, s1), (t1, s2), (t2, s3)
Initial marking: M₀ = [1, 0, 0, 0]
Free-choice property check: Each place has at most one output transition, so the free-choice property holds trivially.
Execution trace:
- M₀ = [1, 0, 0, 0]. Only t0 is enabled. Fire t0.
- M₁ = [0, 1, 0, 0]. Only t1 is enabled. Fire t1.
- M₂ = [0, 0, 1, 0]. Only t2 is enabled. Fire t2.
- M₃ = [0, 0, 0, 1]. No transition is enabled — deadlock.
After reaching M₃, no transition can ever fire again. All transitions are dead. The net is not live. Answer: YES (Or(true)).
A net that IS live (answer: NO):
Places: s0, s1 (2 places)
Transitions: t0, t1 (2 transitions)
Arcs place->transition: (s0, t0), (s1, t1)
Arcs transition->place: (t0, s1), (t1, s0)
Initial marking: M₀ = [1, 0]
This is a simple cycle: t0 moves the token from s0 to s1, t1 moves it back. Both transitions can always fire again. The net is live. Answer: NO (Or(false)).
Validation
#!/usr/bin/env python3
"""Validate NonLivenessFreePetriNet examples by simulating reachability."""
def fire_transition(marking, pt_arcs, tp_arcs, t):
"""Fire transition t in the given marking. Returns new marking or None if not enabled."""
new_marking = list(marking)
# Check all input places have tokens and consume them
for (p, tr) in pt_arcs:
if tr == t:
if new_marking[p] <= 0:
return None
new_marking[p] -= 1
# Produce tokens in output places
for (tr, p) in tp_arcs:
if tr == t:
new_marking[p] += 1
return tuple(new_marking)
def is_not_live(num_places, num_transitions, pt_arcs, tp_arcs, initial_marking, max_markings=10000):
"""
Check if the Petri net is NOT live by exploring the reachability graph.
A net is not live if there exists a reachable marking from which some transition
can never fire again.
"""
from collections import deque
initial = tuple(initial_marking)
visited = {initial}
queue = deque([initial])
# Build full reachability graph
reachability = {} # marking -> set of successor markings
while queue and len(visited) < max_markings:
m = queue.popleft()
successors = set()
for t in range(num_transitions):
new_m = fire_transition(list(m), pt_arcs, tp_arcs, t)
if new_m is not None:
successors.add(new_m)
if new_m not in visited:
visited.add(new_m)
queue.append(new_m)
reachability[m] = successors
# For each reachable marking, check if some transition is dead from that marking
for m in visited:
for t in range(num_transitions):
# Check if t can ever fire from m (search reachable markings from m)
sub_visited = {m}
sub_queue = deque([m])
t_can_fire = False
while sub_queue and not t_can_fire:
current = sub_queue.popleft()
# Can t fire at current?
can_fire_here = True
for (p, tr) in pt_arcs:
if tr == t and current[p] <= 0:
can_fire_here = False
break
if can_fire_here:
t_can_fire = True
break
# Explore successors
if current in reachability:
for succ in reachability[current]:
if succ not in sub_visited:
sub_visited.add(succ)
sub_queue.append(succ)
if not t_can_fire:
return True # Found a dead transition from reachable marking m
return False
# Example 1: Not live (linear chain to deadlock)
print("=== Example 1: Linear chain (should be NOT live) ===")
result1 = is_not_live(
num_places=4,
num_transitions=3,
pt_arcs=[(0, 0), (1, 1), (2, 2)],
tp_arcs=[(0, 1), (1, 2), (2, 3)],
initial_marking=[1, 0, 0, 0],
)
print(f"Not live: {result1}")
assert result1 == True, f"Expected True, got {result1}"
# Example 2: Live (simple cycle)
print("\n=== Example 2: Simple cycle (should be live) ===")
result2 = is_not_live(
num_places=2,
num_transitions=2,
pt_arcs=[(0, 0), (1, 1)],
tp_arcs=[(0, 1), (1, 0)],
initial_marking=[1, 0],
)
print(f"Not live: {result2}")
assert result2 == False, f"Expected False, got {result2}"
# Verify free-choice property for both examples
def check_free_choice(num_places, pt_arcs):
"""Verify free-choice property: if |s•| > 1, then •t = {s} for all t in s•."""
# Build s• for each place
place_outputs = {}
for (p, t) in pt_arcs:
place_outputs.setdefault(p, set()).add(t)
# Build •t for each transition
trans_inputs = {}
for (p, t) in pt_arcs:
trans_inputs.setdefault(t, set()).add(p)
# Check property
for p, transitions in place_outputs.items():
if len(transitions) > 1:
for t in transitions:
if trans_inputs.get(t, set()) != {p}:
return False
return True
print("\n=== Free-choice property checks ===")
fc1 = check_free_choice(4, [(0, 0), (1, 1), (2, 2)])
print(f"Example 1 free-choice: {fc1}")
assert fc1 == True
fc2 = check_free_choice(2, [(0, 0), (1, 1)])
print(f"Example 2 free-choice: {fc2}")
assert fc2 == True
print("\nAll checks passed!")References
- [Jones, Landweber, and Lien, 1977]: N.D. Jones, L.H. Landweber, Y.E. Lien (1977). "Complexity of Some Problems in Petri Nets." Theoretical Computer Science, 4(3), pp. 277-299.
- [Hack, 1972]: M. Hack (1972). "Analysis of Production Schemata by Petri Nets." MIT Project MAC TR-94.
- [Desel and Esparza, 1995]: J. Desel and J. Esparza (1995). Free Choice Petri Nets. Cambridge University Press.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status