LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
RewardState.m
1classdef RewardState < handle
2 % REWARDSTATE Smart state accessor for reward functions
3 %
4 % Provides intuitive access to aggregated state populations at specific
5 % stations and job classes, with support for aggregation operations.
6 %
7 % Usage:
8 % % Access specific station/class population (returns scalar)
9 % pop = state.at(queue1, class1);
10 %
11 % % Access all classes at a station (returns RewardStateView)
12 % view = state.at(queue1);
13 % total = view.total(); % Sum across classes
14 %
15 % % Access class across all stations (returns RewardStateView)
16 % view = state.forClass(class1);
17 % total = view.total(); % Sum across stations
18 %
19 % See also: RewardStateView, Reward, setReward
20
21 properties (Access = private)
22 stateVector % Row vector: aggregated state [1 x (M*K)]
23 sn % NetworkStruct reference
24 nclasses % Number of job classes
25 nstations % Number of stations
26 nodeToStationMap % containers.Map: node.index -> station index
27 classToIndexMap % containers.Map: jobclass.index -> class index
28 end
29
30 methods
31 function self = RewardState(stateVec, sn, nodesToStation, classesToIdx)
32 % REWARDSTATE Constructor
33 %
34 % SELF = REWARDSTATE(STATEVEC, SN, NODESTOSTATION, CLASSESTOIDX)
35 %
36 % STATEVEC - Row vector of aggregated state [1 x (M*K)]
37 % SN - NetworkStruct with model information
38 % NODESTOSTATION - containers.Map: node.index -> station index
39 % CLASSESTOIDX - containers.Map: jobclass.index -> class index
40
41 self.stateVector = stateVec;
42 self.sn = sn;
43 self.nclasses = sn.nclasses;
44 self.nstations = sn.nstations;
45 self.nodeToStationMap = nodesToStation;
46 self.classToIndexMap = classesToIdx;
47 end
48
49 function result = at(self, node, jobclass)
50 % AT Access population at station or station+class
51 %
52 % RESULT = AT(SELF, NODE) returns RewardStateView for all classes
53 % at the station containing NODE
54 %
55 % RESULT = AT(SELF, NODE, JOBCLASS) returns scalar population count
56 % of JOBCLASS at the station containing NODE
57 %
58 % Examples:
59 % view = state.at(queue1); % All classes at queue1
60 % pop = state.at(queue1, class1); % Class1 jobs at queue1
61 % total = state.at(queue1).total(); % Total jobs at queue1
62
63 if nargin == 2
64 % Return view for all classes at this station
65 stationIdx = self.nodeToStationMap(node.index);
66 startIdx = (stationIdx - 1) * self.nclasses + 1;
67 endIdx = stationIdx * self.nclasses;
68
69 if startIdx < 1 || endIdx > length(self.stateVector)
70 error('RewardState:InvalidIndex', ...
71 'Invalid state indices for station %d: [%d:%d]', ...
72 stationIdx, startIdx, endIdx);
73 end
74
75 subvector = self.stateVector(startIdx:endIdx);
76 result = RewardStateView(subvector, self, stationIdx, []);
77 elseif nargin == 3
78 % Return scalar for specific station/class
79 if ~isa(jobclass, 'JobClass')
80 error('RewardState:InvalidArgument', ...
81 'Second argument must be a JobClass object');
82 end
83
84 stationIdx = self.nodeToStationMap(node.index);
85 classIdx = self.classToIndexMap(jobclass.index);
86
87 if classIdx < 1 || classIdx > self.nclasses
88 error('RewardState:InvalidClass', ...
89 'Invalid class index %d for %s', classIdx, jobclass.name);
90 end
91
92 idx = (stationIdx - 1) * self.nclasses + classIdx;
93
94 if idx < 1 || idx > length(self.stateVector)
95 error('RewardState:InvalidIndex', ...
96 'Invalid state index %d for station %d, class %s', ...
97 idx, stationIdx, jobclass.name);
98 end
99
100 result = self.stateVector(idx);
101 else
102 error('RewardState:InvalidNumberOfArguments', ...
103 'at() takes 2 or 3 arguments (self, node, [jobclass])');
104 end
105 end
106
107 function result = forClass(self, jobclass)
108 % FORCLASS Get populations for class across all stations
109 %
110 % RESULT = FORCLASS(SELF, JOBCLASS) returns RewardStateView
111 % showing population of JOBCLASS at each station
112 %
113 % Example:
114 % view = state.forClass(class1);
115 % total = view.total(); % Total class1 jobs in system
116 % view.atStation(queue1); % Class1 population at queue1
117
118 if ~isa(jobclass, 'JobClass')
119 error('RewardState:InvalidArgument', ...
120 'Argument must be a JobClass object');
121 end
122
123 classIdx = self.classToIndexMap(jobclass.index);
124
125 if classIdx < 1 || classIdx > self.nclasses
126 error('RewardState:InvalidClass', ...
127 'Invalid class index %d for %s', classIdx, jobclass.name);
128 end
129
130 values = zeros(1, self.nstations);
131 for ist = 1:self.nstations
132 idx = (ist - 1) * self.nclasses + classIdx;
133 values(ist) = self.stateVector(idx);
134 end
135
136 result = RewardStateView(values, self, [], classIdx);
137 end
138
139 function result = forStation(self, station)
140 % FORSTATION Alias for at(station)
141 %
142 % RESULT = FORSTATION(SELF, STATION) is equivalent to AT(SELF, STATION)
143 %
144 % Provided for semantic clarity when accessing all classes at a station
145
146 result = self.at(station);
147 end
148
149 function sn = get_sn(self)
150 % GET_SN Return NetworkStruct (for advanced usage)
151 %
152 % SN = GET_SN(SELF) returns the NetworkStruct, allowing advanced
153 % users to access rates, capacities, and other parameters.
154 %
155 % Example (advanced):
156 % model.setReward('Advanced', @(state, sn) ...
157 % state.at(queue1) * sn.rates(sn.nodeToStation(queue1.index), 1));
158
159 sn = self.sn;
160 end
161 end
162
163 methods
164 % Property getter for backward compatibility with @(state, sn) syntax
165 function varargout = subsref(self, s)
166 % Allow accessing sn property with dot notation
167 if strcmp(s(1).type, '.')
168 switch s(1).subs
169 case 'sn'
170 varargout{1} = self.get_sn();
171 otherwise
172 % Default behavior
173 varargout{1} = builtin('subsref', self, s);
174 end
175 else
176 varargout{1} = builtin('subsref', self, s);
177 end
178 end
179 end
180end