-
Notifications
You must be signed in to change notification settings - Fork 0
/
semoran.m
222 lines (208 loc) · 7.89 KB
/
semoran.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
% Copyright (c) 2022-2023 Corrado Puligheddu
function [s, x, z, total_value] = semoran(a,l,A,L,S,O,p,actions,min_s)
% SEMORAN computes the Semantic Flexible Edge Slicing Problem solution
% [s,x,z,total_value] = semoran(a,l,A,L,S,O,p,actions) solves the
% Semantic Flexible Edge Slicing Problem (SF-ESP).
%
% It takes as input:
% - a: a cell array of accuracy functions a_tau(z) that take as input
% the compression factor scalar z and return the corresponding accuracy,
% defined for each task
% - l: a cell array of latency functions l_tau(s,z) that take as input
% the resource allocation vector s and the compression factor scalar z,
% and return the corresponding end-to-end latency, defined for each task
% - A: an array of accuracy requirements that have to be satisfied by
% each task
% - L: an array of latency requirements that have to be satisfied by each
% task
% - S: an array containing the total resource capacity available to be
% allocated to tasks; its size is equal to the number of resource types
% - O: an array of offers/priorities for each task
% - p: an array of prices of each resource type
% - actions: cell array of allowed actions, which comprises resource
% allocations of each resource type and compression factors (last);
% each cell element is an array containing the allowed values
%
% It returns:
% - s: the resouce allocation matrix, containing the allocated resources
% for each task and resource type
% - x: the admission vector, containing for each task 1 if the task is
% admitted, 0 otherwise
% - z: the compression factor vector, containing for each task the
% selected compression factor
% - total_value: the scalar value of the objective function
%
% [s,x,z,total_value] = semoran(a,l,A,L,S,O,p,actions,min_s) solves the
% SF-ESP always allocating the minimum amount of resources sufficient to
% execute admitted tasks within constraints, thus without enabling
% flexible resource allocation
% It takes the input defined above, plus min_s: a boolean that has to be
% set to true that enables this solver behavior. It returns the same
% outputs as defined above.
m = length(S);
T = length(L);
assert(T == length(a) && T == length(l) && T == length(A), ...
"Item size "+string(T)+" is not consistent across all inputs");
assert(m == length(p), "S and p must have the same length");
assert(length(O) == T, "O length must equal to the number of tasks");
assert(exist('actions','var'));
assert(numel(actions) == m+1, "Actions variable size must be m+1");
%disp("Discrete actions");
assert(iscell(actions), "Actions variable must have cell type");
if exist('min_s', 'var')
assert(min_s == true);
end
% reshape input variables
S = S(:); % S is column
O = O(:); % O is same shape as S
p = p(:)'; % p is row
% initialize return variables
z = zeros([T,1]);
s = zeros([m,T]);
x = zeros([T,1]);
% define allowed actions
out = cell(size(actions));
[out{:}] = ndgrid(actions{:});
ac=zeros([length(out)-1, numel(out{1})]);
for i=1:length(out)-1
ac(i,:) = out{i}(:);
end
% if P is 0s then replace it with 1s
replace_P = @(P)P*any(P>0)+all(P==0)*ones([m,1]);
primal_gradient = @(s_t, t) (O(t)-p*s_t)*norm(replace_P(s*x))/ ...
sum(s_t./S.*replace_P(s*x));
% find the optimal compression factor for all items starting from the
% accuracy functions. argmin(a) s.t. accuracy requirement is met.
% find an initial weight for each item to perform a preliminary sorting
z = optimal_z(z);
if exist('min_s', 'var')
s = optimal_s(z,s);
end
% admit task according to the order of their primal gradient
% keep going if there are feasible task that are not admitted yet
candidate_task = logical(true([T,1]));
for t = 1:T
if a{t}(z(t)) < A(t)
candidate_task(t) = false;
end
if exist('min_s', 'var')
if sum(s(:,t)) == 0
candidate_task(t) = false;
elseif l{t}(s(:,t),z(t)) > L(t)
candidate_task(t) = false;
end
end
end
while true
candidate_task_set = find(candidate_task);
G = zeros([T,1]);
if isempty(candidate_task_set)
break
end
% calculate the primal gradient of candidate tasks
for c = 1:length(candidate_task_set)
t = candidate_task_set(c);
if exist('min_s', 'var')
% gradients only depends on free resources
G(t) = primal_gradient(s(:,t),t);
continue
end
[s(:,t), G(t)] = find_maximum_gradient(t);
if all(s(:,t) == 0)
candidate_task(t) = false;
end
end
% calculate the max gradient and accept the corresponding task
[g, c] = max(G);
if candidate_task(c)
x(c) = 1;
else
continue;
end
candidate_task(c) = false;
if exist('min_s', 'var')
%remove candidate that are not feasible anymore
for c = 1:length(candidate_task_set)
t = candidate_task_set(c);
if any(s(:,t) > S - s*x)
candidate_task(t) = false;
end
end
end
end
total_value = (O-p*s)*x;
% try to accept feasible tasks
% feasible only if it satisfies performance and resource constraints
function f = check_task_feasibility
f = logical(false([T,1]));
for t = 1:T
% if a{t}(z(t)) => A(t) && ...
% l{t}(min_s(:,t),z(t)) <= L(t) && ...
% all(min_s(:,t) <= S + s*x)
if a{t}(z(t) > A(t))
disp("Task "+ t +" is feasible");
f(t) = true;
end
end
end
function z = optimal_z(z)
z_values = sort(actions{end});
for t = 1:T
found = false;
for z_i = 1:length(z_values)
z(t) = z_values(z_i);
if a{t}(z(t)) >= A(t)
found = true;
break;
end
end
if ~ found
z(t) = 0;
end
end
end
function s = optimal_s(z,s)
[s_values,idx] = sort(O-p*ac, 'descend');
for t = 1:T
if z(t) == 0
continue
end
found = false;
for s_i = 1:length(s_values)
s(:,t) = ac(:,idx(s_i));
if l{t}(s(:,t),z(t)) <= L(t)
found = true;
break;
end
end
if ~ found
s(:,t) = zeros([m,1]);
end
end
end
function [s_t, max_gradient] = find_maximum_gradient(t)
% find the feasible resource allocation that maximizes the gradient
max_gradient = 0;
s_t = zeros([m,1]);
% forall possible actions
% if action is feasible find gradient
% if current gradient is greater than the max we previously had,
% update the max gradient
% return the max gradient and the corresponding resource allocation
for i = 1:length(ac)
if feasible(t,ac(:,i))
gradient = primal_gradient(ac(:,i),t);
if gradient > max_gradient
max_gradient = gradient;
s_t = ac(:,i);
end
end
end
function f = feasible(t,s_t)
f = false;
if all(S-s*x >= s_t) && l{t}(s_t,z(t)) < L(t)
f = true;
end
end
end
end