function petriNetGuiDemo2 %PETRINETGUIDEMO Parallel-task Petri net tutorial GUI. % One job splits into two parallel tasks (A and B) and then joins again. % Run: % petriNetGuiDemo2 places = ["Ready", "TaskA", "TaskB", "ADone", "BDone", "Done"]; transitions = ["Split", "FinishA", "FinishB", "Join"]; % pre(:,j) = tokens consumed by transition j pre = [1 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 0 1; 0 0 0 1; 0 0 0 0]; % post(:,j) = tokens produced by transition j post = [0 0 0 0; 1 0 0 0; 1 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 0 1]; initialMarking = [1; 0; 0; 0; 0; 0]; marking = initialMarking; stepCount = 0; maxSteps = 30; placePos = [1.2 0.0; 5.2 1.4; 5.2 -1.4; 9.2 1.4; 9.2 -1.4; 13.2 0.0]; transPos = [3.2 0.0; 7.2 1.4; 7.2 -1.4; 11.2 0.0]; placeR = 0.75; transW = 0.55; transH = 1.45; fig = figure( ... 'Name', 'Parallel Petri Net Tutorial', ... 'Color', 'w', ... 'MenuBar', 'none', ... 'ToolBar', 'none', ... 'NumberTitle', 'off', ... 'Position', [100 100 1240 700]); ax = axes('Parent', fig, 'Position', [0.04 0.20 0.92 0.74]); hold(ax, 'on'); axis(ax, [-0.5 14.2 -2.8 2.8]); axis(ax, 'equal'); axis(ax, 'off'); statusText = uicontrol( ... 'Style', 'text', ... 'Parent', fig, ... 'Units', 'normalized', ... 'Position', [0.04 0.04 0.92 0.08], ... 'BackgroundColor', 'w', ... 'HorizontalAlignment', 'left', ... 'FontSize', 11, ... 'String', ''); btnStep = uicontrol(fig, 'Style', 'pushbutton', 'Units', 'normalized', ... 'Position', [0.04 0.11 0.08 0.05], 'String', 'Step', ... 'FontSize', 10, 'Callback', @onStep); btnSplit = uicontrol(fig, 'Style', 'pushbutton', 'Units', 'normalized', ... 'Position', [0.14 0.11 0.10 0.05], 'String', 'Split', ... 'FontSize', 10, 'Callback', @(~,~) fireTransition(1, true)); btnFinishA = uicontrol(fig, 'Style', 'pushbutton', 'Units', 'normalized', ... 'Position', [0.26 0.11 0.10 0.05], 'String', 'Finish A', ... 'FontSize', 10, 'Callback', @(~,~) fireTransition(2, true)); btnFinishB = uicontrol(fig, 'Style', 'pushbutton', 'Units', 'normalized', ... 'Position', [0.38 0.11 0.10 0.05], 'String', 'Finish B', ... 'FontSize', 10, 'Callback', @(~,~) fireTransition(3, true)); btnJoin = uicontrol(fig, 'Style', 'pushbutton', 'Units', 'normalized', ... 'Position', [0.50 0.11 0.10 0.05], 'String', 'Join', ... 'FontSize', 10, 'Callback', @(~,~) fireTransition(4, true)); btnRun = uicontrol(fig, 'Style', 'pushbutton', 'Units', 'normalized', ... 'Position', [0.62 0.11 0.08 0.05], 'String', 'Run', ... 'FontSize', 10, 'Callback', @onRun); btnReset = uicontrol(fig, 'Style', 'pushbutton', 'Units', 'normalized', ... 'Position', [0.72 0.11 0.08 0.05], 'String', 'Reset', ... 'FontSize', 10, 'Callback', @onReset); transitionPatch = gobjects(numel(transitions), 1); countText = gobjects(numel(places), 1); drawStaticNet(); renderTokens(); updateUI(); function drawStaticNet % Arcs line(ax, [placePos(1,1) + placeR, transPos(1,1) - transW/2], ... [0, 0], 'Color', [0 0 0], 'LineWidth', 1.4); line(ax, [transPos(1,1) + transW/2, placePos(2,1) - placeR], ... [0, placePos(2,2)], 'Color', [0 0 0], 'LineWidth', 1.4); line(ax, [transPos(1,1) + transW/2, placePos(3,1) - placeR], ... [0, placePos(3,2)], 'Color', [0 0 0], 'LineWidth', 1.4); line(ax, [placePos(2,1) + placeR, transPos(2,1) - transW/2], ... [placePos(2,2), transPos(2,2)], 'Color', [0 0 0], 'LineWidth', 1.4); line(ax, [transPos(2,1) + transW/2, placePos(4,1) - placeR], ... [transPos(2,2), placePos(4,2)], 'Color', [0 0 0], 'LineWidth', 1.4); line(ax, [placePos(3,1) + placeR, transPos(3,1) - transW/2], ... [placePos(3,2), transPos(3,2)], 'Color', [0 0 0], 'LineWidth', 1.4); line(ax, [transPos(3,1) + transW/2, placePos(5,1) - placeR], ... [transPos(3,2), placePos(5,2)], 'Color', [0 0 0], 'LineWidth', 1.4); line(ax, [placePos(4,1) + placeR, transPos(4,1) - transW/2], ... [placePos(4,2), transPos(4,2)], 'Color', [0 0 0], 'LineWidth', 1.4); line(ax, [placePos(5,1) + placeR, transPos(4,1) - transW/2], ... [placePos(5,2), transPos(4,2)], 'Color', [0 0 0], 'LineWidth', 1.4); line(ax, [transPos(4,1) + transW/2, placePos(6,1) - placeR], ... [transPos(4,2), placePos(6,2)], 'Color', [0 0 0], 'LineWidth', 1.4); % Places for i = 1:numel(places) rectangle(ax, ... 'Position', [placePos(i,1) - placeR, placePos(i,2) - placeR, 2*placeR, 2*placeR], ... 'Curvature', [1 1], ... 'EdgeColor', 'k', ... 'LineWidth', 2, ... 'FaceColor', 'w'); text(ax, placePos(i,1), placePos(i,2) - 1.20, places(i), ... 'HorizontalAlignment', 'center', ... 'FontSize', 11, ... 'FontWeight', 'bold'); countText(i) = text(ax, placePos(i,1), placePos(i,2) + 1.20, '', ... 'HorizontalAlignment', 'center', ... 'FontSize', 10, ... 'FontWeight', 'bold'); end % Transitions for i = 1:numel(transitions) transitionPatch(i) = rectangle(ax, ... 'Position', [transPos(i,1) - transW/2, transPos(i,2) - transH/2, transW, transH], ... 'EdgeColor', 'k', ... 'LineWidth', 2, ... 'FaceColor', [0.85 0.85 0.85]); text(ax, transPos(i,1), transPos(i,2) - 1.20, transitions(i), ... 'HorizontalAlignment', 'center', ... 'FontSize', 11, ... 'FontWeight', 'bold'); end text(ax, 7.0, 2.35, 'Parallel Petri Net Tutorial', ... 'HorizontalAlignment', 'center', ... 'FontSize', 14, ... 'FontWeight', 'bold'); end function renderTokens delete(findobj(ax, 'Tag', 'token')); for p = 1:numel(places) pts = tokenLayout(placePos(p,:), marking(p)); for k = 1:size(pts, 1) plot(ax, pts(k,1), pts(k,2), 'ko', ... 'MarkerFaceColor', 'k', ... 'MarkerSize', 8, ... 'Tag', 'token'); end end end function pts = tokenLayout(center, count) if count <= 0 pts = zeros(0, 2); elseif count == 1 pts = center; else r = 0.23; ang = linspace(0, 2*pi, count + 1); ang(end) = []; pts = center + [r*cos(ang(:)), r*sin(ang(:))]; end end function updateUI enabled = all(marking >= pre, 1); enabledNames = transitions(enabled); if isempty(enabledNames) enabledText = "none"; else enabledText = strjoin(enabledNames, ", "); end for i = 1:numel(places) set(countText(i), 'String', sprintf('Tokens: %d', marking(i))); end set(btnSplit, 'Enable', onOff(enabled(1))); set(btnFinishA, 'Enable', onOff(enabled(2))); set(btnFinishB, 'Enable', onOff(enabled(3))); set(btnJoin, 'Enable', onOff(enabled(4))); msg = sprintf([ ... 'Step: %d/%d ', ... 'Ready=%d TaskA=%d TaskB=%d ADone=%d BDone=%d Done=%d ', ... 'Enabled: %s'], ... stepCount, maxSteps, ... marking(1), marking(2), marking(3), marking(4), marking(5), marking(6), ... enabledText); set(statusText, 'String', msg); for i = 1:numel(transitions) if enabled(i) set(transitionPatch(i), 'FaceColor', [0.75 0.93 0.75]); else set(transitionPatch(i), 'FaceColor', [0.85 0.85 0.85]); end end end function idx = pickTransition enabled = all(marking >= pre, 1); idx = find(enabled, 1, 'first'); if isempty(idx) idx = 0; end end function onStep(~, ~) idx = pickTransition(); if idx == 0 updateUI(); return end fireTransition(idx, true); end function onRun(~, ~) while stepCount < maxSteps && isvalid(fig) idx = pickTransition(); if idx == 0 break end fireTransition(idx, true); pause(0.45); end end function onReset(~, ~) marking = initialMarking; stepCount = 0; renderTokens(); updateUI(); end function fireTransition(tIdx, animateFlag) enabled = all(marking >= pre, 1); if ~enabled(tIdx) updateUI(); return end inPlaces = find(pre(:, tIdx) > 0); outPlaces = find(post(:, tIdx) > 0); if animateFlag animateTransition(tIdx, inPlaces, outPlaces); end marking = marking - pre(:, tIdx) + post(:, tIdx); stepCount = stepCount + 1; renderTokens(); updateUI(); end function animateTransition(tIdx, inPlaces, outPlaces) if isempty(inPlaces) || isempty(outPlaces) return end set(transitionPatch(tIdx), 'FaceColor', [0.98 0.85 0.55]); drawnow; nAnim = max(numel(inPlaces), numel(outPlaces)); srcIdx = expandIndices(inPlaces, nAnim); dstIdx = expandIndices(outPlaces, nAnim); tokenH = gobjects(nAnim, 1); for i = 1:nAnim tokenH(i) = plot(ax, placePos(srcIdx(i),1), placePos(srcIdx(i),2), 'o', ... 'MarkerFaceColor', [0.90 0.20 0.20], ... 'MarkerEdgeColor', 'k', ... 'MarkerSize', 10, ... 'Tag', 'token'); end nFrames = 24; for s = 1:nFrames alpha = s / nFrames; for i = 1:nAnim x0 = placePos(srcIdx(i),1); y0 = placePos(srcIdx(i),2); x1 = placePos(dstIdx(i),1); y1 = placePos(dstIdx(i),2); x = (1 - alpha) * x0 + alpha * x1; y = (1 - alpha) * y0 + alpha * y1; set(tokenH(i), 'XData', x, 'YData', y); end drawnow; pause(0.02); end delete(tokenH); set(transitionPatch(tIdx), 'FaceColor', [0.75 0.93 0.75]); end function idx = expandIndices(idx0, n) idx0 = idx0(:); if isempty(idx0) idx = ones(n, 1); return end if numel(idx0) >= n idx = idx0(1:n); return end idx = zeros(n, 1); idx(1:numel(idx0)) = idx0; idx(numel(idx0)+1:end) = idx0(end); end function s = onOff(tf) if tf s = 'on'; else s = 'off'; end end end