clc; clear; close all;

%% Hello everyone, and welcome to ACM 95a/100a
% This is an introduction to MATLAB for ACM 95a/100a.
%% What is MATLAB?
% MATLAB, developed by the Mathworks company, stands for matrix laboratory. It's exceptionally flexible at converting between scalars and matrices, and has a lot of helpful built-in functions for evaluating and plotting data expressed as matrices. We'll be using this in ACM 95a/100a to complement learning complex analysis and differential equations.
% There are two main kinds of MATLAB files you'll have to deal with: live scripts like this one (with a .mlx extension), and m-files (.m). Live scripts let you mix text with code, and

disp('let you see output adjacent to a command.')

% M-files are a more traditional script format, for code and comments that are run in sequence (except for functions, we'll get to that later).
%% How do I use this environment?
% At the top, you'll notice a few tabs. Here's tabs and commands you'll want to know:
% Home: "New Script" will create a new .m file, and "New Live Script" will create a new .mlx file. "Open" is self-explanatory. "Layout" and "Preferences" are nice for customizing how the MATLAB environment is set up. Especially useful is Preferences > Keyboard > Shortcuts where you can set shortcuts, MATLAB has some unconventional defaults.
% You will almost definitely not need Plots, Apps, or Insert for this class.
% Live Editor (for live scripts)/Editor (for m-files): The most useful two sections here are "Section" and "Run." "Section" lets you divide your code into chunks and run them separately, while "Run" simply runs the entire script.
% View: More layout and zoom, try playing around with these to see if you prefer a different view.
% No matter how you set it up, you need at least an Editor or Live Editor (the window you're reading this on), a Workspace to view what variables you have stored, and if using an m-file, a Command Window to view output from the script or quickly test a line or two.
%% Basic MATLAB Properties
%% Variables
% We can assign values to variables just by typing 'variable' = 'value'

ex = 1

% Note this displays the value of our variable "ex". If we want to suppress the output, simply add a semicolon at the end of the line and it will not print.

ex = 1;

% Let's define a row vector:

vec = [1 2 3 4 5 6]

% We can also create this evenly spaced vector using the syntax min:step:max, although since our step has a size of 1, we can simply specify two numbers min:max . This syntax is useful when defining for loops, which we'll get to later.

mat1 = 1:1:6
mat2 = 1:6

% To define a matrix with rows and columns, all we need to do is put a semicolon where we want a row break to be.

mat = [1 2 3; 4 5 6]

% We can also create an empty matrix of zeros of any dimension we want, which is useful when we know the size of our answer but don't know the values and will fill it in throughout the program. Here we use our first function, a pre-written chunk of code we intend to reuse. It takes two inputs, number of rows and number of columns in that order. We can call the function as follows

zero_mat = zeros(3,2)

%% Matrix Operations
% MATLAB is designed to make matrix calculations easy. The syntax is simple: +,-,*,/,^ perform matrix addition, subtraction, multiplication, division, and raising to a power, respectively, while adding "." before any operation performs it elementwise. Always make sure your dimensions are correct! Here is a little example of how to use these.

new_mat = zero_mat + 10
el_wise = new_mat .* 0.5
mat_mul = el_wise * mat

% Basic math functions are built to accommodate both scalars and matrices, which are evaluated elementwise, demonstrated below with the natural log.

log(ex)
log(mat_mul)

%% Loops
% The two loops you will use are \texttt{for} loops and \texttt{while} loops. They have similar structure to both each other and the conditionals.
%% For Loops
% For loops execute the same code block across a given array. If you have coding experience in, for example, Python, this is the same as a for-each loop.
% For loops are useful when we want to repeat something a certain number of times. The syntax of a for loop is shown below--make sure to 'end' a loop once you're done with your operations. The index n runs from start:step:end if you specify three numbers, or start:end with a step size of 1 if you specify two numbers.

n = 20;

x = rand(n,1); % Create an n element row vector
y = log(x);

ynew1 = zeros(n,1);

for i=1:n
    ynew1(i) = y(i) + i;
end

ynew1

%% While Loops
% While loops execute the same code block until a given condition is fulfilled. Here is a while loop that does the same as above.

i = 1;

ynew2 = zeros(n,1);

while i < n + 1
    ynew2(i) = y(i) + i;
    i = i + 1;
end

ynew2

% The real power of a while loop is not to do something more simply achieved with a for loop, but this example is for illustration.
%% Matrix Operations vs For Loops
% We can also see that our loops above simply fulfill the same function as the matrix operation

ynew3 = y + 1

% which is much simpler. This is the strength of MATLAB: always keep an eye out for ways to simplify loops as matrix operations.
%% Conditionals
% Conditionals, or \texttt{if/elseif/else} statements, check for a certain condition before executing a block of code.
% We can create a variable and "decide" what to do depending on its value as follows.

if x(1) > x(end)
    disp('First term is larger.')
    y(1) = 1;
elseif x(end) > x(1)
    disp('Last term is larger.')
    y(end) = 1;
else % they are equal
    disp('First and last terms are equal.')
    y(1) = 1;
    y(end) = 1;
end

%
%% Functions
%% Defining a Function
% Functions in MATLAB must be at the end of the script so please refer to the end of the script for this section.
%% Using a Function
% This structure means we call our function before we define it in the script. Here we use the defined function with output not suppressed by ;

only_one_out = func_name("input")
[out1, out2] = func_name("input")

%% Anonymous Functions
% If we just want a short, one-line function of one or more variables, we can define it as follows:
%  function name = @(variable1, variable2) (expression)
% Here is an example.

smile = @(t) (0.2*t.^2-3);

%% Integral
% We now have a short, simple function saved as \texttt{smile}. We can use this function as an input to other functions to perform operations. One such built-in function is \texttt{integral} which integrates our function. No semicolon intentionally so we can display output. The syntax is as follows:
% output = integral(function name, lower bound, upper bound)

integ = integral(smile, -2, 2)

%% Linspace
% Another very useful built-in method is \texttt{linspace}, which creates a linearly spaced row vector with the syntax:
% outvec = linspace(min, max, step)
% An example is provided below, which we will use with our anonymous function to make a simple plot in the next section.

t = linspace(-2,2,20)

%
%% Plotting
%% Plot
% We will put what we've learned together into a simple plot using linearly spaced vectors and our anonymous function.
% Below, we plot the first curve. We use the linearly spaced vector as an input to our function and style the line. 'b--' means blue and a dashed line style. There are tables of colors and point styles in the MATLAB documentation on the Mathworks website.

plot(t, smile(t),'b--');

% This is great, but we want to add to our plot. We use the command \texttt{hold on} which simply freezes the axes and figure so you keep plotting on the same graph.

hold on;

% Here are some more plotting examples using built-in trig functions and more linearly spaced vectors on the same figure. As you can see, all of these built-in functions handle matrix and scalar inputs as provided. Can you figure out what 'bp' means?

theta = linspace(0,2*pi, 500);
r = 4;
plot(r.*cos(theta),r.*sin(theta),'b');

plot(linspace(-1.5,-1.5,10),linspace(0,2,10),'bp');
plot(linspace(1.5,1.5,10),linspace(0,2,10),'bp');

%% Plot Labeling
% We always want plots to be as descriptive as possible, and there are a lot of ways to add information to plots in MATLAB.
% We can label axes

xlabel("x");
ylabel("y");

% and create a legend. We can simply use the \texttt{legend} function without the \texttt{Location} specification or any of these specifications, they are included so you know they exist.

lgd = legend;
lgd.FontSize = 10;
lgd.Title.String = 'Legend Title';
legend('smile','face','right eye','left eye','Location','bestoutside');
title('Smiley Face')

%% Scatterplot
% We can make a variety of plots. Here is an example of a scatter plot, using math typesetting markup langauge LaTeX as an interpreter for the labels to add equations.
% Note that we start with the \texttt{figure}. We need this command (or a \texttt{hold off}) to end the previous \texttt{hold on} so we create a new figure and don't continue plotting on the same figure as the smiley face.

n = 20;

X = 100*rand(n,1);
Y = exp(X/2);

figure;
scatter(X,Y,'filled');
title('Scatter Example')
ylabel('$e^{\frac{x}{2}}$','Interpreter','latex')
xlabel('$x$','Interpreter',"latex")

%% Logplot
% However, this plot isn't very illustrative. The large y values as x gets close to 100 stretch the axis and make it hard to see the smaller y values. We can visualize this data better by log-scaling the y-axis. Log-scaling the y-axis addresses skewness towards large values and helps visualize percent change with exponential growth.
% There are two ways we can do this.
%% Log Axis

figure;
plot(X,Y,'b-x','LineWidth',1); 
axis(gca); % GCA refers to current axes
set(gca, 'YScale', 'log');
hold off;
ylabel('$e^{\frac{x}{2}}$','Interpreter','latex')
xlabel('$x$','Interpreter',"latex")


%% Semilog y

figure;
semilogy(X,Y,'m:x','LineWidth',1); 
ylabel('$e^{\frac{x}{2}}$','Interpreter','latex')
xlabel('$x$','Interpreter',"latex")

%
%% Set Skills
% Now we will delve into some MATLAB skills you'll use in sets. However: before anything, if there is the name of a function in the set, your first step should always be searching that function to read the MATLAB documentation on the Mathworks website.
%% Throwing an Error
% Sometimes we want to stop execution of the code if a certain condition is met. We call this "throwing an error." This is the basic syntax to "throw" an error in MATLAB. Errors can be useful when a function gets a bad input and it isn't worth it to try and handle this bad input.

% Try commenting out each x separately and re-running the section!

% x = 1;
x = 2;
if x == 1
    error('Example error');
end

%
%% ODE Numerical Solution
% Broad steps for all of these:
% Create function for steps
% Create initial condition and timestep variables
% Create a time vector
% Create a vector to put the generated y_n's in
% Loop through the time vector and use the function to make the y_n's
%% Solving 1st order IVPs using ode45
% Consider the following 1st order IVP y' = f(y,t) ; y(t_0) = y_0.
% In Matlab, we can solve it numerically using the \texttt{ode45} solver. Matlab has several first order ODE solvers, including \texttt{ode23}, \texttt{ode113}, and \texttt{ode45}. As a rule of thumb, Matlab recommends \texttt{ode45} as the first solver one should try. It implements the Runge-Kutta method and provides a good trade-off between accuracy and speed.
% First, define the interval on which you want to find the solution:
% \texttt{tspan} = [t_0, t_1];
% Here t_1 can be larger or smaller than t_0. Next, define the function f(y,t) on the right-hand-side of the ODE:
% \texttt{f=@(t,y) f(t,y);}
% Definbe the initial condition:
% \texttt{y0=$y_0$;}
% Note that \texttt{ode45} always interprets \texttt{y0} as the value of the solution at the first element of vector \texttt{tspan}. So, if you are interested in the solution on the interval [t_1, t_2], but the initial value y_0 is given at t_0\in[t_1, t_2], then you will have to call \texttt{ode45} twice: for \texttt{tspan1} = [t_0, t_1] and for \texttt{tspan1} = [t_0, t_2], and then "glue" two solutions together.
% The numerical solution can then be found by executing
% \texttt{[t,y]=ode45(f,tspan,y0);}
% Here \texttt{t} is a vector representing the discretization of the interval \texttt{tspan}, where the first element of \texttt{t} is \texttt{tspan(1)=$t_0$} and the last element of \texttt{t} is \texttt{tspan(2)=$t_1$}, and y is the numerical solution, where \texttt{y(i)}is the approximation of the solution at time \texttt{t(i)}.
%% Example
% Here is an example of solving IVP y'+y = 0 ; y(0) = 1 on the interval [0,1]:

tspan_example=[0,1];
f_example=@(t,y) -y;
y0_example=1;
[t_example,y_example]=ode45(f_example,tspan_example,y0_example);

%
%% Visualizing a Third Variable Using Color
% We have learned about color and line styles, but sometimes we want to visualize a third variable using color. In the example below, we use a function (scroll down to the end to read and understand it) to give us a color value for given x and y values which we then use as another property in the \texttt{scatter} function as shown below. We use the \texttt{colorbar} command to make a key for the color values.

figure;

x = rand(1,500);
y = rand(1,500);

% Define a vector of color values using a function we define below
c = cf(x,y);

% Create a scatter plot with x, y, [] as input size, and log(c) as color
% We need the placeholder for size because while MATLAB is flexible about
% your number of inputs, it has a set order you must use. Since color is a
% later input than size, we need the placeholder.
s = scatter(x,y,[],log(c),'filled');

% Title the graph and add x and y axes
title('Example Colorbar Scatter Plot');
xlabel('x');
ylabel('y');
% Add a key for the colors
colorbar;

%
%% TO DO Matrix Operations vs For Loops More Advanced
% We saw an example early on of how matrix operations can simplify repeated tasks in for loops. Sometimes, however, the for loop is easier. A task that is a good example of both of these is using time stepping to solve for elements in a series defined by a recursion relation, which is shown below.
% Let's try to find the first 20 elements in the series defined by the recursion relation:
% a_{n+1} = 2 * a_n; a_1 = 1.
% We begin by pre-allocating our arrays, which saves time.

n = linspace(1, 20, 20);
a = zeros(1, 20);
a(1) = 1;

%  We can find each subsequent element in the series using a loop. The loop is simpler here because we are using each element to find the next one, and a loop saves complicated vector slicing.

for i = 1:19
    a(i+1) = 2 * a(i);
end

% This series looks like the function x(t) = 2^{t-1}. We can plot the two against each other.

t = linspace(1, 20, 40);
x = 2.^(t-1);

figure;
plot(n, a, '-^');
hold on
plot(t, x, ':*');
hold off
legend('recursion', 'geometric'); 
title('Recursion Relation Example 1')
ylabel('$a_n$','Interpreter','latex')
xlabel('$n$','Interpreter',"latex")

% We can try a more complex recursion relation as well.
% a_{n+1} = 2  a_n - \frac{n^2}{a_n}; a_1 = 1.
% We can use the same procedure as earlier as it's easiest to define the right hand side of the equation as its own function, so we can calculate each subsequent element using the function defined on the right, which we define as an anonymous function.

f = @(n, a) (2 * a - (n.^2)./a);

% Note it's good practice to use matrix operations (.^ or ./ for example) when defining functions so they're scalable.

n2 = linspace(1, 20, 20);
a2 = zeros(1, 20);
a2(1) = 1;

% Using a for loop is still the simplest way to find the next elements.

for i = 1:19
    a2(i+1) = f(i, a2(i));
end

% And once again we plot.

figure;
plot(n2, a2);
title('Recursion Relation Example 2')
ylabel('$a_n$','Interpreter','latex')
xlabel('$n$','Interpreter',"latex")

%
%% Functions
% This is a very basic function where everything is named what it is for simplicity. There are two ways to formally define a function in MATLAB: either as (a) the only content of a file with the same name as the function or (b) as you see here, at the end of a file with a different name. Functions defined as (a) can be called from outside the file, but functions of type (b) cannot. As you can see, we have two outputs and one input. If we call it with one output variable, we will only retrieve the first output.

function [output1, output2] = func_name(input)
    output1 = strcat("This is your output based on ",input);
    output2 = 40;
end

% Here is another function that we will use later in the code. Note the explanatory comments: this kind of structured comment explaining inputs and outputs is useful for future you referencing old code and others (including grading TAs ;) ) reading code you wrote.

% cf: function to calculate color value
% Input:
%   x: Cartesian x value vector
%   y: Cartesian y value vector
% Output:
%   color: vector containing calculated color values
function color = cf(x,y)
    color = abs((2.5 .* x - y)./(1025 .* (x + y)));
end