1classdef RewardState < handle
2 % REWARDSTATE Smart state accessor
for reward functions
4 % Provides intuitive access to aggregated state populations at specific
5 % stations and job
classes, with support
for aggregation operations.
8 % % Access specific station/
class population (returns scalar)
9 % pop = state.at(queue1, class1);
11 % % Access all
classes at a station (returns RewardStateView)
12 % view = state.at(queue1);
13 % total = view.total(); % Sum across
classes
15 % % Access
class across all stations (returns RewardStateView)
16 % view = state.forClass(class1);
17 % total = view.total(); % Sum across stations
19 % See also: RewardStateView, Reward, setReward
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
31 function self = RewardState(stateVec, sn, nodesToStation, classesToIdx)
32 % REWARDSTATE Constructor
34 % SELF = REWARDSTATE(STATEVEC, SN, NODESTOSTATION, CLASSESTOIDX)
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
41 self.stateVector = stateVec;
43 self.nclasses = sn.nclasses;
44 self.nstations = sn.nstations;
45 self.nodeToStationMap = nodesToStation;
46 self.classToIndexMap = classesToIdx;
49 function result = at(self, node,
jobclass)
50 % AT Access population at station or station+class
52 % RESULT = AT(SELF, NODE) returns RewardStateView for all
classes
53 % at the station containing NODE
55 % RESULT = AT(SELF, NODE, JOBCLASS) returns scalar population count
56 % of JOBCLASS at the station containing NODE
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
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;
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);
75 subvector = self.stateVector(startIdx:endIdx);
76 result = RewardStateView(subvector, self, stationIdx, []);
78 % Return scalar for specific station/class
80 error('RewardState:InvalidArgument', ...
81 'Second argument must be a JobClass
object');
84 stationIdx = self.nodeToStationMap(node.index);
85 classIdx = self.classToIndexMap(
jobclass.index);
87 if classIdx < 1 || classIdx > self.nclasses
88 error('RewardState:InvalidClass', ...
89 'Invalid class index %d for %s', classIdx,
jobclass.name);
92 idx = (stationIdx - 1) * self.nclasses + classIdx;
94 if idx < 1 || idx > length(self.stateVector)
95 error('RewardState:InvalidIndex', ...
96 'Invalid state index %d for station %d, class %s', ...
100 result = self.stateVector(idx);
102 error('RewardState:InvalidNumberOfArguments', ...
103 'at() takes 2 or 3 arguments (self, node, [
jobclass])');
107 function result = forClass(self,
jobclass)
108 % FORCLASS Get populations for class across all stations
110 % RESULT = FORCLASS(SELF, JOBCLASS) returns RewardStateView
111 % showing population of JOBCLASS at each station
114 % view = state.forClass(class1);
115 % total = view.total(); % Total class1 jobs in system
116 % view.atStation(queue1); % Class1 population at queue1
119 error('RewardState:InvalidArgument', ...
120 'Argument must be a JobClass
object');
123 classIdx = self.classToIndexMap(
jobclass.index);
125 if classIdx < 1 || classIdx > self.nclasses
126 error('RewardState:InvalidClass', ...
127 'Invalid class index %d for %s', classIdx,
jobclass.name);
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);
136 result = RewardStateView(values, self, [], classIdx);
139 function result = forStation(self, station)
140 % FORSTATION Alias for at(station)
142 % RESULT = FORSTATION(SELF, STATION)
is equivalent to AT(SELF, STATION)
144 % Provided for semantic clarity when accessing all
classes at a station
146 result = self.at(station);
149 function sn = get_sn(self)
150 % GET_SN Return NetworkStruct (for advanced usage)
152 % SN = GET_SN(SELF) returns the NetworkStruct, allowing advanced
153 % users to access rates, capacities, and other parameters.
155 % Example (advanced):
156 % model.setReward('Advanced', @(state, sn) ...
157 % state.at(queue1) * sn.rates(sn.nodeToStation(queue1.index), 1));
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, '.')
170 varargout{1} = self.get_sn();
173 varargout{1} = builtin(
'subsref', self, s);
176 varargout{1} = builtin(
'subsref', self, s);