Get Shrove Tuesday in Lua - date

How can I get the date of Shrove Tuesday (12/02/2013, 04/03/2014, 17/02/2015, etc.) in Lua from a supplied year? If possible, could it be explained clearly so that it can be adapted for Easter, Mother's Day, and other holidays that change each year? There are scripts available online that get Easter, but they're not explained very clearly and I don't understand how I can change them for Shrove Tuesday and other holidays.

According to Wikipedia, Shrove Tuesday is exactly 47 days before Easter Sunday. So the key is really just how to calculate Easter Day, a movable feast. You can modify the code to calculate Easter to get Shrove Tuesday.
function shrove_tuesday(year)
local leap_year
if year % 4 == 0 then
if year % 100 == 0 then
if year % 400 == 0 then
leap_year = true
else
leap_year = false
end
else
leap_year = true
end
else
leap_year = false
end
local a = year % 19
local b = math.floor(year / 100)
local c = year % 100
local d = math.floor(b / 4)
local e = b % 4
local f = math.floor((b + 8) / 25)
local g = math.floor((b - f + 1) / 3)
local h = (19 * a + b - d - g + 15) % 30
local i = math.floor(c / 4)
local k = c % 4
local L = (32 + 2 * e + 2 * i - h - k) %7
local m = math.floor((a + 11 * h + 22 * L) / 451)
local month = math.floor((h + L - 7 * m + 114 - 47) / 31)
local day = (h + L - 7 * m + 114 - 47) % 31 + 1
if month == 2 then --adjust dates in February
day = leap_year and day - 2 or day - 3
end
return day, month
end
The calculation seems complicated, that's because calculating Easter Day is complicated, this function is following the algorithm of Computus.
Test:
print(shrove_tuesday(2012))
print(shrove_tuesday(2013))
print(shrove_tuesday(2014))
print(shrove_tuesday(2015))
Output:
21 2
12 2
4 3
17 2
You can easily use the day and month to get formatted string using string.format("%02d/%02d/%04d", day, month, year) or whatever you need.

Related

Building table with specifik data

I need some help with a task that I have:
I have 4 vectors with data: 3 of them are with dates and the 4th one is with overdue days, something like this:
dateAdded dueDate date overdue
Published
02/11/18 02/11/18 03/11/18 1
03/11/18 04/11/18 11/11/18 7
03/11/18 04/11/18 04/12/18 30
04/11/18 05/11/18 ongoing overdue up to today
Can you give me some tips how can I create a table with the overdue days for each month from the year, considering that when I have transition from one month to another one I have to count the overdue to both months? Also when the datePublished hasn't come yet I have to count the overdue dates for each month passed.
Thanks
My solution:
number_months = max(((year(dateAdded)-2018))*12 + rem(month(dateAdded),13));
idx = 1;
ii=1;
for k=1:number_months
kpit(k,1) = k;
kpit(k,2) = 0;
kpit(k,3) = 0;
end
for i=1:data_length_Added
% if month(dateAdded(i)) == month(dueDate(i)) && month(dateAdded(i)) ~= 0
if month(dueDate(i)) == month(datePublished(i)) && month(dateAdded(i)) ~= 0
[~,idx]=ismember(month(dueDate(i)),kpit(:,1),'rows');% finds the position of an element from the array in the array for months
kpit(idx,2) =kpit(idx,2) + overdue(i);
kpit(idx,3) = kpit(idx,3) + 1;
idx = idx + 1;
else if month(datePublished(i)) == month(dueDate(i)) + 1
[~,idx]=ismember(month(dueDate(i)),kpit(:,1),'rows');
[~,idx1]=ismember(month(datePublished(i)),kpit(:,1),'rows');
year1 = year(datePublished(i));
weight = (day(datePublished(i)))/eomday(year1,month(datePublished(i)));
kpit(idx,2) =kpit(idx,2) + overdue(i);
kpit(idx1,2) =kpit(idx1,2) + overdue(i)*weight;
kpit(idx,3) = kpit(idx,3)+ 1;
kpit(idx1,3) = kpit(idx1,3)+ 1;
if (month(datePublished(i)) ~= 0 && month(datePublished(i)) > month(dueDate(i))+1)
% if (datePublished > dueDate)% If the correction is done check every month if it is the next one
[~,idx]=ismember(month(datePublished(i)),kpit(:,1),'rows');
year1 = year(datePublished(i));
weight = day(datePublished(i))/eomday(year1,month(datePublished(i))); %Should count all overdue days for full months and weighted overdue dats for not full months
kpit(idx,2) = overdue(i)*weight;
kpit(idx,3) = kpit(idx,3) + 1;
for j=(month(datePublished(i))-1):month(dueDate(i))
[~,idx]=ismember(month(datePublished(j)),kpit(:,1),'rows');
kpit(idx,2) =kpit(idx,2) + overdue(j);
kpit(idx,3) = kpit(idx,3)+ 1;
j = j +1;
end
end
end
end
else if month(dueDate(i)) == 0
[~,idx]=ismember(month(today),kpit(:,1),'rows');
year1 = year(today);
weight = day(today)/eomday(year1,month(today)); %Should count all overdue days for full months and weighted overdue dats for not full months
kpit(idx,2) = overdue(i)*weight;
kpit(idx,3) = kpit(idx,3) + 1;
for j=(month(today)-1):month(dueDate(i))
[~,idx]=ismember(month(today),kpit(:,1),'rows');
kpit(idx,2) =kpit(idx,2) + overdue(j);
kpit(idx,3) = kpit(idx,3)+ 1;
j = j +1;
end
end
end

