1function [enabled_next_states,enabled_rates,enabled_sync,gctr_start,depRatesSamples,arvRatesSamples,outprob_a,outprob_p,rate_a,eventCache] = solver_ssa_findenabled(sn,node_a,enabled_next_states,cur_state,outprob_a,event_a,class_a,isSimulation,node_p,local,outprob_p,event_p,class_p,sync,gsync,depRatesSamples,samples_collected,arvRatesSamples,last_node_a,last_node_p,eventCache)
2enabled_sync = []; % row
is action label, col1=rate, col2=
new state
8 isf_a = sn.nodeToStateful(node_a{act});
10 % isf_p = sn.nodeToStateful(node_p{act});
11 % %update_cond_a =
true;
12 % %enabled_next_states{act} = cur_state;
13 %
if isempty(enabled_next_states{act}) || ...
14 % isempty(enabled_next_states{act}{isf_a})|| ...
15 % isempty(enabled_next_states{act}{isf_p}) || ...
16 % length(cur_state) < max(isf_a,isf_p)
17 % % no data or a lot has changed
18 % enabled_next_states{act} = cur_state;
19 % update_cond_a =
true;
20 % elseif sn.nodetype(node_p{act}) == NodeType.Cache
21 % enabled_next_states{act} = cur_state;
22 % update_cond_a =
true;
23 % elseif (isf_a == isf_p) || (length(cur_state{isf_a}) == length(cur_state_1{isf_a}) && ...
24 % length(cur_state{isf_p}) == length(cur_state_1{isf_p}) && ...
25 % all(cur_state{isf_a}==cur_state_1{isf_a}) && ...
26 % all(cur_state{isf_p}==cur_state_1{isf_p}))
27 % % active
is unchanged
28 % enabled_next_states{act}{isf_p} = cur_state{isf_p};
29 % update_cond_a =
false;
31 % enabled_next_states{act} = cur_state;
32 % update_cond_a =
true;
35 % enabled_next_states{act} = cur_state;
36 % update_cond_a =
true;
38 enabled_next_states{act} = cur_state;
41 [enabled_next_states{act}{isf_a}, rate_a{act}, outprob_a{act}, eventCache] = State.afterEvent(sn, node_a{act}, cur_state{isf_a}, event_a{act}, class_a{act}, isSimulation, eventCache);
44 if isempty(enabled_next_states{act}{isf_a}) || isempty(rate_a{act})
48 for ia=1:size(enabled_next_states{act}{isf_a},1) %
for all possible
new states, check
if they are enabled
49 %
if the transition cannot occur
50 if isnan(rate_a{act}(ia)) || rate_a{act}(ia) == 0 % handles degenerate rate values
51 % set the transition with a zero rate so that it
is
53 rate_a{act}(ia) = 1e-38; % ~ zero in 32-bit precision
56 if enabled_next_states{act}{isf_a}(ia,:) == -1 % hash not found
59 update_cond_p =
true; %samples_collected == 1 || ((node_p{act} == last_node_a || node_p{act} == last_node_p)) || isempty(outprob_a{act}) || isempty(outprob_p{act});
62 if node_p{act} ~= local
63 if node_p{act} == node_a{act} %self-loop, active and passive are the same
66 [enabled_next_states{act}{isf_p}, ~, outprob_p{act}, eventCache] = State.afterEvent(sn, node_p{act}, enabled_next_states{act}{isf_p}, event_p{act}, class_p{act}, isSimulation, eventCache);
69 isf_p = sn.nodeToStateful(node_p{act});
71 [enabled_next_states{act}{isf_p}, ~, outprob_p{act}, eventCache] = State.afterEvent(sn, node_p{act}, enabled_next_states{act}{isf_p}, event_p{act}, class_p{act}, isSimulation, eventCache);
74 if ~isempty(enabled_next_states{act}{isf_p})
75 if sn.isstatedep(node_a{act},3)
76 prob_sync_p{act} = sync{act}.passive{1}.prob(cur_state, enabled_next_states{act}); %state-dependent
78 prob_sync_p{act} = sync{act}.passive{1}.prob;
84 if ~isempty(enabled_next_states{act}{isf_a})
85 if node_p{act} == local
88 if ~isnan(rate_a{act})
89 if all(~cellfun(@isempty,enabled_next_states{act}))
90 if event_a{act} == EventType.DEP
91 node_a_sf{act} = isf_a;
92 node_p_sf{act} = isf_p;
93 depRatesSamples(samples_collected,node_a_sf{act},class_a{act}) = depRatesSamples(samples_collected,node_a_sf{act},class_a{act}) + outprob_a{act} * outprob_p{act} * rate_a{act}(ia) * prob_sync_p{act};
94 arvRatesSamples(samples_collected,node_p_sf{act},class_p{act}) = arvRatesSamples(samples_collected,node_p_sf{act},class_p{act}) + outprob_a{act} * outprob_p{act} * rate_a{act}(ia) * prob_sync_p{act};
96 % simulate also self-loops as we need to log them
97 %
if any(~cellfun(@isequal,new_state{act},cur_state))
98 if node_p{act} < local && ~sn.csmask(class_a{act}, class_p{act}) && sn.nodetype(node_p{act})~=NodeType.Source && (rate_a{act}(ia) * prob_sync_p{act} >0)
99 line_error(mfilename,sprintf(
'Error: state-dependent routing at node %d (%s) violates the class switching mask (node %d -> node %d, class %d -> class %d).', node_a{act}, sn.nodenames{node_a{act}}, node_a{act}, node_p{act}, class_a{act}, class_p{act}));
101 enabled_rates(ctr) = rate_a{act}(ia) * prob_sync_p{act};
102 enabled_sync(ctr) = act;
112for gact=1:G %
event at node ind with global side-effects
113 gind = gsync{gact}.active{1}.node; % get the active node (transition) from the gsync
event
114 [enabled_next_states{A+gact}, outrate, outprob] = State.afterGlobalEvent(sn, gind, cur_state, gsync{gact}, isSimulation);
115 for ia=find(outrate .* outprob)
116 enabled_rates(ctr) = outrate(ia) * outprob(ia);
117 enabled_sync(ctr) = A+gact;