LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
setReward.m
1function self = setReward(self, name, rewardFn)
2% SETREWARD Define a reward function on the network for CTMC analysis
3%
4% SELF = SETREWARD(SELF, NAME, REWARDFN)
5%
6% NAME - String identifier for the reward
7% REWARDFN - Function handle with signature:
8% @(state) -> double (recommended - new API)
9% @(state, sn) -> double (backward compatible)
10%
11% state: RewardState object providing intuitive state access:
12% - state.at(node) - Jobs at node (all classes)
13% - state.at(node, class) - Jobs at node for specific class
14% - state.forClass(class) - Jobs of class (all nodes)
15%
16% RewardState also supports aggregation via RewardStateView:
17% - state.at(node).total() - Sum jobs across classes at node
18% - state.at(node).max() - Max jobs across classes at node
19% - state.at(node).min() - Min jobs across classes at node
20% - state.at(node).count() - Count non-zero entries
21%
22% sn: NetworkStruct (optional, for advanced users to access
23% rates, capacities, etc.)
24%
25% Multiple rewards can be defined by calling setReward multiple times
26% with different names. Use clearRewards() to remove all rewards.
27%
28% Recommended: Use Reward templates for common metrics
29% Reward.queueLength(node, [class])
30% Reward.utilization(node, [class])
31% Reward.blocking(node)
32%
33% Examples (New API - Recommended):
34% % Basic: reference nodes and classes directly
35% model.setReward('QLen_Q1_C1', @(state) state.at(queue1, class1));
36%
37% % Aggregation: sum across classes
38% model.setReward('TotalJobs_Q1', @(state) state.at(queue1).total());
39%
40% % Aggregation: sum across stations
41% model.setReward('ClassTotal_C1', @(state) state.forClass(class1).total());
42%
43% % Using templates
44% model.setReward('Util_Q1', Reward.utilization(queue1));
45% model.setReward('Block_Q1', Reward.blocking(queue1));
46%
47% % Custom composite rewards
48% model.setReward('Cost', @(state) ...
49% 2.0 * state.at(queue1).total() + ...
50% 5.0 * state.at(queue2).total());
51%
52% % Advanced: using NetworkStruct parameter (for power-users)
53% model.setReward('AdvancedMetric', @(state, sn) ...
54% state.at(queue1, class1) * sn.rates(sn.nodeToStation(queue1.index), 1));
55%
56% See also: RewardState, RewardStateView, Reward, getAvgReward
57%
58% Copyright (c) 2012-2026, Imperial College London
59% All rights reserved.
60
61if ~ischar(name) && ~isstring(name)
62 error('Reward name must be a string');
63end
64if ~isa(rewardFn, 'function_handle') && ~isa(rewardFn, 'RewardDescriptor')
65 error('Reward function must be a function handle @(state, sn) -> double, or a RewardDescriptor returned by a Reward.* template');
66end
67
68% A RewardDescriptor is callable exactly like a bare handle, but additionally
69% records what the reward measures ({kind, node, class}). Keep the descriptor so
70% that linemodel_save can serialize the reward declaratively; a bare handle
71% carries no such information and is stored as-is.
72if isa(rewardFn, 'RewardDescriptor')
73 descriptor = rewardFn;
74else
75 descriptor = [];
76end
77
78% Initialize reward cell array if needed
79if isempty(self.sn)
80 self.sn = NetworkStruct();
81end
82if ~isfield(self.sn, 'reward') || isempty(self.sn.reward)
83 self.sn.reward = {};
84end
85
86% Check if reward with this name already exists and update it
87name = char(name);
88found = false;
89for i = 1:length(self.sn.reward)
90 if strcmp(self.sn.reward{i}.name, name)
91 self.sn.reward{i}.fn = rewardFn;
92 self.sn.reward{i}.descriptor = descriptor;
93 found = true;
94 break;
95 end
96end
97
98% Add new reward if not found
99if ~found
100 reward.name = name;
101 reward.fn = rewardFn;
102 reward.type = 'state';
103 reward.descriptor = descriptor;
104 self.sn.reward{end+1} = reward;
105end
106
107end
Definition fjtag.m:157
Definition Station.m:245