%% MATHTOOLS 2018 - LAB 2
% by Perri Katzman

%% 1 IF statements
% Sometimes you only want to execute a piece of code only when certain
% conditions are met. In those cases you can use if statements to
% conditionally execute a portion of code.

% Can you think of an instance why you might want to do something but not
% always? (if friday==false, go to HUC. else go to Meyer)


% Example:
% get the day of the week
[dayNumber, dayName] = weekday(datetime)

%%%% INTERLUDE: 
% breaking a line into smaller components;
% getting multiple outputs from a function

% if today is not equal to friday
if strcmp(dayName, 'Fri') == 0
    classLocation = 'HUC'; % class meets in HUC
else % today IS equal to friday
    classLocation = 'Meyer'; % class meets in Meyer
end

% display where class is held today
disp(['Today class is held in: ' classLocation])

%%%% INTERLUDE: 
% strcmp vs ==
% concatenating strings



% Not quite right... class is only held in HUC on tuesdays and thursdays.
% If only we could get more specific... or... "elseif"?

% if today IS equal to friday
if strcmp(dayName, 'Fri') % if the statement evaluates to 1, it's TRUE
    classLocation = 'Meyer'; 
elseif strcmp(dayName, 'Tue') || strcmp(dayName, 'Thu') % if today is tuesday OR thursday
    classLocation = 'HUC';
else
    classLocation = 'NA';
end
% display where class is held today
disp(['Today class is held in: ' classLocation])


%%%% INTERLUDE: 
% OR (||) and AND (&&)


% Test this by manually setting dayName ('Mon', 'Tue', 'Wed', 'Thu', 'Fri')
dayName = 'Wed';
if strcmp(dayName, 'Fri') % if the statement evaluates to 1, it's TRUE
    classLocation = 'Meyer'; 
elseif strcmp(dayName, 'Tue') || strcmp(dayName, 'Thu') % if today is tuesday OR thursday
    classLocation = 'HUC';
else
    classLocation = 'NA';
end
% display where class is held today
disp(['Today class is held in: ' classLocation])

%%%% INTERLUDE: 
% Note dayName is still set to whatever we manually set it to. Be careful
% when assigning the same variable name to a new value. There is no undo!



%% 2 WHILE loops

% example of loading a .mat file into the workspace:
load('loop.mat')
imshow(loopImg)


% Sometimes you want a section of code to be run for a certain amount of
% time, or to run repeatedly as long as a certain condition is met. 
% That's where While loops come in handy!


% To see how long something takes, we can measure elapsed time with "tic"
% and "toc". These can also be helpful when you're trying to figure out 
% what code is more efficient.


tic % start time
while toc <2 % while the elapsed time is less than 2 seconds
    disp(toc) % display elapsed time
end

% (you may want to clear your command window now: clc)


% While loops are also helpful when you're not sure a priori how many
% iterations you need

% say we draw 2 numbers from a random distribution
sample1 = rand
sample2 = rand


% For this example, we want sample2 to be smaller than sample1.
% We can use a while loop to repeatedly pull samples until the condition is
% met.

while sample2>=sample1 % do this as long as sample2 is equal to or larger than sample1
    sample1 = rand
    sample2 = rand
end

% and now we want to incrementally add to sample2 until its larger than
% sample1
while sample2 < sample1
    sample2 = sample2 + .01
end
% this loop will terminate once the initial condition is no longer met.
% another way to do this is to set while to 1 and have an if statement in
% the while loop

% reset the numbers:
sample1 = rand; 
sample2 = sample1/2; %ensure sample 2 starts as smaller

while 1
    if sample2 > sample1
        disp([num2str(sample2) ' is larger than ' num2str(sample1)])
        % num2str converts numbers into strings so that they can be used by
        % functions that require strings
        break
    end
    sample2 = sample2 + .01
end



%% 3 FOR loops

% for loops are useful when you know a priori how many times you want to
% iterate something. Each time the program reaches the end of the code in a
% loop, it starts back up at the top but keeps track of what iteration it
% is currently on. By default, each iteration through the for loop updates
% the counter by 1.

% count to 5
for ii = 1:5
    disp(ii)
end


% fibonicci sequence example: For loops can be helpful with recursive
% functions when the next value in a sequence depends on the previous
% values.

% initialize: why?
fib = [];
% iterate 10 times
for ii = 1:10
    if length(fib) < 2 % if the current length of fib is 0 or 1
        fib(ii) = 1
    else
        fib(ii) = fib(ii-1) + fib(ii-2)
    end
end

% you don't have to iterate by only 1:
for ii = 5:-1:-2 % decrease
    disp(ii)
end

for ii = 0:0.1:1 % increase by non-integers
    disp(ii)
end



% Another example: making code flexible
% Say you're collecting data and storing it in a matrix. Right now you have
% two data vectors, each with 10 values. Let's make that and store it as a
% single matrix: 
nVec = 2;
vecLength = 10;
vecs = rand(vecLength, nVec);

% display the vectors
figure 
% subplot 1
subplot(2,1,1)
stem(vecs(:,1))
title('subplot 1')
% subplot 2
subplot(2,1,2)
stem(vecs(:,2))
title('subplot 2')

% inefficient! What if you collected more vectors? 


%%% Exercise:
% Write some code to display 20 vectors instead of just 2. Have each of the
% subplots be titled like above, and have more than 1 column of subplots.


