Optimization Problem of a Single Lessons Scheduling Model - minizinc
I've written a Minizinc-Model that allows a teacher to schedule single lessons of his students. Teacher and students can prioritize their available time slots (prioTeacher, respectively prio).
The model works fine for simple and small input sets, but with a realistic set of input data, i.e. 3 days, each having 44 time slots (== 15 minutes) and 11 students, didn't find the optimal solution after more than 24 hours.
Model (stupla-prio.mzn)
% enum of presence days
enum DAY;
int: num_days = card(DAY);
% maximal duration of a lessons
int: maxDur;
% maximal numbers of slots per Day;
int: maxSlots;
set of int: SLOT = 1..maxSlots;
set of int: SLOTx = 0..maxSlots;
% number of students
int: n;
set of int: STUDENT = 1..n;
%
array[DAY] of set of SLOT: teacher;
array[STUDENT,DAY] of set of SLOT: feasible;
array[STUDENT] of 1..maxDur: lessonDuration;
array[STUDENT,DAY,SLOT] of 0..3: prio;
array[DAY,SLOT] of 0..3: prioTeacher;
% Factor for weighting: obj = obj_stud + k * obj_teacher
int: k;
%
% decision VARIABLES
% array[STUDENT,DAY] of var 0..maxSlots: start_slot;
array[STUDENT,DAY] of var SLOTx: start_slot;
array[STUDENT,DAY] of var SLOTx: end_slot;
% 2d-array that stores for each d (in DAYS) and each SLOT
% the STUDENT or
% 0 if it is not allocated or
% -1 the teacher is available neither
array[SLOT,DAY] of var -1..n: schedule;
% -----------------------------------------------------------
% CONSTRAINTS
% 1. For each student 'start_slot' must be in 'feasible'
constraint forall(s in STUDENT, d in DAY where start_slot[s,d] > 0)(
start_slot[s,d] in feasible[s,d] );
% 2. For each student 'end_slot' = 'start_slot' + lessonDuration - 1
constraint forall(s in STUDENT, d in DAY)(
if start_slot[s,d] > 0 then
end_slot[s,d] = start_slot[s,d] + lessonDuration[s] - 1
else
end_slot[s,d] = 0
endif);
% 3. All slot between 'start_slot' and 'end_slot' must be in 'feasible'
constraint forall(s in STUDENT, d in DAY where start_slot[s,d] > 0)(
forall(j in 1..lessonDuration[s]-1) ( start_slot[s,d] + j in feasible[s,d] )
);
% 4. make sure each student has exactly 1 lesson
constraint forall(s in STUDENT)( sum([start_slot[s,d] > 0| d in DAY]) = 1);
% 5. link 'schedule' to 'start_slot' and 'end_slot'
constraint forall(s in STUDENT, d in DAY, z in SLOT) (
(z in feasible[s,d] /\ z >= start_slot[s,d] /\ z <= end_slot[s,d])
<-> schedule[z,d] = s
);
% 6. mark empty slots for teacher
constraint forall(d in DAY, z in SLOT)(
(z in teacher[d] /\ schedule[z,d] = -1) -> schedule[z,d] = 0 );
% objective function students
var int: obj_stud;
constraint obj_stud = sum([prio[schedule[z,d],d,z]|
d in DAY, z in SLOT where schedule[z,d] > 0]);
% objective function teacher
var int: obj_teacher;
constraint obj_teacher = sum([prioTeacher[d,z]|
d in DAY, z in SLOT where schedule[z,d] > 0]);
%solve satisfy;
solve :: int_search( [start_slot[s,d] |s in STUDENT, d in DAY], first_fail, indomain, complete) maximize (obj_stud + k * obj_teacher);
output [
% "start_slot =\n" ++ show2d(start_slot) ++ "\n" ++
% "end_slot = " ++ show2d(end_slot) ++ "\n" ++
% " teacher = " ++ show(teacher) ++ ";\n" ++
% " feasible = " ++ show2d(feasible) ++ "\n" ++
% "schedule = \n" ++ show2d(schedule) ++ ";\n" ++
% " - "
" Slot# ||"] ++
[ " \(d) |" | d in DAY ] ++
[
"| obj = " ++ show(obj_stud + k * obj_teacher) ++
" [teacher=\(obj_teacher), " ++
"stud=\(obj_stud), k=\(k)]" ] ++
[ "\n -------++"] ++
[ "-------+" | d in DAY ] ++
["+\n"] ++
[
if d = 1 then show_int(5,z) ++ " ||" else "" endif ++
show_int(4,schedule[z,d]) ++ " |" ++
if d = num_days then "|\n" else "" endif | z in SLOT, d in DAY
] ++ [ " -------++"] ++
[ "-------+" | d in DAY ]
++ ["+\n"]
;
Data
example 1 (works fine)
DAY = {Mon, Wed};
maxSlots = 14; % == 30 minutes slot duration
teacher = [ {1,2,3,4,5,6},
{6,11,12,13,14}];
n = 4;
lessonDuration = [2,1,1,3];
maxDur = 3;
feasible = array2d(1..n, DAY, [
{1,2,3,4,5,6}, {6},
{1,2,3}, {}, % Stud2: Day1, Day2
{1}, {13,14}, % Stud3: Day1, Day2
{3,4,5}, {11,12,13,14}]);
prio = array3d(1..n,DAY,1..maxSlots, [
% Stud1
1,1,1,2,2,2,0,0,0,0,0,0,0,0,
0,0,0,0,0,2,0,0,0,0,0,0,0,0,
% Stud2
1,3,3,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% Stud3
3,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,2,2,
% Stud4
0,0,1,2,2,0,0,0,0,0,0,0,0,0 ,
0,0,0,0,0,0,0,0,0,0,3,3,1,1]);
%
k = 10;
prioTeacher = array2d(DAY,1..maxSlots, [
% Example 1:
% morning muffel, and break
% 1,1,1,2,2,2,3,1,1,3,3,3,3,3,
% 1,1,1,2,2,2,3,1,1,3,3,3,3,3,]);
% Example 2:
% early bird
3,3,3,3,3,3,1,1,1,1,1,1,1,1,
3,3,3,3,3,3,1,1,1,1,1,1,1,1]);
Example 2 (takes verrry long...)
% Datafile
% Available week days
DAY = {Mon, Tue, Wed};
% Number of maximal slots per day, == 15 minutes slots
maxSlots = 44;
% Number of students
n = 11;
% Weighting factor
k = 1;
lessonDuration = [3,3,2,3,3,3,3,3,6,4,2];
maxDur = 6;
teacher = [ {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},
{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},
{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}];
% feasible time slots (teacher and students intersected)
feasible = array2d(1..n, DAY, [
% IH
{1,2,3,4,5,6,7,8}, {}, {1,2,3,4,37,38,39,40,41,42,43},
% MM
{11,12,13,14,15,16,28,29,30,31}, {7,8,9,10,11}, {},
% NW
{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}, {}, {1,2,3,4,5,6,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},
% RD
{7,8,9,10,11,12,40,41,42}, {13,14,15,16,17,18,19,20,21,22,23,34,35,36,37,38}, {},
% MS
{7,8,9,10,11,12,34,35,36,37,38,39,40,41,42}, {35,36,37,38,39,40}, {},
% SB
{}, {1,2,3,4,5,6}, {8,9,10,11,12},
% SO
{}, {}, {6,7,8,9,10,11,12,36,37,38,39,40,41,42},
% CT
{}, {}, {1,2,3,4,5,6,7,8,9,10,11,12},
% AG
{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}, {9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28}, {},
% SS
{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}, {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}, {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},
% RF
{25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42}, {}, {33,34,35,36,37,38,39,40,41,42}
]);
% Prioririties of Teacher
prioTeacher = array2d(DAY,1..maxSlots, [
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]);
% Priorities of Students
prio = array3d(1..n,DAY,1..maxSlots, [
% 1. IH
2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,0,
% 2. MM
0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 3. NW
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,
% 4. RD
0,0,0,0,0,0,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 5. MS
0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 6. SB
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 7. SO
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,0,0,
% 8. CT
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 9. AG
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
% 10. SS
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
% 11. RF
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,0,0]);
(You can access the files here: https://gitlab.com/andibachmann/stupla_mzn/tree/master/mzn/t3 )
I did my calculations with mzn-gecode (G12 MiniZinc evaluation driver, version 2.0.2).
Any hints and/or directions for further improvements are welcome!
Regards
Andi
I did the following changes to the model:
combined the DAY and SLOT dimensions into a single TIME dimension (parameters are converted accordingly), caution is taken so that lessons don't extend over multiple days.
removed the explicit schedule representation of the solution - it is now calculated on-the-fly in the output section.
pre-calculated feasible start times for student lessons - thereby only the start times must be constrained in the model.
changed to use binary variables start and active that represent if a student lesson starts at a given time and is active at given time, respectively.
made all constraints linear in the start and active variables.
Using the modified model the OSICBC solver solves the larger instance to optimum within a second.
% enum of presence days
enum DAY;
int: num_days = card(DAY);
% maximal duration of a lessons
int: maxDur;
% maximal numbers of slots per Day;
int: maxSlots;
set of int: SLOT = 1..maxSlots;
set of int: SLOTx = 0..maxSlots;
% number of students
int: n;
set of int: STUDENT = 1..n;
%
array[DAY] of set of SLOT: teacher;
array[STUDENT,DAY] of set of SLOT: feasible;
array[STUDENT] of 1..maxDur: lessonDuration;
array[STUDENT,DAY,SLOT] of 0..3: prio;
array[DAY,SLOT] of 0..3: prioTeacher;
% Factor for weighting: obj = obj_stud + k * obj_teacher
int: k;
% Make the time axis one-dimensional and convert all data accordingly.
set of int: TIME = 1..maxSlots*num_days;
function int: time(int: d, int: z) = (d-1)*maxSlots + z;
set of TIME: teacher_time = {time(d, z) | d in DAY, z in teacher[d]};
array[STUDENT] of set of TIME: feasible_time = [{time(d, z) | d in DAY, z in feasible[s,d]} | s in STUDENT];
array[STUDENT] of set of TIME: feasible_start_time =
[{time(d,z) | d in DAY, z in 1..maxSlots-lessonDuration[s]+1 where forall(u in time(d,z)..time(d,z)+lessonDuration[s]-1)(u in feasible_time[s] intersect teacher_time)} | s in STUDENT];
array[STUDENT,TIME] of 0..3: prio_time = array2d(STUDENT, TIME, [prio[s,d,z] | s in STUDENT, d in DAY, z in SLOT]);
array[TIME] of 0..3: prioTeacher_time = [prioTeacher[d,z] | d in DAY, z in SLOT];
%
% decision VARIABLES
array[STUDENT,TIME] of var 0..1: start;
array[STUDENT,TIME] of var 0..1: active;
% -----------------------------------------------------------
% CONSTRAINTS
% 1. a lesson can only start at a feasible time
constraint forall(s in STUDENT, t in TIME)
(start[s,t] <= bool2int(t in feasible_start_time[s]));
% 2. each lesson must have a start time
constraint forall(s in STUDENT)
(sum(t in TIME)(start[s,t]) = 1);
% 3. maximum one lesson active at any time
constraint forall(t in TIME)
(sum(s in STUDENT)(active[s,t]) <= 1);
% 4&5. constraints defining if lesson active
constraint forall(s in STUDENT, d in 1..num_days)
(active[s,time(d,1)] = start[s,time(d,1)]);
constraint forall(s in STUDENT, d in 1..num_days, z in 2..maxSlots)
(active[s,time(d,z)] <= active[s,time(d,z-1)] + start[s,time(d,z)]);
% 6. ensure duration of lesson is fulfilled
constraint forall(s in STUDENT)
(sum(t in TIME)(active[s,t]) = lessonDuration[s]);
var int: obj = sum(s in STUDENT, t in TIME)
(active[s,t] * (prio_time[s,t] + k*prioTeacher_time[t]));
solve maximize obj;
output [
" Slot# ||"] ++
[ " \(d) |" | d in DAY ] ++
[
"| obj = " ++ show(obj) ++
" [teacher=\(sum(s in STUDENT, t in TIME)(active[s,t] * k*prioTeacher_time[t])), " ++
"stud=\(sum(s in STUDENT, t in TIME)(active[s,t] * prio_time[s,t])), k=\(k)]" ] ++
[ "\n -------++"] ++
[ "-------+" | d in DAY ] ++
["+\n"] ++
[
if d = 1 then show_int(5,z) ++ " ||" else "" endif ++
show_int(4,let {var int: student = sum(s in STUDENT)(s*active[s,time(d,z)])} in if student > 0 then student else bool2int(z in teacher[d]) - 1 endif) ++ " |" ++
if d = num_days then "|\n" else "" endif | z in SLOT, d in DAY
] ++ [ " -------++"] ++
[ "-------+" | d in DAY ]
++ ["+\n"]
;
Another option (sticking to the original model and easier to read) would be:
...
array[STUDENT] of var TIME: start_time;
include "disjunctive.mzn";
constraint disjunctive(start_time, lessonDuration);
constraint forall(s in STUDENT)
(start_time[s] in feasible_start_time[s]);
var int: obj = sum(s in STUDENT, t in TIME where t >= start_time[s] /\ t <= start_time[s] + lessonDuration[s] - 1)(prio_time[s,t] + k*prioTeacher_time[t]);
solve maximize obj;
...
Related
Minizinc Objective Function For Gaps in Schedule
I have a working Miniznic model to schedule individual lessons of 1 professor having n students (Optimization Problem of a Single Lessons Scheduling Model). The model considers availability (hard constraint) and the time preferences (objective function) of the professor as well as of the students. Now, I want to extend the model and optimize the schedule such that gaps between lessons are minimized. Example: Schedule : p L p p L L . . p p L L p L L p L p p . L p L L . L p L Real Gaps : . L p p L L . . . . L L p L L p L . . . L p L L . L p L where `p` = 0 == Teacher available, but no Lesson `L` = 1 == Teacher gives lesson (to student) `.` = -1 == Teacher not available Obviously, the p in slot 1 must not be counted as a gap. Similarly, slots 9 and 10 are no gaps, neither. Eliminating all false gaps, the Schedule should finally look like the Real Gaps array (Note: false gaps are marked with .; the same as not available). The result would be a gap array [2, 1, 1, 1, 1] (for each gap showing the number of slots it lasts). Based on such an array one could then e.g. formulate an objective to minimize the overall gap slots. In ruby I was able to formulate an algorithm that does what I want: def gap_array(schedule_arr) # initialize variables start_search = false # flag for break start break_slots = 0 # counter of break slots res_arr = [] # resulting array schedule_arr.each do |slot| if slot == 1 # start watching for break start_search = true end # if start_search if slot == 0 # == break break_slots += 1 elsif slot == 1 # == consecutive lesson slot if break_slots > 0 # number of break_slots > 0 res_arr.append(break_slots) break_slots = 0 end else # == not available break_slots = 0 # any break so far is discarded start_search = false end end end return res_arr end How can I formulate such an algorithm in Minizinc? Thanks!
One way to this in MiniZinc would be to extend the model at Optimization Problem of a Single Lessons Scheduling Model in the following way: Initially calculate teacher_free as the slots where the teacher is not available combined with adjacent slots where no lesson takes place (this is done in two steps, going from the left teacher_free_left and the right teacher_free_right, respectively, and then combining the results to form teacher_free). In the next step the real_gap is calculated as slots where the teacher is not free and no lesson takes place. In the objective a penalty term for real_gap is then introduced like (k2 being the gap penalty weight): int: k2 = 1; var int: obj = sum(s in STUDENT, t in TIME) (active[s,t] * (prio_time[s,t] + k*prioTeacher_time[t])) - k2*sum(real_gap); Here all the other extensions to the model (with some further comments): array[DAY,SLOT] of var 0..1: lesson = array2d(DAY, SLOT, [sum(s in STUDENT)(active[s,time(d,z)]) | d in DAY, z in SLOT]); array[DAY,SLOT] of var 0..1: teacher_free_left; array[DAY,SLOT] of var 0..1: teacher_free_right; array[DAY,SLOT] of var 0..1: teacher_free; array[DAY,SLOT] of var 0..1: real_gap; predicate equals_and(var 0..1: z, var 0..1: x, var 0..1: y) = (z <= x /\ z <= y /\ z >= x + y - 1); predicate equals_or(var 0..1: z, var 0..1: x, var 0..1: y) = (z >= x /\ z >= y /\ z <= x + y); % calculate teacher free left % first slot -> teacher free = no lesson in the slot % other slots -> teacher free = teacher out or (left slot teacher free and no lesson in slot) array[DAY,SLOT] of var 0..1: teacher_free_left_temp; constraint forall(d in DAY) (teacher_free_left_temp[d,1]=1-lesson[d,1]); constraint forall(d in DAY, z in 2..maxSlots) (equals_and(teacher_free_left_temp[d,z], teacher_free_left[d,z-1], 1-lesson[d,z])); constraint forall(d in DAY, z in SLOT) (equals_or(teacher_free_left[d,z], 1 - bool2int(z in teacher[d]), teacher_free_left_temp[d,z])); % calculate teacher free right % last slot -> teacher free = no lesson in the slot % other slots -> teacher free = teacher out or (right slot teacher free and no lesson in slot) array[DAY,SLOT] of var 0..1: teacher_free_right_temp; constraint forall(d in DAY) (teacher_free_right_temp[d,maxSlots]=1-lesson[d,maxSlots]); constraint forall(d in DAY, z in 1..maxSlots-1) (equals_and(teacher_free_right_temp[d,z], teacher_free_right[d,z+1], 1-lesson[d,z])); constraint forall(d in DAY, z in SLOT) (equals_or(teacher_free_right[d,z], 1 - bool2int(z in teacher[d]), teacher_free_right_temp[d,z])); % teacher free when teacher free left or teacher free right constraint forall(d in DAY, z in SLOT) (equals_or(teacher_free[d,z], teacher_free_left[d,z], teacher_free_right[d,z])); % real gap when teacher not free and no lesson constraint forall(d in DAY, z in SLOT) (equals_and(real_gap[d,z], 1-teacher_free[d,z], 1-lesson[d,z]));
Black Scholes function with vector inputs in Matlab
I'm trying to write a function in Matlab that calculates the Call price using the Black Scholes formula with vector inputs. I have so far: function [C] = BlackScholesCall(S,K,t,r,sigma) %This function calculates the call price per Black-Scholes equation %INPUT S ... stock price at time 0 % K ... strike price % r ... interest rate % sigma ... volatility of the stock price measured as annual standard deviation % t ... duration in years %OUTPUT C ... call price %USAGE BlackScholesCall(S,K,t,r,sigma) for l = 1:length(K) for z = 1:length(t) d1 = (log(S/K(l)) + (r + 0.5*sigma^2)*t(z))/(sigma*sqrt(t(z))); d2 = d1 - sigma*sqrt(t(z)); N1 = 0.5*(1+erf(d1/sqrt(2))); N2 = 0.5*(1+erf(d2/sqrt(2))); C(l) = S*N1-K(l)*exp(-r*t(z))*N2; end end end F.e. the code to call my function would be S = 20 K = 16:21 t = 1:1:5 r = 0.02 sigma = 0.25 C = BlackScholesCall(S, K, t, r, sigma) But when I compare this with the results of the blsprice function in Matlab, I get different results. I suspect there might be something wrong with the way I did the loop?
You are getting the same results as, >> blsprice(S,K,r,t(end),sigma) ans = 7.1509 6.6114 6.1092 5.6427 5.2102 4.8097 This is because by using C(l) = ... you are overwriting each element of C numel(t) times, and hence only storing/returning the last calculated values for each value of z. At a minimum you need to use, %C(l) = S*N1-K(l)*exp(-r*t(z))*N2; C(z,l) = S*N1-K(l)*exp(-r*t(z))*N2; But you should also pre-allocate your output matrix. That is, before either of the loops, you should add C = nan(numel(K),numel(t)); Finally, you should note that you don't need to use any loops at all, [Kmat,tmat] = meshgrid(K,t); d1 = (log(S./Kmat) + (r + 0.5*sigma^2)*tmat)./(sigma*sqrt(tmat)); d2 = d1 - sigma*sqrt(tmat); N1 = 0.5*(1+erf(d1/sqrt(2))); N2 = 0.5*(1+erf(d2/sqrt(2))); C = S*N1-Kmat.*exp(-r*tmat).*N2;
An R version could be the following. BlackScholesCall <- function(S, K, tt, r, sigma){ f <- function(.K, .tt){ d1 <- (log(S/.K) + (r + 0.5*sigma^2)*.tt)/(sigma*sqrt(.tt)) d2 <- d1 - sigma*sqrt(.tt) S*pnorm(d1) - .K*exp(-r*.tt)*pnorm(d2) } m <- length(K) n <- length(tt) o <- outer(K, tt, f) last <- if(m > n) o[n:m, n] else o[m, m:n] c(diag(o), last) } BlackScholesCall(S, K, tt, r, sigma) #[1] 4.703480 4.783563 4.914990 5.059922 5.210161 5.210161 4.809748
Matlab Nested Radicals
Working on an assignment in MATLAB and I can't seem to figure this problem out due to the arithmetic, I've been trying it for about 6 hours now I need to create a loop that accepts user input > 1 (done) and loops through the following (m is input) t1 = sqrt(m); t2 = sqrt(m-sqrt(m)); t3 = sqrt(m-sqrt(m+sqrt(m))) t4 = sqrt(m-sqrt(m+sqrt(m-sqrt(m)))) t5 = sqrt(m-sqrt(m+sqrt(m-sqrt(m+sqrt(m))))) and so on until the new t value minus the old t value is < 1e-12 My current code is as follows %Nested Radicals clear all; clc; %User input for m m = input('Please enter a value for m: '); %Error message if m is less than 1 if m <= 1 fprintf('ERROR: m must be greater than 1\n') m = input('Please enter a value for m: '); end %Error message if m is not an integer if mod(m,1) ~= 0 fprintf('m must be an integer\n') m = input('Please enter a value for m: \n'); end %Nested things t_old = m; t_new = sqrt(m); varsign = -1; index = 1; loop = true; endResult = 1e-12; sqrts = [sqrt(m), sqrt(m-sqrt(m)), sqrt(m-sqrt(m+sqrt(m))), sqrt(m-sqrt(m+sqrt(m-sqrt(m)))), sqrt(m-sqrt(m+sqrt(m-sqrt(m+sqrt(m)))))]; fprintf('m = %d\n',m) fprintf('t1 = %14.13f\n', t_new') while loop if index ~= 1 curResult = abs(sqrts(1,index) - sqrts(1, index-1)); else curResult = abs(sqrts(1, index)); end if curResult > endResult if index < 5 t_new = sqrts(1, index+1); else t_new = sqrts(1, index); loop=false; end if index fprintf('t%d = %14.13f\n', index, t_new) end else fprintf('t%d = %14.13f\n', index, t_new); break; end index = index + 1; if index > 50 fprintf('t%d = %14.13f\n', index, t_new); break; end end
Unless I'm very much mistaken, you can write the expression for t(n) as follows: t(n) = sqrt(m-sqrt(m+t(n-2)); which makes it a lot easier to loop: %Nested Radicals clear all; clc; %User input for m m = input('Please enter a value for m: '); %Error message if m is less than 1 if m <= 1 fprintf('ERROR: m must be greater than 1\n') m = input('Please enter a value for m:'); end %Error message if m is not an integer if mod(m,1) ~= 0 fprintf('m must be an integer\n') m = input('Please enter a value for m:'); end %Nested things t_old = sqrt(m); t_new = sqrt(m-sqrt(m)); threshold = 1e-12; k = 3; while abs(t_new - t_old) >= threshold temp = sqrt(m-sqrt(m+t_old)); t_old = t_new; t_new = temp; k = k+1; end fprintf('t%d = %14.13f\n', k-2, t_old); fprintf('t%d = %14.13f\n', k-1, t_new); fprintf('t%d - t%d = %14.13f\n', k-2, k-1, t_old - t_new); which gives for m=9 for example: Please enter a value for m: 9 t17 = 2.3722813232696 t18 = 2.3722813232691 t17 - t18 = 0.0000000000005
I'm not sure what you're trying to do with the sqrts variable, you should be calculating each step on the fly in your loop, since you can't possibly know how deep you need to go m = 5; % Get m however you want to n = 0; % Iteration counter tol = 1e-12 % Tolerance at which to stop dt = 1; % initialise to some value greater than 'tol' so we can start the loop % Loop until tn is less than tolerance. Would be sensible to add a condition on n, % like "while tn > tol && n < 1000", so the loop doesn't go on for years if the % condition takes a trillion loops to be satisfied while dt > tol % Set the value of the deepest nested expression tn = sqrt(m); % We know how many times take sqrt, so for loop our way out of the nested function % Initially we want the sign to be -1, then +1, -1, ... % This is achieved using ((-1)^ii) for ii = 1:n tn = sqrt(m + ((-1)^ii)*tn); % Calculate next nested function out end % Increment iteration number n = n + 1; dt = abs( t_old - tn ); t_old = tn; end I've not done any analysis on your function, so have no idea if it's guaranteed to converge to some value <1e-12. If it isn't then you definitely need to add some maximum iteration condition as I suggest in the comments above.
Multilevel Otsu Threshold Matlab
I have tried to implement the Mutlilevel Otsu Threshold Algorithm but my values does not correspond to the ones from the matlab internal function, maybe I have mistake. This is the standard Algorithm: Here is my Code: function [T] = MultiLevelOtsu(img, n) % Calculate Histogram of Image H = imhist(uint8(img)); a = size(H, 2); b = size(H, 1); T = [zeros(1, n)]; % Step 1 : Repeat recursivly Step 2-6 n/2-1 times for i = 1:n/2-1 % Step 2 : Define & Update Range R = [a:b]'; % Step 3 : Find mean & std of all pixels in R mu = mean(R); sigma = std(R); % Step 4 : Sub-ranges T1 & T2 T1 = mu - 1*sigma; T2 = mu + 1*sigma; % Step 5 : Threshold Calculation T(i) = floor((ceil(otsuthresh(H(a:T1))*256)+ceil(otsuthresh(H(T2:b))*256))/2); % Step 6 : Update a & b a = T1+1; b = T2-1; end % Step 7 : Update Step 5 T1 = mu; T2 = mu+1; T = floor((ceil(otsuthresh(H(a:T1))*256)+ceil(otsuthresh(H(T2:b))*256))/2); end
Matlab and sorting single results to a matrix
for i=1:1:k %k = 100 people for j=1:1:l %l = 5 orders Resultx = a + b + d(j); % cost of drink Resultx Resulty = f + g + c(j); % cost of food Resulty end Matrix(i) = [Resultsx1...j Resulty1...j] end Those % notes are for helping me express the problem I want to solve in my mind, and later on, in my script. Lets claim that we want for each i to store values in a matrix of costs of the drinks and food it orders. So for people i = 1, 1[1 5] %people 1, first order: drink costs 1 and food costs 5 2[2 3] %people 1, second order: drink costs 2 and food costs 3 ... j[x y] %people 1, j order: drink and food costs x and y !!! Matrix(1) = sort (j [x,y]) !!! for people i = 2, 1[1 5] %people 2, first order: drink costs 1 and food costs 5 2[2 3] %people 2, second order: drink costs 2 and food costs 3 ... j[x y] %people 2, j order: drink and food costs x and y !!! Matrix(2) = sort (j [x,y]) !!! for people i = k, 1[1 5] %people k, first order: drink costs 1 and food costs 5 2[2 3] %people k, second order: drink costs 2 and food costs 3 ... j[x y] %people k, j order: drink and food costs x and y !!! Matrix(i) = sort (j [x,y]) !!! I want to form every result of each ith iteration to a Matrix in ascending order Matrix(i) = sort (j [x,y]). Perhaps not the best paradigm, but thank you in advance.
(Two ways I understood your statement; I'm presuming you're interested in 2. solution. In this form Resultx and Resulty don't depend on i in any way, and therefore they'll be the same for all the "people"). 1. Matrix is [ k x 2 ] array. Results from second loop are summed up! Matrix = zeros(k, 2); % pre-allocate space for i=1:1:k %k = 100 people Resultx = 0; Resulty = 0; for j=1:1:l %l = 5 orders Resultx = Resultx + a + b + d(j); % cost of drink Resultx Resulty = Resulty + f + g + c(j); % cost of food Resulty end Matrix(i,:) = [Resultx, Resulty] % save pair end Sorted = sortrows(Matrix, [1 2]); % sort pairs Last command sorts pairs, first by 1st column, then by 2nd column in ascending order. If you would like descending order for both criteria, you would use [-1 -2] instead. Combining ascending and descending is also possible (for example [-1 2]) but senselessness is questionable in this case. 2. Matrix is [ k x l x 2 ] array in which the results are kept individually and are not summed up in second loop. Matrix = zeros(k, l, 2); % pre-allocate space Intermediate = zeros(l, 2); % container used for sorting for i=1:1:k %k = 100 people for j=1:1:l %l = 5 orders Resultx = a + b + d(j); % cost of drink Resultx Resulty = f + g + c(j); % cost of food Resulty Intermediate(j,:) = [Resultx, Resulty]; %save pair end Matrix(i,:,:) = sortrows(Intermediate, [1 2]); % sort pairs end Note: You should do avoid writing loops in Matlab and resort to vectorized solution wherever possible!