Return a vector of Grades from if-else statements

I have an if-else if construct which gives me grades A, B, C, D, F depending on marks from 0-100.
if (mark > 100) | (mark < 0)
disp('Invalid mark');
return; % Exit from the program.
end % Of first if statement
if mark >= 80 % Mark is in range 80 - 100.
grade = 'A';
elseif mark >= 70 % Mark is in range 70 - 79.
grade = 'B';
elseif mark >= 60 % Mark is in range 60 - 69.
grade = 'C';
elseif mark >= 50 % Mark is in range 50 - 59.
grade = 'D'
else % Mark is in range 0 - 44.
grade = 'F';
end
disp(grade);
Now, I have a another long vector of numeric marks (from 0-100) of size Ax1 called 'marks'. I am not sure; how to input each of those numeric marks through this line of code to achieve an output vector of grades?
You can do it in a vectorized way, along these lines:
grade_names = 'FDCBA';
th = [50 60 70 80]; % thresholds that define the grades
marks = [75 70 33 99 88 58]; % data
grades_num = 1 + sum(bsxfun(#ge, marks(:).', th(:) ), 1); % vector with numbers
% indicating grade: 1 for the first ('F'), 2 for the second ('D') etc
grades = grade_names(grades_num);
In the example, this gives the char vector od grades
grades =
BBFAAD
If you prefer cell array output, change the first line to
grade_names = {'F' 'D' 'C' 'B' 'A'};
which will give
grades =
'B' 'B' 'F' 'A' 'A' 'D'
Try this:
for i=1:length(marks)
mark=marks(i);`
followed by your code
and adding an end in the end for the for loop.
You can also put the grades in a vector too and not just display them.
Here is another solution slightly different from Luis Mendo 's answer:
if numel(find((mark > 100) | (mark < 0))) > 0
disp('Invalid mark');
return; % Exit from the program.
end % Of first if statement
%array of break points
brkpnt = [0 50:10:80 101];
%distance between breakpoints
cnt = diff(brkpnt);
%table of grades corresponding to related marks
Grades = repelem('FDCBA', cnt);
%the result. 1 added to mark to make indices greater than 0
grade = Grades(mark + 1)
or you may use simple vectorized form
grade(mark >= 80) = 'A';
grade(mark < 80 & mark >= 70) = 'B';
grade(mark < 70 & mark >= 60) = 'C';
grade(mark < 60 & mark >= 50) = 'D';
grade(mark < 50) = 'F';
I compared these methos with a benchmark that its result is:
-----------repelem method---
Elapsed time is 0.00621986 seconds.
-----------bsxfun method---
Elapsed time is 0.022429 seconds.
-----------simple vectorized method---
Elapsed time is 0.0253041 seconds.
-----------for loop method---
Elapsed time is 7.7302 seconds.
The benchmark : Online Demo

Using Kharitonov method to design the Robust controller for uncertain model

The tr. functions describing the system.
G11= 1 / (29s^3 + 40s^2 + 30s +20), G12= 1 / (50s^3 + 10s^2 + 70s +2),
G21= 1 / (80s^3 + 10s^2 + 90s +5), G22= 1 / (11s^3 + 4s^2 + 66s +7),
then,
Can I consider it as an uncertain plants given by Gij= 1/ (a s^3 + bs^2 + c s + d ) where,
a min = 11, a max = 80; b min =4 , b max = 40,
c min = 30, c max = 90, d min = 2, d max = 20.
How can we apply Kharitonov theorem to design a PID controller for an uncertain system described transfer functions and plot the interval stable region?

How can we measure the similarity distance between categorical data ?

How can we measure the similarity distance between categorical data ?
Example:
Gender: Male, Female
Numerical values: [0 - 100], [200 - 300]
Strings: Professionals, beginners, etc,...
Thanks in advance.
There are different ways to do this. One of the simplest would be as follows.
1) Assign numeric value to each property so the order matches the meaning behind the property if possible. It is important to order property values from lower to higher if property can be measured. If it is not possible and property is categorical (like gender, profession, etc), just assign number to each possible value.
P1 - Gender
-------------------
0 - Male
1 - Female
P2 - Experience
-----------
0 - Beginner
5 - Average
10 - Professional
P3 - Age
-----------
[0 - 100]
P4 - Body height, cm
-----------
[50 - 250]
2) For each concept find scale factor and offset so all property values fall in the same chosen range, say [0-100]
Sx = 100 / (Px max - Px min)
Ox = -Px min
In sample provided you would get:
S1 = 100
O1 = 0
S2 = 10
O2 = 0
S3 = 1
O3 = 0
S4 = 0.5
O4 = -50
3) Now you can create a vector containing all the property values.
V = (S1 * P1 + O1, S2 * P2 + O2, S3 * P3 + O3, S4 * P4 + O4)
In sample provided it would be:
V = (100 * P1, 10 * P2, P3, 0.5 * P4 - 50)
4) Now you can compare two vectors V1 and V2 by subtracting one from other. The length of resulting vector will tell how different they are.
delta = |V1 - V2|
Vectors are subtracted by subtracting each dimension. Vector length can be calculated as square root of sum of squared vector dimensions.
Imagine we have 3 persons:
John
P1 = 0 (male)
P2 = 0 (beginner)
P3 = 20 (20 years old)
P4 = 190 (body height is 190 cm)
Kevin
P1 = 0 (male)
P2 = 10 (professional)
P3 = 25 (25 years old)
P4 = 186 (body height is 186 cm)
Lea
P1 = 1 (female)
P2 = 10 (professional)
P3 = 40 (40 years old)
P4 = 178 (body height is 178 cm)
Vectors would be:
J = (100 * 0, 10 * 0, 20, 0.5 * 190 - 50) = (0, 0, 20, 45)
K = (100 * 0, 10 * 10, 25, 0.5 * 186 - 50) = (0, 100, 25, 43)
L = (100 * 1, 10 * 10, 40, 0.5 * 178 - 50) = (100, 100, 40, 39)
To determine we need to subtract vectors:
delta JK = |J - K| =
= |(0 - 0, 0 - 100, 20 - 25, 45 - 43)| =
= |(0, -100, -5, 2)| =
= SQRT(0 ^ 2 + (-100) ^ 2 + (-5) ^ 2 + 2 ^ 2) =
= SQRT(10000 + 25 + 4) =
= 100,14
delta KL = |K - L| =
= |(0 - 100, 100 - 100, 25 - 40, 43 - 39)| =
= |(-100, 0, -15, 4)| =
= SQRT((-100) ^ 2 + 0 ^ 2 + (-15) ^ 2 + 4 ^ 2) =
= SQRT(10000 + 225 + 16) =
= 101,20
delta LJ = |L - J| =
= |(100 - 0, 100 - 0, 40 - 20, 39 - 45)| =
= |(100, 100, 20, -6)| =
= SQRT(100 ^ 2 + 100 ^ 2 + (20) ^ 2 + (-6) ^ 2) =
= SQRT(10000 + 10000 + 400 + 36) =
= 142,95
From this you can see that John and Kevin are more similar than any other as delta is smaller.
There are a number of measures for finding similarity between categorical data. The following paper discuses briefly about these measures.
https://conservancy.umn.edu/bitstream/handle/11299/215736/07-022.pdf?sequence=1&isAllowed=y
If you're trying to do this in R, there's a package named 'nomclust', which has all these similarity measures readily available.
Hope this helps!
If you are using python, there is a latest library which helps in finding the proximity matrix based on similarity measures such as Eskin, overlap, IOF, OF, Lin, Lin1, etc.
After obtaining the proximity matrix we can go on clustering using Hierarchical Cluster Analysis.
Check this link to the library named "Categorical_similarity_measures":
https://pypi.org/project/Categorical-similarity-measures/0.4/
Just a thought, We can also apply euclidean distance between two variables to find a drift value. If it is 0, then there is no drift or else call as similar. But the vector should be sorted and same length before calculation.

How to distribute values randomly over a given time period?

I am trying to distribute a certain value over a random period of time. To clarify more ,
Suppose I want to distribute product x and y over 30 days. I have 1500 items of product x that has to be distributed over 30 days randomly. There is a restriction on the number of items that can be distributed over 1 day i.e.max 60.
I have been trying to scratch out something but am really unsucessful with this problem. I am really new to programming so it would be a real help if somebody could point me to the right approach.
As an addendum, if I have more than 1 items to be distributed (like suppose there are x,y and z) with different values (ex. 1500, 1000, 900) and there is a limitation on how many items can be distributed on a particular day (max 150 per day) will this logic still work or should I look at something new. Also, should there be a check, like suppose 100 of x, 20 of y and 30 of z are distributed, then subtract the value (for the next day I have 1400 of x, 980 of y and 870 of z available for distribution) as this will change the permutation values ?
Thank you guys !
This should work for you!
days = 30;
elem = 1500;
max_x = 60;
x = randi(max_x,days,1);
remain = elem - sum(x);
while remain > 0
idx_1 = find(x < max_x); % Numbers that can be increased
idx_fill = randperm(numel(idx_1),remain);
% idx_fill = idx_fill(:,1); % Might be needed
x(idx_1(idx_fill)) = x(idx_1(idx_fill)) + 1;
remain = elem - sum(x);
end
while remain < 0
idx_2 = find(x > 0); % Numbers that can be reduced
idx_red = randperm(numel(idx_2),abs(remain));
% idx_red = idx_red(:,1); % Might be needed
x(idx_2(idx_red)) = x(idx_2(idx_red)) - 1;
remain = elem - sum(x);
end
sum(x)
max(x)
min(x)
ans = 1500
ans = 60
ans = 34
This is an intuitive approach and works nicely for 2D arrays, without "randperm":
N = 36000; % for three hundred years
days = 30; % days
elem = 1500; % elements in ten years
min_x = 0; % daily minimum
max_x = 60; % daily maximum
tic
x = zeros(days, N);
for hh = 1:elem
% Add new candidates
inds = randi(days, N, 1);
inds = ((1:N).' - 1) * days + inds;
x(inds) = x(inds) + 1;
% Check
inds_chck = x > max_x;
any_inds_chck = any(inds_chck);
find_any_inds_chck = find(any_inds_chck);
ctrl = numel(find_any_inds_chck);
while ctrl>0
% First remove baddies
inds = inds(find_any_inds_chck);
x(inds) = x(inds) - 1;
% Then reassign to new candidates
inds = randi(days, ctrl, 1);
inds = (find_any_inds_chck.' - 1) * days + inds;
x(inds) = x(inds) + 1;
% Check again
inds_chck = x(:, find_any_inds_chck) > max_x;
any_inds_chck = any(inds_chck);
find_any_inds_chck = find(any_inds_chck);
ctrl = numel(find_any_inds_chck);
end
end
toc
But the price is a weird probability function:
hist(x(:), max_x - min_x + 1)
Note that the constraint has an obvious effect on the degrees of freedom as well.
Also note that they have tried to answer a similar question in Generate a random number with max, min and mean (average) in Matlab .