%%% Indexing instead of for loops:
% Loops are very helpful, and sometimes neccessary-- but they aren't very
% efficient for matlab. When possible, you should use indexing to change
% multiple values in a vector at the same time.

% reminder: you can index into a vector by using parentheses
x = rand(5,1) % create a 5-vector
x(3) % select the 3rd index
x(3) = x(4) % set the value at the 3rd index to the value at the 4th index
x(3) == x(4) % evaluates to 1

%%% Exercise:
% 1. Using a for loop, create a vector that is 1e6 rows where all the values
% are zero except for all indices that are multiples of 3, where the value
% should be 1.
% 2. Do the same thing using indexing
% 3. Using tic/toc, show how much faster indexing is



%% 4 Functions!

% We've been using functions this whole time! ones(), zeros(), rand() --
% these are all functions that matlab has built in, but we can also make
% our own.

% To keep things basic, lets re-create the mean() function -- 
% -- important! name it something other than mean() so you don't overwrite

% To start, go to the EDITOR tab above and click new -> function
% Things to note:
% - the inside of the function will flexibly respond to whatever the input
%   argument is
% - the intermediate values will not exit the function
% - only what you set equal to the output will be output
% - save the function w the same name as in the top line of the function

% Regular scripts are different because all the intermediate values remain
% in the workspace.



%% 5 Review of inner & outer products, matrix multiplication

%Inner products
rowVector = [1 2 3 4];
columnVector = [5;6;7;8]; % or [5 6 7 8]'
innerProduct = rowVector*columnVector
dot(rowVector,columnVector) %Same
sum(rowVector.*columnVector') %Same

% Outer products
outerProduct = columnVector*rowVector

%Matrix multiplication 
A = [1 2; 3 4];
B = [5 6; 7 8];
C = A*B
D = B*A
%Matrix multiplication does not commute. Neither do dot products, as a
%special case of matrix multiplication. Only element-wise multiplication
%commutes
E1 = A.*B
E2 = B.*A
E1 == E2


%% 6 Exercise with while loop, if statements, & dot products
% Let's find 10 orthogonal vectors by random trial and error

orthoCounter=1; %this is our counter of orthogonal vectors
loopCounter=0; %this is our counter iterations

while orthoCounter < 11 % We don't know how many trials we need, so while is suitable
    A=randn(1,2); % draw a 2d row vector randomly from a normal distribution
    B=randn(2,1); % draw a 2d column vector randomly from a normal distribution
    testThem = A*B; % Take inner product
    loopCounter=loopCounter+1; % increase loop count
    if abs(testThem)<0.00001 % Ideally we would want IPs that are exactly zero, but due to MATLAB's numeric systems, very unlikely to happen
        disp('Orthogonal!') % expression of joy
        rowContainer(orthoCounter,:)=A; % capture the row vector
        columnContainer(:,orthoCounter)=B; % capture the corresponding column vector
        orthoCounter=orthoCounter+1; % increase counter
    end
        
end
% The reason I'm showing the next comand is to give an example of how to
% mix charactersand numbers in the same statement
disp(['It took ',num2str(loopCounter), ' repeats to find 10 orthogonal vectors!']);

% Now that we found them, let's plot them
figure 
% Unless you call this explicitly and there is not one open, it will open 
% one for you. Here it is good to open one explicitly. 
for ii=1:10
    plot([0 rowContainer(ii,1)],[0 rowContainer(ii,2)],'color','b') % plot x-piece of row vector
    axis([-2 2 -2 2])  
    
    hold on %Put hold on, otherwise the second vector will overwrite the first one
    plot([0 columnContainer(1,ii)],[0 columnContainer(2,ii)],'color','r')
    hold off
    
    pause % only move on to the next loop on button press
end


%% 7 Rotation example
close all

% Let's generate a bunch of vectors on the x,y coordinate plane, pulled
% from a normal distribution. 
vecs = randn(2,150);

% Sometimes its easier to display vectors as just the end point, not a line
% from the origin to the end point. 
figure
scatter(vecs(1,:), vecs(2,:), 25, 'filled')

% What type of matrix acts as a "rotation"?

% What's special about how they're constructed?


% our degree of rotation
theta = 1/180*pi;  % 1 degree in radians.
%theta=-1/180*pi;  % rotate in other direction

% rotator matrix for our example:
operatorMatrix=[cos(theta) sin(theta);-sin(theta) cos(theta)]; 

% proof this works:
% row 1 * row 2:
% [cos(theta) sin(theta)] * [-sin(theta) cos(theta)]'
% cos(theta)*-sin(theta) + sin(theta)*cos(theta)
% sin(theta)*cos(theta) - sin(theta)*cos(theta) = 0

% col 1 * col 2:
% [cos(theta) -sin(theta)] * [sin(theta) cos(theta)]' --> same thing


% Plot the vectors, multiply them by the rotator matrix, replot
for ii=1:359
    scatter(vecs(1,:), vecs(2,:), 25, 'filled')% plot the endpoints of the vectors, not the vectors
    axis([-5 5 -5 5]) % set axis to cover all the points (w reasonable certainty)
    pause(0.05) % with an argument, pause tells MATLAB how long to wait before moving on, in seconds
    % pause with no argument waits for button press before continuing
    vecs=operatorMatrix*vecs; % operate on the vectors
end

% ~*~ the magic of matlab ~*~

%%% EXERCISE:
% Instead of having the points rotate, get them to gradually condense or expand






%% THE END