```python
%matplotlib inline
```

```python
# Write your imports here
import numpy as np
```

# High-School Maths Exercise
## Getting to Know Jupyter Notebook. Python Libraries and Best Practices. Basic Workflow

### Problem 1. Markdown
Jupyter Notebook is a very light, beautiful and convenient way to organize your research and display your results. Let's play with it for a while.

First, you can double-click each cell and edit its content. If you want to run a cell (that is, execute the code inside it), use Cell > Run Cells in the top menu or press Ctrl + Enter.

Second, each cell has a type. There are two main types: Markdown (which is for any kind of free text, explanations, formulas, results... you get the idea), and code (which is, well... for code :D).

Let me give you a...
#### Quick Introduction to Markdown
##### Text and Paragraphs
There are several things that you can do. As you already saw, you can write paragraph text just by typing it. In order to create a new paragraph, just leave a blank line. See how this works below:
```
This is some text.
This text is on a new line, but it will continue the same paragraph (so you can make your paragraphs more easily readable by just continuing on a new line, or just go on and on like this one line is ever continuing).

This text is displayed in a new paragraph.

And this is yet another paragraph.
```
**Result:**

This is some text.
This text is on a new line, but it will continue the same paragraph (so you can make your paragraphs more easily readable by just continuing on a new line, or just go on and on like this one line is ever continuing).

This text is displayed in a new paragraph.

And this is yet another paragraph.

##### Headings
There are six levels of headings. Level one is the highest (largest and most important), and level 6 is the smallest. You can create headings of several types by prefixing the header line with one to six "#" symbols (this is called a pound sign if you are ancient, or a sharp sign if you're a musician... or a hashtag if you're too young :D). Have a look:
```
# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6
```

**Result:**

# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6

It is recommended that you have **only one** H1 heading - this should be the header of your notebook (or scientific paper). Below that, you can add your name or just jump to the explanations directly.

##### Emphasis
You can create emphasized (stonger) text by using a **bold** or _italic_ font. You can do this in several ways (using asterisks (\*) or underscores (\_)). In order to "escape" a symbol, prefix it with a backslash (\). You can also strike thorugh your text in order to signify a correction.
```
**bold** __bold__
*italic* _italic_

This is \*\*not \*\* bold.

I ~~didn't make~~ a mistake.
```

**Result:**

**bold** __bold__
*italic* _italic_

This is \*\*not\*\* bold.

I ~~didn't make~~ a mistake.

##### Lists
You can add two types of lists: ordered and unordered. Lists can also be nested inside one another. To do this, press Tab once (it will be converted to 4 spaces).

To create an ordered list, just type the numbers. Don't worry if your numbers are wrong - Jupyter Notebook will create them properly for you. Well, it's better to have them properly numbered anyway...
```
1. This is
2. A list
10. With many
9. Items
    1. Some of which
    2. Can
        3. Be nested
42. You can also
    * Mix
    * list
    * types
```

**Result:**
1. This is
2. A list
10. With many
9. Items
    1. Some of which
    2. Can
        3. Be nested
42. You can also
    * Mix
    * list
    * types

To create an unordered list, type an asterisk, plus or minus at the beginning:
```
* This is
* An
    + Unordered
    - list
```

**Result:**
* This is
* An
    + Unordered
        - list

##### Links
There are many ways to create links but we mostly use one of them: we present links with some explanatory text. See how it works:
```
This is [a link](http://google.com) to Google.
```

**Result:**

This is [a link](http://google.com) to Google.

##### Images
They are very similar to links. Just prefix the image with an exclamation mark. The alt(ernative) text will be displayed if the image is not available. Have a look (hover over the image to see the title text):
```

```

**Result:**

If you want to resize images or do some more advanced stuff, just use HTML.

Did I mention these cells support HTML, CSS and JavaScript? Now I did.

##### Tables
These are a pain because they need to be formatted (somewhat) properly. Here's a good [table generator](http://www.tablesgenerator.com/markdown_tables). Just select File > Paste table data... and provide a tab-separated list of values. It will generate a good-looking ASCII-art table for you.
```
| Cell1 | Cell2 | Cell3 |
|-------|-------|-------|
| 1.1   | 1.2   | 1.3   |
| 2.1   | 2.2   | 2.3   |
| 3.1   | 3.2   | 3.3   |
```

**Result:**

| Cell1 | Cell2 | Cell3 |
|-------|-------|-------|
| 1.1   | 1.2   | 1.3   |
| 2.1   | 2.2   | 2.3   |
| 3.1   | 3.2   | 3.3   |

##### Code
Just use triple backtick symbols. If you provide a language, it will be syntax-highlighted. You can also use inline code with single backticks.

```python
def square(x):
    return x ** 2
```
This is `inline` code. No syntax highlighting here.

**Result:**
```python
def square(x):
    return x ** 2
```
This is `inline` code. No syntax highlighting here.

**Now it's your turn to have some Markdown fun.** In the next cell, try out some of the commands. You can just throw in some things, or do something more structured (like a small notebook).

# Math for devs
## Author: Antonio DIchev

This is a list:
* 1
* 2
* 3

| Cell1 | Cell2 | Cell3 |
|-------|-------|-------|
| 1.1   | 1.2   | 1.3   |
| 2.1   | 2.2   | 2.3   |
| 3.1   | 3.2   | 3.3   |

### Problem 2. Formulas and LaTeX
Writing math formulas has always been hard. But scientists don't like difficulties and prefer standards. So, thanks to Donald Knuth (a very popular computer scientist, who also invented a lot of algorithms), we have a nice typesetting system, called LaTeX (pronounced _lah_-tek). We'll be using it mostly for math formulas, but it has a lot of other things to offer.

There are two main ways to write formulas. You could enclose them in single `$` signs like this: `$ ax + b $`, which will create an **inline formula**: $ ax + b $. You can also enclose them in double `$` signs `$$ ax + b $$` to produce $$ ax + b $$.

Most commands start with a backslash and accept parameters either in square brackets `[]` or in curly braces `{}`. For example, to make a fraction, you typically would write `$$ \frac{a}{b} $$`: $$ \frac{a}{b} $$.

[Here's a resource](http://www.stat.pitt.edu/stoffer/freetex/latex%20basics.pdf) where you can look up the basics of the math syntax. You can also search StackOverflow - there are all sorts of solutions there.

You're on your own now. Research and recreate all formulas shown in the next cell. Try to make your cell look exactly the same as mine. It's an image, so don't try to cheat by copy/pasting :D.

Note that you **do not** need to understand the formulas, what's written there or what it means. We'll have fun with these later in the course.

$$y=ax+b$$

$$ax^2+bx+c=0$$

$$x_{1,2}= \frac{-b\pm \sqrt{b^2-4ac}}{2a}$$

$$f(x)|_{x=a} = f(a)+f'(a)(x-a)+\frac{f''(a)}{2!}(x-a)^2+...+\frac{f^(n)(a)}{n!}(x-a)^n+...$$

$$(x+y)^n=\begin{pmatrix}n\\0\end{pmatrix}x^ny^0+\begin{pmatrix}n\\1\end{pmatrix}x^1y^{n-1}+...\begin{pmatrix}n\\n\end{pmatrix}x^0y^{n}=\sum^n\limits_{k=0}\begin{pmatrix}n\\k\end{pmatrix}x^{n-k}y^{k} $$

$$\int_{-\infty}^{+\infty}e^{-x^2}dx=\sqrt\pi$$

$$\begin{pmatrix}
2 & 1 & 3 \\
2 & 6 & 8 \\
6 & 8 & 18
\end{pmatrix} $$

$$A = \begin{bmatrix}
    a_{11} & a_{12} & \dots & a_{1n}  \\
    a_{21} & a_{22} & \dots & a_{2n}  \\
    \vdots & \vdots & \ddots & \vdots \\
    a_{m1} & a_{m2} & \dots & a_{mn}  \\
    \end{bmatrix}$$

### Problem 3. Solving with Python
Let's first do some symbolic computation. We need to import `sympy` first.

**Should your imports be in a single cell at the top or should they appear as they are used?** There's not a single valid best practice. Most people seem to prefer imports at the top of the file though. **Note: If you write new code in a cell, you have to re-execute it!**

Let's use `sympy` to give us a quick symbolic solution to our equation. First import `sympy` (you can use the second cell in this notebook):
```python
import sympy
```

Next, create symbols for all variables and parameters. You may prefer to do this in one pass or separately:
```python
x = sympy.symbols('x')
a, b, c = sympy.symbols('a b c')
```

Now solve:
```python
sympy.solve(a * x**2 + b * x + c)
```

Hmmmm... we didn't expect that :(. We got an expression for $a$ because the library tried to solve for the first symbol it saw. This is an equation and we have to solve for $x$. We can provide it as a second paramter:
```python
sympy.solve(a * x**2 + b * x + c, x)
```

Finally, if we use `sympy.init_printing()`, we'll get a LaTeX-formatted result instead of a typed one. This is very useful because it produces better-looking formulas.

How about a function that takes $a, b, c$ (assume they are real numbers, you don't need to do additional checks on them) and returns the **real** roots of the quadratic equation?

Remember that in order to calculate the roots, we first need to see whether the expression under the square root sign is non-negative.

If $b^2 - 4ac > 0$, the equation has two real roots: $x_1, x_2$

If $b^2 - 4ac = 0$, the equation has one real root: $x_1 = x_2$

If $b^2 - 4ac < 0$, the equation has zero real roots

Write a function which returns the roots. In the first case, return a list of 2 numbers: `[2, 3]`. In the second case, return a list of only one number: `[2]`. In the third case, return an empty list: `[]`.

```python
import math
def solve_quadratic_equation(a, b, c):
    """
    Returns the real solutions of the quadratic equation ax^2 + bx + c = 0
    """
    D = b**2 - 4*a*c

    if D < 0:
        return []
    elif D == 0:
        x = (-b+math.sqrt(b**2-4*a*c))/2*a
        return x
    else:
        x1 = (-b-math.sqrt(b**2-4*a*c))/2*a
        x2 = (-b+math.sqrt(b**2-4*a*c))/2*a
        return x1, x2
```

```python
# Testing: Execute this cell. The outputs should match the expected outputs. Feel free to write more tests
print(solve_quadratic_equation(1, -1, -2)) # [-1.0, 2.0]
print(solve_quadratic_equation(1, -8, 16)) # [4.0]
print(solve_quadratic_equation(1, 1, 1)) # []
```

    (-1.0, 2.0)
    4.0
    []

**Bonus:** Last time we saw how to solve a linear equation. Remember that linear equations are just like quadratic equations with $a = 0$. In this case, however, division by 0 will throw an error. Extend your function above to support solving linear equations (in the same way we did it last time).

### Problem 4. Equation of a Line
Let's go back to our linear equations and systems. There are many ways to define what "linear" means, but they all boil down to the same thing.

The equation $ax + b = 0$ is called *linear* because the function $f(x) = ax+b$ is a linear function. We know that there are several ways to know what one particular function means. One of them is to just write the expression for it, as we did above. Another way is to **plot** it. This is one of the most exciting parts of maths and science - when we have to fiddle around with beautiful plots (although not so beautiful in this case).

The function produces a straight line and we can see it.

How do we plot functions in general? Ww know that functions take many (possibly infinitely many) inputs. We can't draw all of them. We could, however, evaluate the function at some points and connect them with tiny straight lines. If the points are too many, we won't notice - the plot will look smooth.

Now, let's take a function, e.g. $y = 2x + 3$ and plot it. For this, we're going to use `numpy` arrays. This is a special type of array which has two characteristics:
* All elements in it must be of the same type
* All operations are **broadcast**: if `x = [1, 2, 3, 10]` and we write `2 * x`, we'll get `[2, 4, 6, 20]`. That is, all operations are performed at all indices. This is very powerful, easy to use and saves us A LOT of looping.

There's one more thing: it's blazingly fast because all computations are done in C, instead of Python.

First let's import `numpy`. Since the name is a bit long, a common convention is to give it an **alias**:
```python
import numpy as np
```

Import that at the top cell and don't forget to re-run it.

Next, let's create a range of values, e.g. $[-3, 5]$. There are two ways to do this. `np.arange(start, stop, step)` will give us evenly spaced numbers with a given step, while `np.linspace(start, stop, num)` will give us `num` samples. You see, one uses a fixed step, the other uses a number of points to return. When plotting functions, we usually use the latter. Let's generate, say, 1000 points (we know a straight line only needs two but we're generalizing the concept of plotting here :)).
```python
x = np.linspace(-3, 5, 1000)
```
Now, let's generate our function variable
```python
y = 2 * x + 3
```

We can print the values if we like but we're more interested in plotting them. To do this, first let's import a plotting library. `matplotlib` is the most commnly used one and we usually give it an alias as well.
```python
import matplotlib.pyplot as plt
```

Now, let's plot the values. To do this, we just call the `plot()` function. Notice that the top-most part of this notebook contains a "magic string": `%matplotlib inline`. This hints Jupyter to display all plots inside the notebook. However, it's a good practice to call `show()` after our plot is ready.
```python
plt.plot(x, y)
plt.show()
```

```python
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-3, 5, 1000)
y = 2 * x + 3
plt.plot(x, y)
plt.show()
```

It doesn't look too bad bit we can do much better. See how the axes don't look like they should? Let's move them to zeto. This can be done using the "spines" of the plot (i.e. the borders).

All `matplotlib` figures can have many plots (subfigures) inside them. That's why when performing an operation, we have to specify a target figure. There is a default one and we can get it by using `plt.gca()`. We usually call it `ax` for "axis".
Let's save it in a variable (in order to prevent multiple calculations and to make code prettier). Let's now move the bottom and left spines to the origin $(0, 0)$ and hide the top and right one.
```python
ax = plt.gca()
ax.spines["bottom"].set_position("zero")
ax.spines["left"].set_position("zero")
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
```

**Note:** All plot manipulations HAVE TO be done before calling `show()`. It's up to you whether they should be before or after the function you're plotting.

This should look better now. We can, of course, do much better (e.g. remove the double 0 at the origin and replace it with a single one), but this is left as an exercise for the reader :).

```python
plt.plot(x, y)
ax = plt.gca()
ax.spines["bottom"].set_position("zero")
ax.spines["left"].set_position("zero")
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
plt.show()
```

### * Problem 5. Linearizing Functions
Why is the line equation so useful? The main reason is because it's so easy to work with. Scientists actually try their best to linearize functions, that is, to make linear functions from non-linear ones. There are several ways of doing this. One of them involves derivatives and we'll talk about it later in the course.

A commonly used method for linearizing functions is through algebraic transformations. Try to linearize
$$ y = ae^{bx} $$

Hint: The inverse operation of $e^{x}$ is $\ln(x)$. Start by taking $\ln$ of both sides and see what you can do. Your goal is to transform the function into another, linear function. You can look up more hints on the Internet :).

$$\ln y=b*x+\ln a$$

### * Problem 6. Generalizing the Plotting Function
Let's now use the power of Python to generalize the code we created to plot. In Python, you can pass functions as parameters to other functions. We'll utilize this to pass the math function that we're going to plot.

Note: We can also pass *lambda expressions* (anonymous functions) like this:
```python
lambda x: x + 2```
This is a shorter way to write
```python
def some_anonymous_function(x):
    return x + 2
```

We'll also need a range of x values. We may also provide other optional parameters which will help set up our plot. These may include titles, legends, colors, fonts, etc. Let's stick to the basics now.

Write a Python function which takes another function, x range and number of points, and plots the function graph by evaluating it at every point.

**BIG hint:** If you want to use not only `numpy` functions for `f` but any one function, a very useful (and easy) thing to do, is to vectorize the function `f` (e.g. to allow it to be used with `numpy` broadcasting):
```python
f_vectorized = np.vectorize(f)
y = f_vectorized(x)
```

```python
def plot_math_function(f, min_x, max_x, num_points):

        f_vectorized = np.vectorize(f)
        x=np.linspace(min_x,max_x,num_points)
        y = f_vectorized(x)

        plt.plot(x, y)
        ax = plt.gca()
        ax.spines["bottom"].set_position("zero")
        ax.spines["left"].set_position("zero")
        ax.spines["top"].set_visible(False)
        ax.spines["right"].set_visible(False)
        plt.show()
```

```python
#x = np.linspace(-15,15,100) # 100 linearly spaced numbers
#y = np.sin(x)/x # computing the values of sin(x)/x

# compose plot
#plt.plot(x,y) # sin(x)/x
#plt.plot(x,y,'co') # same function with cyan dots
#plt.plot(x,2*y,x,3*y) # 2*sin(x)/x and 3*sin(x)/x
#plt.show() # show the plot
```

```python

```

```python
plot_math_function(lambda x: 2 * x + 3, -3, 5, 1000)
plot_math_function(lambda x: -x + 8, -1, 10, 1000)
plot_math_function(lambda x: x**2 - x - 2, -3, 4, 1000)
plot_math_function(lambda x: np.sin(x), -np.pi, np.pi, 1000)
plot_math_function(lambda x: np.sin(x) / x, -4 * np.pi, 4 * np.pi, 1000)
```

### * Problem 7. Solving Equations Graphically
Now that we have a general plotting function, we can use it for more interesting things. Sometimes we don't need to know what the exact solution is, just to see where it lies. We can do this by plotting the two functions around the "=" sign ans seeing where they intersect. Take, for example, the equation $2x + 3 = 0$. The two functions are $f(x) = 2x + 3$ and $g(x) = 0$. Since they should be equal, the point of their intersection is the solution of the given equation. We don't need to bother marking the point of intersection right now, just showing the functions.

To do this, we'll need to improve our plotting function yet once. This time we'll need to take multiple functions and plot them all on the same graph. Note that we still need to provide the $[x_{min}; x_{max}]$ range and it's going to be the same for all functions.

```python
vectorized_fs = [np.vectorize(f) for f in functions]
ys = [vectorized_f(x) for vectorized_f in vectorized_fs]
```

```python
def plot_math_functions(functions, min_x, max_x, num_points):

        vectorized_fs = [np.vectorize(f) for f in functions]
        x=np.linspace(min_x,max_x,num_points)

        ys = [vectorized_f(x) for vectorized_f in vectorized_fs]

        #y = [y for y in ys]

        for i in ys: #ys is my range of y values on the chart
            plt.plot(x, i)
        ax = plt.gca()
        ax.spines["bottom"].set_position("zero")
        ax.spines["left"].set_position("zero")
        ax.spines["top"].set_visible(False)
        ax.spines["right"].set_visible(False)
        plt.show()

```

```python
plot_math_functions([lambda x: 2 * x + 3, lambda x: 0], -3, 5, 1000)
plot_math_functions([lambda x: 3 * x**2 - 2 * x + 5, lambda x: 3 * x + 7], -2, 3, 1000)
```

This is also a way to plot the solutions of systems of equation, like the one we solved last time. Let's actually try it.

```python
plot_math_functions([lambda x: (-4 * x + 7) / 3, lambda x: (-3 * x + 8) / 5, lambda x: (-x - 1) / -2], -1, 4, 1000)
```

### Problem 8. Trigonometric Functions
We already saw the graph of the function $y = \sin(x)$. But, how do we define the trigonometric functions once again? Let's quickly review that.

The two basic trigonometric functions are defined as the ratio of two sides:
$$ \sin(x) = \frac{\text{opposite}}{\text{hypotenuse}} $$
$$ \cos(x) = \frac{\text{adjacent}}{\text{hypotenuse}} $$

And also:
$$ \tan(x) = \frac{\text{opposite}}{\text{adjacent}} = \frac{\sin(x)}{\cos(x)} $$
$$ \cot(x) = \frac{\text{adjacent}}{\text{opposite}} = \frac{\cos(x)}{\sin(x)} $$

This is fine, but using this, "right-triangle" definition, we're able to calculate the trigonometric functions of angles up to $90^\circ$. But we can do better. Let's now imagine a circle centered at the origin of the coordinate system, with radius $r = 1$. This is called a "unit circle".

We can now see exactly the same picture. The $x$-coordinate of the point in the circle corresponds to $\cos(\alpha)$ and the $y$-coordinate - to $\sin(\alpha)$. What did we get? We're now able to define the trigonometric functions for all degrees up to $360^\circ$. After that, the same values repeat: these functions are **periodic**:
$$ \sin(k.360^\circ + \alpha) = \sin(\alpha), k = 0, 1, 2, \dots $$
$$ \cos(k.360^\circ + \alpha) = \cos(\alpha), k = 0, 1, 2, \dots $$

We can, of course, use this picture to derive other identities, such as:
$$ \sin(90^\circ + \alpha) = \cos(\alpha) $$

A very important property of the sine and cosine is that they accept values in the range $(-\infty; \infty)$ and produce values in the range $[-1; 1]$. The two other functions take values in the range $(-\infty; \infty)$ **except when their denominators are zero** and produce values in the same range.

#### Radians
A degree is a geometric object, $1/360$th of a full circle. This is quite inconvenient when we work with angles. There is another, natural and intrinsic measure of angles. It's called the **radian** and can be written as $\text{rad}$ or without any designation, so $\sin(2)$ means "sine of two radians".

It's defined as *the central angle of an arc with length equal to the circle's radius* and $1\text{rad} \approx 57.296^\circ$.

We know that the circle circumference is $C = 2\pi r$, therefore we can fit exactly $2\pi$ arcs with length $r$ in $C$. The angle corresponding to this is $360^\circ$ or $2\pi\ \text{rad}$. Also, $\pi rad = 180^\circ$.

(Some people prefer using $\tau = 2\pi$ to avoid confusion with always multiplying by 2 or 0.5 but we'll use the standard notation here.)

**NOTE:** All trigonometric functions in `math` and `numpy` accept radians as arguments. In order to convert between radians and degrees, you can use the relations $\text{[deg]} = 180/\pi.\text{[rad]}, \text{[rad]} =  \pi/180.\text{[deg]}$. This can be done using `np.deg2rad()` and `np.rad2deg()` respectively.

#### Inverse trigonometric functions
All trigonometric functions have their inverses. If you plug in, say $\pi/4$ in the $\sin(x)$ function, you get $\sqrt{2}/2$. The inverse functions (also called, arc-functions) take arguments in the interval $[-1; 1]$ and return the angle that they correspond to. Take arcsine for example:
$$ \arcsin(y) = x: sin(y) = x $$
$$ \arcsin\left(\frac{\sqrt{2}}{2}\right) = \frac{\pi}{4} $$

Please note that this is NOT entirely correct. From the relations we found:
$$\sin(x) = sin(2k\pi + x), k = 0, 1, 2, \dots $$

it follows that $\arcsin(x)$ has infinitely many values, separated by $2k\pi$ radians each:
$$ \arcsin\left(\frac{\sqrt{2}}{2}\right) = \frac{\pi}{4} + 2k\pi, k = 0, 1, 2, \dots $$

In most cases, however, we're interested in the first value (when $k = 0$). It's called the **principal value**.

Note 1: There are inverse functions for all four basic trigonometric functions: $\arcsin$, $\arccos$, $\arctan$, $\text{arccot}$. These are sometimes written as $\sin^{-1}(x)$, $cos^{-1}(x)$, etc. These definitions are completely equivalent.

Just notice the difference between $\sin^{-1}(x) := \arcsin(x)$ and $\sin(x^{-1}) = \sin(1/x)$.

#### Exercise
Use the plotting function you wrote above to plot the inverse trigonometric functions.

```python
plot_math_functions([lambda x:np.arcsin(x)], -1, 1, 1000)
plot_math_functions([lambda x:np.arccos(x)], -1, 1, 1000)
plot_math_functions([lambda x:np.arctan(x)], -1, 1, 1000)
plot_math_functions([lambda x:np.arctan(1/x)], -1, 1, 1000)
```

```python
def plot_circle(x_c, y_c, r):
    """
    Plots the circle with center C(x_c; y_c) and radius r.
    This corresponds to plotting the equation x^2 + y^2 = r^2
    """
    ##(x−x_c)**2 + (y−y_c)**2 = r**2

    x = np.linspace(-r+x_c,r+x_c,1000)
    y = y_c+np.sqrt(-(x-x_c)**2+r**2)
    y2 = y_c-np.sqrt(-(x-x_c)**2+r**2)
    plt.plot(x, y,'b')
    plt.plot(x, y2,'b')
    plt.gca().set_aspect('equal')
    plt.show()
```

```python
plot_circle(300, 300, 600)
```

### ** Problem 9. Perlin Noise
This algorithm has many applications in computer graphics and can serve to demonstrate several things... and help us learn about math, algorithms and Python :).
#### Noise
Noise is just random values. We can generate noise by just calling a random generator. Note that these are actually called *pseudorandom generators*. We'll talk about this later in this course.
We can generate noise in however many dimensions we want. For example, if we want to generate a single dimension, we just pick N random values and call it a day. If we want to generate a 2D noise space, we can take an approach which is similar to what we already did with `np.meshgrid()`.

$$ \text{noise}(x, y) = N, N \in [n_{min}, n_{max}] $$

This function takes two coordinates and returns a single number N between $n_{min}$ and $n_{max}$. (This is what we call a "scalar field").

Random variables are always connected to **distributions**. We'll talk about these a great deal but now let's just say that these define what our noise will look like. In the most basic case, we can have "uniform noise" - that is, each point in our little noise space $[n_{min}, n_{max}]$ will have an equal chance (probability) of being selected.

#### Perlin noise
There are many more distributions but right now we'll want to have a look at a particular one. **Perlin noise** is a kind of noise which looks smooth. It looks cool, especially if it's colored. The output may be tweaked to look like clouds, fire, etc. 3D Perlin noise is most widely used to generate random terrain.

#### Algorithm
... Now you're on your own :). Research how the algorithm is implemented (note that this will require that you understand some other basic concepts like vectors and gradients).

#### Your task
1. Research about the problem. See what articles, papers, Python notebooks, demos, etc. other people have created
2. Create a new notebook and document your findings. Include any assumptions, models, formulas, etc. that you're using
3. Implement the algorithm. Try not to copy others' work, rather try to do it on your own using the model you've created
4. Test and improve the algorithm
5. (Optional) Create a cool demo :), e.g. using Perlin noise to simulate clouds. You can even do an animation (hint: you'll need gradients not only in space but also in time)
6. Communicate the results (e.g. in the Softuni forum)

Hint: [This](http://flafla2.github.io/2014/08/09/perlinnoise.html) is a very good resource. It can show you both how to organize your notebook (which is important) and how to implement the algorithm.


##### Copyright 2020 The Cirq Developers

```
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
```

# Ion Device Class

    View on QuantumAI

    Run in Google Colab

    View source on GitHub

    Download notebook

The `IonDevice` represents a trapped ion quantum computer with all-to-all qubit connectivity.  The number of qubits as well as the duration of gates and measurements are specified by the user when creating an ion device.

Two-qubit gates are implemented by an Ising-type coupling known as the *Mølmer–Sørensen* gate. The Mølmer–Sørensen gate couples ions through the shared motional modes of the ion chain.  The ion motion and internal state decouples at the end of each gate. The `IonDevice` class assumes this decoupling is perfect and does not explicitly model the ion motion.

```
try:
    import cirq
except ImportError:
    print("installing cirq...")
    !pip install cirq --quiet
    print("installed cirq.")
    import cirq

import numpy as np
```

## Defining an `IonDevice`

To define an `IonDevice`, we specify

- The set of qubits in the device,
- The duration of single-qubit gates,
- The duration of two-qubit gates, and
- The duration of measurement gates.

The code below creates an `IonDevice` with four qubits in a linear array. The durations we use for each type of gate are reasonable order-of-magnitude estimates, though they will differ for different trapped ion computers.

```
"""Create an IonDevice."""
ion_device = cirq.IonDevice(
    qubits=cirq.LineQubit.range(4),
    oneq_gates_duration=cirq.Duration(micros=10),
    twoq_gates_duration=cirq.Duration(micros=200),
    measurement_duration=cirq.Duration(micros=100)
)
```

We can view some properties of the `ion_device` as shown below.

```
"""View some properties of the device."""
# Display the ion device.
print("Ion Device:\n", ion_device)

# Get all qubits in the device.
print("\nQubits in the IonDevice:\n", sorted(ion_device.qubits))

# Get a qubit at a certain position (if present).
pos = 2
print(f"\nQubit at position {pos}:\n", ion_device.at(pos))
```

    Ion Device:
     0───1───2───3

    Qubits in the IonDevice:
     [cirq.LineQubit(0), cirq.LineQubit(1), cirq.LineQubit(2), cirq.LineQubit(3)]

    Qubit at position 2:
     2

## Native Gate Set

An `IonDevice` can implement single-qubit rotations about the $X$, $Y$, and $Z$ axes of the Bloch sphere: namely, `cirq.rx`, `cirq.ry`, and `cirq.rz`.

An `IonDevice` can implement the two-qubit Mølmer–Sørensen gate, a rotation about the $XX$ axis in the two-qubit Bloch sphere defined as

\begin{equation}
    \exp(-i t XX) = \left[ \begin{matrix}
        \cos t & 0 & 0 & -i \sin t \\
        0 & \cos t & -i \sin t & 0 \\
        0 & -i \sin t & \cos t & 0 \\
        -i \sin t & 0 & 0 & \cos t
    \end{matrix} \right] .
\end{equation}

The Mølmer–Sørensen gate is defined in Cirq as `cirq.ms`.

One can check if a given gate is valid with `IonDevice.validate_gate`. This method raises an error if the gate is invalid (not supported by the device) and does nothing if the gate is valid (supported by the device).

```
"""Check if gates are valid. Invalid gates raise a ValueError."""
# Single-qubit X rotation of any angle is supported.
ion_device.validate_gate(cirq.rx(np.pi / 7))

# Single-qubit Z rotation of any angle is supported.
ion_device.validate_gate(cirq.rz(np.pi / 5))

# Mølmer–Sørensen gate of any angle is supported.
ion_device.validate_gate(cirq.ms(np.pi / 4))
```

One can also validate operations and circuits with `IonDevice.validate_operation` and `IonDevice.validate_circuit`, respectively.

We can get the duration of valid operations as follows.

```
"""Get the duration of valid operations."""
# Duration of a single-qubit operation.
ion_device.duration_of(cirq.ry(np.pi / 2).on(ion_device.at(0)))
```

    cirq.Duration(micros=10)

## Decomposing Operations and Circuits

Operations which are not valid on the device can be decomposed into a set of valid operations. For example, a CNOT gate is not supported but can be implemented with the following decomposition.

```
"""Decompose a CNOT operation into valid IonDevice operations."""
# Get a CNOT operation.
op = cirq.CNOT(ion_device.at(0), ion_device.at(1))

# Decompose it for the IonDevice.
ion_device_ops = cirq.ConvertToIonGates().convert_one(op)

# Print the sequence of operations to implement a CNOT.
print("Sequence of IonDevice operations for a CNOT:\n")
print(cirq.Circuit(ion_device_ops))
```

    Sequence of IonDevice operations for a CNOT:

    0: ───Ry(0.5π)───MS(0.25π)───Rx(-0.5π)───Ry(-0.5π)───
                     │
    1: ──────────────MS(0.25π)───Rx(-0.5π)───────────────

Circuits can also be decomposed in a similar manner using `IonDevice.decompose_circuit`.

```
"""Decompose a circuit into IonDevice operations."""
# Example circuit to decompose.
circuit = cirq.Circuit(
    cirq.H(cirq.LineQubit(0)),
    cirq.CNOT(cirq.LineQubit(0), cirq.LineQubit(1)),
    cirq.CNOT(cirq.LineQubit(0), cirq.LineQubit(2))
)

# Display it.
print("Circuit to decompose:\n")
print(circuit)

# Decompose the circuit.
ion_device_circuit = ion_device.decompose_circuit(circuit)

# Display the decomposed circuit.
print("\nIonDevice circuit:\n")
print(ion_device_circuit)
```

    Circuit to decompose:

    0: ───H───@───@───
              │   │
    1: ───────X───┼───
                  │
    2: ───────────X───

    IonDevice circuit:

    0: ───PhX(1)───────────MS(0.25π)───PhX(1)^0.5───────────MS(0.25π)───PhX(-0.5)^0.5───S^-1───
                           │                                │
    1: ────────────────────MS(0.25π)───PhX(1)^0.5───────────┼──────────────────────────────────
                                                            │
    2: ─────────────────────────────────────────────────────MS(0.25π)───PhX(1)^0.5─────────────


# Cleaning Data

**Prerequisites**

- [Intro](https://datascience.quantecon.org/intro.html)
- [Boolean selection](https://datascience.quantecon.org/basics.html)
- [Indexing](https://datascience.quantecon.org/the_index.html)

**Outcomes**

- Be able to use string methods to clean data that comes as a string
- Be able to drop missing data
- Use cleaning methods to prepare and analyze a real dataset

**Data**

- Item information from about 3,000 Chipotle meals from about 1,800
  Grubhub orders

```python
# Uncomment following line to install on colab
! pip install qeds
```

    Requirement already satisfied: qeds in c:\users\asus\anaconda3\lib\site-packages (0.6.2)
    Requirement already satisfied: pandas in c:\users\asus\anaconda3\lib\site-packages (from qeds) (0.25.1)
    Requirement already satisfied: pandas-datareader in c:\users\asus\anaconda3\lib\site-packages (from qeds) (0.8.1)
    Requirement already satisfied: plotly in c:\users\asus\anaconda3\lib\site-packages (from qeds) (4.5.4)
    Requirement already satisfied: quandl in c:\users\asus\anaconda3\lib\site-packages (from qeds) (3.5.0)
    Requirement already satisfied: numpy in c:\users\asus\anaconda3\lib\site-packages (from qeds) (1.16.5)
    Requirement already satisfied: scipy in c:\users\asus\anaconda3\lib\site-packages (from qeds) (1.3.1)
    Requirement already satisfied: scikit-learn in c:\users\asus\anaconda3\lib\site-packages (from qeds) (0.21.3)
    Requirement already satisfied: seaborn in c:\users\asus\anaconda3\lib\site-packages (from qeds) (0.9.0)
    Requirement already satisfied: quantecon in c:\users\asus\anaconda3\lib\site-packages (from qeds) (0.4.6)
    Requirement already satisfied: statsmodels in c:\users\asus\anaconda3\lib\site-packages (from qeds) (0.10.1)
    Requirement already satisfied: pyarrow in c:\users\asus\anaconda3\lib\site-packages (from qeds) (0.16.0)
    Requirement already satisfied: requests in c:\users\asus\anaconda3\lib\site-packages (from qeds) (2.22.0)
    Requirement already satisfied: openpyxl in c:\users\asus\anaconda3\lib\site-packages (from qeds) (3.0.0)
    Requirement already satisfied: matplotlib in c:\users\asus\anaconda3\lib\site-packages (from qeds) (3.1.1)
    Requirement already satisfied: pytz>=2017.2 in c:\users\asus\anaconda3\lib\site-packages (from pandas->qeds) (2019.3)
    Requirement already satisfied: python-dateutil>=2.6.1 in c:\users\asus\anaconda3\lib\site-packages (from pandas->qeds) (2.8.0)
    Requirement already satisfied: lxml in c:\users\asus\anaconda3\lib\site-packages (from pandas-datareader->qeds) (4.4.1)
    Requirement already satisfied: six in c:\users\asus\anaconda3\lib\site-packages (from plotly->qeds) (1.12.0)
    Requirement already satisfied: retrying>=1.3.3 in c:\users\asus\anaconda3\lib\site-packages (from plotly->qeds) (1.3.3)
    Requirement already satisfied: inflection>=0.3.1 in c:\users\asus\anaconda3\lib\site-packages (from quandl->qeds) (0.3.1)
    Requirement already satisfied: more-itertools in c:\users\asus\anaconda3\lib\site-packages (from quandl->qeds) (7.2.0)
    Requirement already satisfied: joblib>=0.11 in c:\users\asus\anaconda3\lib\site-packages (from scikit-learn->qeds) (0.13.2)
    Requirement already satisfied: sympy in c:\users\asus\anaconda3\lib\site-packages (from quantecon->qeds) (1.4)
    Requirement already satisfied: numba>=0.38 in c:\users\asus\anaconda3\lib\site-packages (from quantecon->qeds) (0.45.1)
    Requirement already satisfied: patsy>=0.4.0 in c:\users\asus\anaconda3\lib\site-packages (from statsmodels->qeds) (0.5.1)
    Requirement already satisfied: idna<2.9,>=2.5 in c:\users\asus\anaconda3\lib\site-packages (from requests->qeds) (2.8)
    Requirement already satisfied: certifi>=2017.4.17 in c:\users\asus\anaconda3\lib\site-packages (from requests->qeds) (2019.9.11)
    Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in c:\users\asus\anaconda3\lib\site-packages (from requests->qeds) (1.24.2)
    Requirement already satisfied: chardet<3.1.0,>=3.0.2 in c:\users\asus\anaconda3\lib\site-packages (from requests->qeds) (3.0.4)
    Requirement already satisfied: jdcal in c:\users\asus\anaconda3\lib\site-packages (from openpyxl->qeds) (1.4.1)
    Requirement already satisfied: et-xmlfile in c:\users\asus\anaconda3\lib\site-packages (from openpyxl->qeds) (1.0.1)
    Requirement already satisfied: cycler>=0.10 in c:\users\asus\anaconda3\lib\site-packages (from matplotlib->qeds) (0.10.0)
    Requirement already satisfied: kiwisolver>=1.0.1 in c:\users\asus\anaconda3\lib\site-packages (from matplotlib->qeds) (1.1.0)
    Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in c:\users\asus\anaconda3\lib\site-packages (from matplotlib->qeds) (2.4.2)
    Requirement already satisfied: mpmath>=0.19 in c:\users\asus\anaconda3\lib\site-packages (from sympy->quantecon->qeds) (1.1.0)
    Requirement already satisfied: llvmlite>=0.29.0dev0 in c:\users\asus\anaconda3\lib\site-packages (from numba>=0.38->quantecon->qeds) (0.29.0)
    Requirement already satisfied: setuptools in c:\users\asus\anaconda3\lib\site-packages (from kiwisolver>=1.0.1->matplotlib->qeds) (41.4.0)

```python
import pandas as pd
import numpy as np
import qeds
```

## Outline

- [Cleaning Data](#Cleaning-Data)
  - [Cleaning Data](#Cleaning-Data)
  - [String Methods](#String-Methods)
  - [Type Conversions](#Type-Conversions)
  - [Missing Data](#Missing-Data)
  - [Case Study](#Case-Study)
  - [Appendix: Performance of `.str` Methods](#Appendix:-Performance-of-`.str`-Methods)
  - [Exercises](#Exercises)

## Cleaning Data

For many data projects, a [significant proportion of
time](https://www.forbes.com/sites/gilpress/2016/03/23/data-preparation-most-time-consuming-least-enjoyable-data-science-task-survey-says/#74d447456f63)
is spent collecting and cleaning the data — not performing the analysis.

This non-analysis work is often called “data cleaning”.

pandas provides very powerful data cleaning tools, which we
will demonstrate using the following dataset.

```python
df = pd.DataFrame({"numbers": ["#23", "#24", "#18", "#14", "#12", "#10", "#35"],
                   "nums": ["23", "24", "18", "14", np.nan, "XYZ", "35"],
                   "colors": ["green", "red", "yellow", "orange", "purple", "blue", "pink"],
                   "other_column": [0, 1, 0, 2, 1, 0, 2]})
df
```

      numbers
      nums
      colors
      other_column

      0
      #23
      23
      green
      0

      1
      #24
      24
      red
      1

      2
      #18
      18
      yellow
      0

      3
      #14
      14
      orange
      2

      4
      #12
      NaN
      purple
      1

      5
      #10
      XYZ
      blue
      0

      6
      #35
      35
      pink
      2

What would happen if we wanted to try and compute the mean of
`numbers`?

```python
df["numbers"].mean()
```

It throws an error!

Can you figure out why?

Hint: When looking at error messages, start at the very
bottom.

The final error says, `TypeError: Could not convert #23#24... to numeric`.

## String Methods

Our solution to the previous exercise was to remove the `#` by using
the `replace` string method: `int(c2n.replace("#", ""))`.

One way to make this change to every element of a column would be to
loop through all elements of the column and apply the desired string
methods…

```python
%%time

# Iterate over all rows
for row in df.iterrows():

    # `iterrows` method produces a tuple with two elements...
    # The first element is an index and the second is a Series with the data from that row
    index_value, column_values = row

    # Apply string method
    clean_number = int(column_values["numbers"].replace("#", ""))

    # The `at` method is very similar to the `loc` method, but it is specialized
    # for accessing single elements at a time... We wanted to use it here to give
    # the loop the best chance to beat a faster method which we show you next.
    df.at[index_value, "numbers_loop"] = clean_number
```

    Wall time: 6.51 ms

While this is fast for a small dataset like this, this method slows for larger datasets.

One *significantly* faster (and easier) method is to apply a string
method to an entire column of data.

Most methods that are available to a Python string (we learned a
few of them in the [strings lecture](https://datascience.quantecon.org/../python_fundamentals/basics.html)) are
also available to a pandas Series that has `dtype` object.

We access them by doing `s.str.method_name` where `method_name` is
the name of the method.

When we apply the method to a Series, it is applied to all rows in the
Series in one shot!

Let’s redo our previous example using a pandas `.str` method.

```python
%%time

# ~2x faster than loop... However, speed gain increases with size of DataFrame. The
# speedup can be in the ballpark of ~100-500x faster for big DataFrames.
# See appendix at the end of the lecture for an application on a larger DataFrame
df["numbers_str"] = df["numbers"].str.replace("#", "")
```

    Wall time: 0 ns

We can use `.str` to access almost any string method that works on
normal strings. (See the [official
documentation](https://pandas.pydata.org/pandas-docs/stable/text.html)
for more information.)

```python
df["colors"].str.contains("p")
```

    0    False
    1    False
    2    False
    3    False
    4     True
    5    False
    6     True
    Name: colors, dtype: bool

```python
df["colors"].str.capitalize()
```

    0     Green
    1       Red
    2    Yellow
    3    Orange
    4    Purple
    5      Blue
    6      Pink
    Name: colors, dtype: object

## Type Conversions

In our example above, the `dtype` of the `numbers_str` column shows that pandas still treats
it as a string even after we have removed the `"#"`.

We need to convert this column to numbers.

The best way to do this is using the `pd.to_numeric` function.

This method attempts to convert whatever is stored in a Series into
numeric values

For example, after the `"#"` removed, the numbers of column
`"numbers"` are ready to be converted to actual numbers.

```python
df["numbers_numeric"] = pd.to_numeric(df["numbers_str"])
```

```python
df.dtypes
```

    numbers             object
    nums                object
    colors              object
    other_column         int64
    numbers_loop       float64
    numbers_str         object
    numbers_numeric      int64
    dtype: object

```python
df.head()
```

      numbers
      nums
      colors
      other_column
      numbers_loop
      numbers_str
      numbers_numeric

      0
      #23
      23
      green
      0
      23.0
      23
      23

      1
      #24
      24
      red
      1
      24.0
      24
      24

      2
      #18
      18
      yellow
      0
      18.0
      18
      18

      3
      #14
      14
      orange
      2
      14.0
      14
      14

      4
      #12
      NaN
      purple
      1
      12.0
      12
      12

We can convert to other types well.

Using the `astype` method, we can convert to any of the supported
pandas `dtypes` (recall the [intro lecture](https://datascience.quantecon.org/intro.html)).

Below are some examples. (Pay attention to the reported `dtype`)

```python
df["numbers_numeric"].astype(str)
```

    0    23
    1    24
    2    18
    3    14
    4    12
    5    10
    6    35
    Name: numbers_numeric, dtype: object

```python
df["numbers_numeric"].astype(float)
```

    0    23.0
    1    24.0
    2    18.0
    3    14.0
    4    12.0
    5    10.0
    6    35.0
    Name: numbers_numeric, dtype: float64

## Missing Data

Many datasets have missing data.

In our example, we are missing an element from the `"nums"` column.

```python
df
```

      numbers
      nums
      colors
      other_column
      numbers_loop
      numbers_str
      numbers_numeric

      0
      #23
      23
      green
      0
      23.0
      23
      23

      1
      #24
      24
      red
      1
      24.0
      24
      24

      2
      #18
      18
      yellow
      0
      18.0
      18
      18

      3
      #14
      14
      orange
      2
      14.0
      14
      14

      4
      #12
      NaN
      purple
      1
      12.0
      12
      12

      5
      #10
      XYZ
      blue
      0
      10.0
      10
      10

      6
      #35
      35
      pink
      2
      35.0
      35
      35

We can find missing data by using the `isnull` method.

```python
df.isnull()
```

      numbers
      nums
      colors
      other_column
      numbers_loop
      numbers_str
      numbers_numeric

      0
      False
      False
      False
      False
      False
      False
      False

      1
      False
      False
      False
      False
      False
      False
      False

      2
      False
      False
      False
      False
      False
      False
      False

      3
      False
      False
      False
      False
      False
      False
      False

      4
      False
      True
      False
      False
      False
      False
      False

      5
      False
      False
      False
      False
      False
      False
      False

      6
      False
      False
      False
      False
      False
      False
      False

We might want to know whether particular rows or columns have any
missing data.

To do this we can use the `.any` method on the boolean DataFrame
`df.isnull()`.

```python
df.isnull().any(axis=0)
```

    numbers            False
    nums                True
    colors             False
    other_column       False
    numbers_loop       False
    numbers_str        False
    numbers_numeric    False
    dtype: bool

```python
df.isnull().any(axis=1)
```

    0    False
    1    False
    2    False
    3    False
    4     True
    5    False
    6    False
    dtype: bool

Many approaches have been developed to deal with missing data, but the two most commonly used (and the corresponding DataFrame method) are:

- Exclusion: Ignore any data that is missing (`.dropna`).
- Imputation: Compute “predicted” values for the data that is missing
  (`.fillna`).

For the advantages and disadvantages of these (and other) approaches,
consider reading the [Wikipedia
article](https://en.wikipedia.org/wiki/Missing_data).

For now, let’s see some examples.

```python
# drop all rows containing a missing observation
df.dropna()
```

      numbers
      nums
      colors
      other_column
      numbers_loop
      numbers_str
      numbers_numeric

      0
      #23
      23
      green
      0
      23.0
      23
      23

      1
      #24
      24
      red
      1
      24.0
      24
      24

      2
      #18
      18
      yellow
      0
      18.0
      18
      18

      3
      #14
      14
      orange
      2
      14.0
      14
      14

      5
      #10
      XYZ
      blue
      0
      10.0
      10
      10

      6
      #35
      35
      pink
      2
      35.0
      35
      35

```python
# fill the missing values with a specific value
df.fillna(value=100)
```

      numbers
      nums
      colors
      other_column
      numbers_loop
      numbers_str
      numbers_numeric

      0
      #23
      23
      green
      0
      23.0
      23
      23

      1
      #24
      24
      red
      1
      24.0
      24
      24

      2
      #18
      18
      yellow
      0
      18.0
      18
      18

      3
      #14
      14
      orange
      2
      14.0
      14
      14

      4
      #12
      100
      purple
      1
      12.0
      12
      12

      5
      #10
      XYZ
      blue
      0
      10.0
      10
      10

      6
      #35
      35
      pink
      2
      35.0
      35
      35

```python
# use the _next_ valid observation to fill the missing data
df.fillna(method="bfill")
```

      numbers
      nums
      colors
      other_column
      numbers_loop
      numbers_str
      numbers_numeric

      0
      #23
      23
      green
      0
      23.0
      23
      23

      1
      #24
      24
      red
      1
      24.0
      24
      24

      2
      #18
      18
      yellow
      0
      18.0
      18
      18

      3
      #14
      14
      orange
      2
      14.0
      14
      14

      4
      #12
      XYZ
      purple
      1
      12.0
      12
      12

      5
      #10
      XYZ
      blue
      0
      10.0
      10
      10

      6
      #35
      35
      pink
      2
      35.0
      35
      35

```python
# use the _previous_ valid observation to fill missing data
df.fillna(method="ffill")
```

      numbers
      nums
      colors
      other_column
      numbers_loop
      numbers_str
      numbers_numeric

      0
      #23
      23
      green
      0
      23.0
      23
      23

      1
      #24
      24
      red
      1
      24.0
      24
      24

      2
      #18
      18
      yellow
      0
      18.0
      18
      18

      3
      #14
      14
      orange
      2
      14.0
      14
      14

      4
      #12
      14
      purple
      1
      12.0
      12
      12

      5
      #10
      XYZ
      blue
      0
      10.0
      10
      10

      6
      #35
      35
      pink
      2
      35.0
      35
      35

We will see more examples of dealing with missing data in future
chapters.

## Case Study

We will now use data from an
[article](https://www.nytimes.com/interactive/2015/02/17/upshot/what-do-people-actually-order-at-chipotle.html)
written by The Upshot at the NYTimes.

This data has order information from almost 2,000 Chipotle orders and
includes information on what was ordered and how much it cost.

```python
chipotle = qeds.data.load("chipotle_raw")
chipotle.head()
```

      order_id
      quantity
      item_name
      choice_description
      item_price

      0
      1
      1
      Chips and Fresh Tomato Salsa
      NaN
      $2.39

      1
      1
      1
      Izze
      [Clementine]
      $3.39

      2
      1
      1
      Nantucket Nectar
      [Apple]
      $3.39

      3
      1
      1
      Chips and Tomatillo-Green Chili Salsa
      NaN
      $2.39

      4
      2
      2
      Chicken Bowl
      [Tomatillo-Red Chili Salsa (Hot), [Black Beans...
      $16.98

## Appendix: Performance of `.str` Methods

Let’s repeat the “remove the `#`” example from above, but this time on
a much larger dataset.

```python
import numpy as np
test = pd.DataFrame({"floats": np.round(100*np.random.rand(100000), 2)})
test["strings"] = test["floats"].astype(str) + "%"
test.head()
```

      floats
      strings

      0
      15.52
      15.52%

      1
      97.98
      97.98%

      2
      77.81
      77.81%

      3
      72.99
      72.99%

      4
      28.47
      28.47%

```python
%%time

for row in test.iterrows():
    index_value, column_values = row
    clean_number = column_values["strings"].replace("%", "")
    test.at[index_value, "numbers_loop"] = clean_number
```

    Wall time: 19.6 s

```python
%%time
test["numbers_str_method"] = test["strings"].str.replace("%", "")
```

    Wall time: 62.3 ms

```python
test["numbers_str_method"].equals(test["numbers_loop"])
```

    True

We got the exact same result in a fraction of the time!


Dinámica

Capítulo 1: Cinemática y Cinética de partículas

Movimiento rectilíneo

2021/02

MEDELLÍN - COLOMBIA

 Text provided under a Creative Commons Attribution license, CC-BY. All code is made available under the FSF-approved MIT license.(c) Carlos Alberto Alvarez Henao

***

***Docente:*** Carlos Alberto Álvarez Henao, I.C. D.Sc.

***e-mail:*** carlosalvarezh@gmail.com

***skype:*** carlos.alberto.alvarez.henao

***Linkedin:*** https://www.linkedin.com/in/carlosalvarez5/

***github:*** https://github.com/carlosalvarezh/Dinamica

***Herramienta:*** [Jupyter](http://jupyter.org/)

***Kernel:*** Python 3.9

***

Tabla de Contenidos

1  Dinámica

1.1  Ubicación de la dinámica en la Física

1.2  Definiciones

1.3  Estrategia para la solución de problemas

2  Cinemática rectilínea - Movimiento continuo

2.1  Consideraciones

2.2  Posición

2.3  Desplazamiento

2.4  Velocidad

2.5  Aceleración

2.6  Aceleración constante

2.6.1  Velocidad como función del tiempo

2.6.2  Posición como función del tiempo

2.6.3  Velocidad como función de la posición

2.6.4  Observaciones

2.7  Recapitulando

2.8  Ejemplos

2.8.1  Desplazamiento rectilíneo de un Automovil

2.8.2  Altura máxima cohete

2.8.3  Partícula en campo magnético

3  Cinemática rectilínea: Movimiento variable

3.1  Gráficas de $s-t$, $v-t$ y $a-t$

3.2  Gráficas de $v-s$ y $a-s$

3.3  Ejemplos

3.3.1  Desplazamiento en bicicleta

 Fuente: Engineer4Free

***Introducción***

Estas notas son extraídas principalmente de los textos de Dinámica de [Hibbeler](https://www.pearson.com/us/higher-education/product/Hibbeler-Engineering-Mechanics-Dynamics-14th-Edition/9780133915389.html) y [Beer&Johnston](https://www.amazon.com/Vector-Mechanics-Engineers-Ferdinand-Beer/dp/0077402324), así como también de la revisión de extensa literatura en internet. Las referencias se indicarán en cada apartado. Se hace uso de la herramienta [Jupyter Notebook](https://jupyter.org/) empleando el lenguaje de programación [python](https://python.org/) en la versión estable más reciente

## Dinámica

Parte de la física que estudia la relación existente entre las fuerzas que actúan sobre un cuerpo y los efectos que se producirán sobre el movimiento de ese cuerpo.

 Fuente: Engineer4Free

### Ubicación de la dinámica en la Física

 Fuente: Wikisabio

### Definiciones

- ***Mecánica:*** Se ocupa del estado de reposo o movimiento de cuerpos sometidos a la acción de fuerzas.

- ***Estática:*** Se ocupa del equilibrio de un cuerpo que está en reposo o que se mueve con velocidad constante.

- ***Dinámica:*** Se ocupa del movimiento acelerado de un cuerpo.

- ***Cinemática:*** Trata sólo los aspectos geométricos del movimiento.

- ***Cinética:*** Analiza las fuerzas que provocan el movimiento.

Para desarrollar estos principios, primero se analizará la dinámica de una partícula, y a continuación se abordarán temas de dinámica de un cuerpo rígido en dos y luego en tres dimensiones.

### Estrategia para la solución de problemas

- Lea el problema con cuidado y trate de correlacionar la situación física real con la teoría que haya estudiado.

- Trace todos los diagramas necesarios y tabule los datos del problema.

- Establezca un sistema de coordenadas y aplique los principios pertinentes, casi siempre en forma matemática.

- Resuelva de manera algebraica las ecuaciones necesarias hasta donde sea práctico; luego, utilice un conjunto consistente de unidades y complete la solución numéricamente. Reporte la respuesta sin más cifras significativas que la precisión de los datos dados.

- Estudie la respuesta con juicio técnico y sentido común para determinar si parece o no razonable.

- Una vez completadas las soluciones, repase el problema. Trate de pensar en otras formas de obtener la misma solución.

## Cinemática rectilínea - Movimiento continuo

### Consideraciones

 Fuente: Pinterest

- Los cuerpos se consideran de tamaño finito, como partícula, y el movimiento del cuerpo como un todo se caracteriza por el movimiento de su centro de masa, sin rotación.

- Se considera la partícula con masa, y su tamaño y forma son indiferentes.

- Se presenta la partícula moviéndose a lo largo de una trayectoria rectilínea.

- La cinemática de una partícula se caracteriza al especificar, en cualquier instante, su posición, desplazamiento, velocidad y aceleración.

### Posición

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

La trayectoria rectilínea de una partícula se definirá por medio de un solo eje de coordenadas $s$.

El origen $O$ en la trayectoria es un punto fijo, y a partir de él se utiliza la coordenada de posición s para especificar la ubicación de la partícula en cualquier instante dado. La magnitud de $s$ es la distancia de $O$ a la partícula (en unidades de longitud), y su signo algebraico define el sentido de su dirección.

La posición es una cantidad vectorial puesto que tiene tanto magnitud como dirección, aunque en este caso se representa por el escalar algebraico $s$ puesto que la dirección se mantiene a lo largo del eje de coordenadas.

### Desplazamiento

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

El desplazamiento de la partícula se define como el cambio de su posición, y es dado por:

\begin{equation*}
\Delta s= s'-s
\label{eq:Ec1_1} \tag{1.1}
\end{equation*}

En este caso $\Delta s$ es positivo puesto que la posición final de la partícula queda a la derecha de su posición inicial, es decir, $s'>s$. Asimismo, si la posición final quedara a la izquierda de su posición inicial, $\Delta s$ sería negativo.

El desplazamiento de una partícula también es una cantidad vectorial, y deberá distinguirse de la distancia que recorre la partícula. Específicamente, la distancia recorrida es un escalar positivo que representa la longitud total de la trayectoria a lo largo de la cual viaja la partícula.

### Velocidad

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

Si la partícula recorre una distancia $\Delta s$ durante el intervalo $\Delta t$, su velocidad promedio durante este intervalo es

\begin{equation*}
\textbf{v}_{prom}=\frac{\Delta s}{\Delta t}
\label{eq:Ec1_2} \tag{1.2}
\end{equation*}

La velocidad instantánea es una cantidad vectorial definida como

\begin{equation*}
\textbf{v}=\lim_{\Delta t \rightarrow 0}\frac{\Delta s}{\Delta t}=\frac{ds}{dt}
\label{eq:Ec1_3} \tag{1.3}
\end{equation*}

Como la dirección temporal siempre será positiva, entonces el signo para determinar el sentido de la velocidad le corresponderá a $ds$. La magnitud de la velocidad es lo que se conoce como *rapidez*.

### Aceleración

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

Conocida la velocidad de la partícula en dos puntos, la aceleración promedio en un intervalo de tiempo $\Delta t$ está dada por

\begin{equation*}
\textbf{a}_{prom}=\frac{\Delta \textbf{v}}{\Delta t}
\label{eq:Ec1_4} \tag{1.4}
\end{equation*}

La aceleración instantánea es una cantidad vectorial definida como

\begin{equation*}
\textbf{a}=\lim_{\Delta t \rightarrow 0}\frac{\Delta \textbf{v}}{\Delta t}=\frac{d\textbf{v}}{dt}
\label{eq:Ec1_5} \tag{1.5}
\end{equation*}

La aceleración también se puede interpretar como la segunda derivada del desplazamiento respecto al tiempo.
Una relación diferencial que incluye el desplazamiento, la velocidad y la aceleración a lo largo de una trayectoria, eliminando la dependencia del tiempo es:

\begin{equation*}
\textbf{a}ds=\textbf{v}d\textbf{v}
\label{eq:Ec1_6} \tag{1.6}
\end{equation*}

### Aceleración constante

Si la aceleración es constante, se pueden integrar las tres ecuaciones cinemáticas vistas:

$$\textbf{a}_c=\frac{d\textbf{v}}{dt}; \quad \textbf{v}=\frac{ds}{dt}; \quad \textbf{a}ds=\textbf{v}d\textbf{v}$$

#### Velocidad como función del tiempo

Integrando $a_c=\frac{d\textbf{v}}{dt}$, con condiciones iniciales $\textbf{v}=v_0$ cuando $𝑡=0$

$$\int_{v_0}^v d\textbf{v} = \int_0^t a_c dt$$

Se llega a

\begin{equation*}
\textbf{v} = v_0 + a_c t
\label{eq:Ec1_7} \tag{1.7}
\end{equation*}

#### Posición como función del tiempo

Integrando $\textbf{v}=ds/dt=v_0 + a_c t$, con condiciones iniciales $s=s_0$ cuando $𝑡=0$

$$\int_{s_0}^s ds = \int_0^t (v_0 +a_c t) dt$$

Se llega a

\begin{equation*}
s = s_0 + v_0 t +\frac{1}{2} a_c t^2
\label{eq:Ec1_8} \tag{1.8}
\end{equation*}

#### Velocidad como función de la posición

Integrando $\textbf{v}d\textbf{v}=a_c ds$, con condiciones iniciales $v=v_0$ cuando $s=s_0$

$$\int_{v_0}^v \textbf{v}d\textbf{v} = \int_{s_0}^s a_c ds$$

Se llega a

\begin{equation*}
v^2 = v_0^2 + 2a_c (s-s_0)
\label{eq:Ec1_9} \tag{1.9}
\end{equation*}

#### Observaciones

- Las ecuaciones anteriores son útiles cuando la aceleración es constante y cuando $t=0$, $s=s_0$ y $v=v_0$.

- Si se conoce una relación entre dos de las cuatro variables, $\textbf{a}$, $\textbf{v}$, $s$ y $t$, entonces se puede obtener una tercera variable con una de las ecuaciones cinemáticas, $\textbf{a}=d\textbf{v}/dt$, $\textbf{v}=ds/dt$ o $\textbf{a}ds=\textbf{v}d\textbf{v}$, puesto que cada ecuación relaciona las tres variables.

- Siempre que se realice una integración, es importante que se conozcan la posición y la velocidad en un instante dado para evaluar o la constante de integración si se utiliza una integral indefinida, o los límites de integración si se utiliza una integral definida.

### Recapitulando

- La dinámica se ocupa de cuerpos que tienen movimiento acelerado.

- La cinemática es un estudio de la geometría del movimiento.

- La cinética es un estudio de las fuerzas que causan el movimiento.

- La cinemática rectilínea se refiere al movimiento en línea recta.

- La rapidez se refiere a la magnitud de la velocidad.

- La rapidez promedio es la distancia total recorrida, dividida entre el tiempo total. Ésta es diferente de la velocidad promedio, la cual es el desplazamiento dividido entre el tiempo.

- Una partícula que reduce el paso está desacelerando.

- Una partícula puede tener una aceleración y al mismo tiempo una velocidad cero.

- La relación $\textbf{a}ds=\textbf{v} d\textbf{v}$ se deriva de $\textbf{a}=d\textbf{v}/dt$ y $\textbf{v}=ds/dt$, al eliminar $dt$.

### Ejemplos

#### Desplazamiento rectilíneo de un Automovil

 Ejemplo 12.1: Hibbeler R. Engineering Mechanics: Dynamics

El automóvil de la figura se desplaza en línea recta de modo que durante un corto tiempo su velocidad está definida por $\textbf{v}=3t^2 + 2t$ pies/s, donde $t$ está en segundos. Determine su posición y aceleración cuando $t = 3 s$. Cuando $t = 0, s = 0$.

Vamos a resolver el ejemplo de dos formas: Analítica y computacionalmente.

***Solución analítica:***

- ***Sistema de coordenadas:*** Se establece el sistema de coordenadas en sentido horizontal, con origen en el punto $O$, positivo a la derecha.

- ***Posición:*** como la velocidad es una función del tiempo, $\textbf{v}=f(t)$, la posición se determina de la  [(Ec1.3)](#Ec1_3). Reemplazando

$$\textbf{v}=3t^2 + 2t=\frac{ds}{dt}$$

realizando la separación de variables e integrando el espacio, $s$, entre $0$ y $s$ y el tiempo, $t$, entre $0$ y $t$:

$$\int_0^s ds=\int_0^t(3t^2+2t)dt$$

$$\left. s\right|_0^s= \left. t^3+t^2 \right|_0^t$$

cuando $t=3 s$

$$s(3)=3^3+3^2 =36 pies$$

- ***Aceleración***
La aceleración también es función del tiempo y se determina de ecuación [(Ec1.5)](#Ec1_5).

$$\textbf{a}=\frac{d(3t^2 + 2t)}{dt}=\frac{d\textbf{v}}{dt}$$

realizando la separación de variables e integrando:

$$\textbf{a}=6t+2$$

cuando $t=3 s$

$$a(3)=6(3)+2=20 \text{pies/s}^2$$

***Solución computacional:***

Ahora vamos a resolver el ejemplo computacionalmente empleando el módulo [`sympy`](https://www.sympy.org/en/index.html) de `python`. Primero, se carga el módulo de cálculo simbólico, que nos permitirá obtener expresiones analíticas de la posición y la aceleración, que serán evaluadas en el tiempo solicitado. Para la impresión de algunos resultados de forma analítica se empleará el módulo [`mathjax`](https://www.mathjax.org/).

```python
from sympy import *
t = symbols('t')
init_printing(use_latex='mathjax')
```

Generamos una expresión para la función velocidad, como fue dada en el enunciado

```python
def v(t):

    """
    Función velocidad
        función para determinar la velocidad en función del tiempo, t.

    Input:
        Cadena de caracteres en donde t es la varible.

    Output:
        Cadena de caracteres.

    Ejemplo:
        3 * t**2 + 2 * t
    """

    # Ingresando la función a través del teclado (descomentar las dos líneas siguientes y comentar la última línea)
    #veloc = input("Ingrese la función correspondiente a la velocidad, v(t): ")
    #return veloc

    # escribiendo la función directamente dentro del módulo (comentar las dos líneas anteriores)
    return 3 * t**2 + 2 * t
```

```python
help(v)
```

Visualizando la integral de la velocidad a ser calculada de forma analítica

```python
Integral(v(t),(t,0,t))
```

Integrando analíticamente la expresión de la velocidad, para obtener una expresión de la posición:

```python
pos = integrate(v(t),(t,0,t))
pos
```

Evaluando la expresión del espacio obtenida con la integración, en $t=3s$

```python
print("La posición que tendrá el vehículo despues de 3 seg será de {0} pies".format(pos.subs(t,3)))
```

Ahora vamos a determinar una expresión para la aceleración, derivando la expresión dada de la velocidad

```python
acel = diff(v(t),t)
print(acel)
```

Por último, evaluamos la expresión de la aceleración obtenida con la derivada de la velociad respecto al tiempo, en $t=3s$

```python
print("La aceleración del vehículo después de 3 seg es {0} pies/s^2".format(acel.subs(t,3)))
```

Compactando en una única celda el código visto:

```python
from sympy import *
t = symbols('t')

# definición de la función a evaluar
def v(t):
    return 3 * t**2 + 2 * t

# posición
pos = integrate(v(t),(t,0,t))
print("La posición que tendrá el vehículo despues de 3 seg será de {0} pies".format(pos.subs(t,3)))

# aceleración
acel = diff(v(t),t)
print("La aceleración del vehículo después de 3 seg es {0} pies/s^2".format(acel.subs(t,3)))
```

#### Altura máxima cohete

 Ejemplo 12.3: Hibbeler R. Engineering Mechanics: Dynamics

Durante una prueba un cohete asciende a $75 m/s$ y cuando está a $40 m$ del suelo su motor falla. Determine la altura máxima $s_B$ alcanzada por el cohete y su velocidad justo antes de chocar con el suelo. Mientras está en movimiento, el cohete se ve sometido a una aceleración constante dirigida hacia abajo de $9.81 m/s^2$ debido a la gravedad. Ignore la resistencia del aire.

Igual que el ejemplo anterior, se dará solución analítica y computacional.

***Solución analítica:***

- ***Sistema de coordenadas:*** Se establecerá el origen de coordenadas a nivel del suelo.

- ***Altura máxima:*** Del enunciado se establece que el cohete está a una distancia de $s_A=40m$ del suelo, con una velocidad $v_A = +75m/s$ cuando el motor falla, que es cuando se empieza a tomar el tiempo, es decir, $t=0$. La aceleración que experimenta el cohete es debida a la gravedad, $a_c=-9.81m/s^2$ (negativa pues actúa en sentido contrario al desplazamiento y velocidad). Como la aceleración es constante, la posición y velocidad del cohete se pueden relacionar directamente mediante la [Ec. 1.9](#Ec1_9), donde $A$ y $B$ son los puntos inicial y final (de máxima altura) respectivamente.

$$v_B^2=v_A^2+2a_c(s_B-s_A)$$

La velocidad en el punto $B$ es cero. Reemplazando valores se tiene:

$$0=(75m/s)^2+2(-9.81m/s^2)(s_B-40m)$$

y despejando para el valor de $s_B$

$$s_B=327m$$

- ***Velocidad:*** La velocidad final del cohete (justo antes de chocar con la tierra), punto $C$, también se puede determinar de la [Ec. 1.9](#Ec1_9). En este caso el punto $B$ será el inicial.

$$v_C^2=v_B^2+2a_c(s_C-s_B)$$

La velocidad en el punto $B$ y la distancia en el punto $C$ son cero. Reemplazando valores se tiene:

$$v_C=\pm \sqrt{(0)^2+2(-9.81m/s^2)(0-327m)}$$

y calculando para el valor de $v_C$

$$v_C=-80.1m/s$$

Se selecciona la raíz negativa pues el cohete está descendiendo.

***Solución computacional:*** Se deja al estudiante intentar una solución empleando programación con `python`.

#### Partícula en campo magnético

 Ejemplo 12.3: Hibbeler R. Engineering Mechanics: Dynamics

Una partícula metálica se somete a la influencia de un campo magnético a medida que desciende a través de un fluido que se extiende de la placa $A$ a la placa $B$. Si la partícula se libera del reposo en el punto medio $C$, $s=100 mm$ y la aceleración es $a=(4s) m/s^2$, donde $s$ está en metros, determine la velocidad de la partícula cuando llega a la placa $B$, $s=200 mm$ y el tiempo que le lleva para ir de $C$ a $B$.

***Solución analítica:***

- ***Sistema de coordenadas:*** Positivo hacia abájo (dirección del desplazamiento)

- ***Velocidad:*** Como la aceleración es dada en función del espacio, $a=f(s)$, podemos deivar la ecuación de la velocidad a partir de la [Ec. 1.6](#Ec1_6), con condiciones iniciales $v=0$ en $s=0.1m$, entonces:

$$vdv=ads$$

integrando a ambos lados, con los límites de integración correspondientes, se tien:

$$\int_0^v vdv=\int_{0.1}^s 4s ds$$

$$\left. \frac{1}{2}v^2 \right |_0^v = \left . \frac{4}{2} s^2  \right|_{0.1}^s$$

$$v=\pm 2 \sqrt{(s^2-0.01)} m/s$$

evaluando en $s=200 mm = 0.2 m$ se tiene

$$v_B=0.346 m/s=346 mm/s$$

se escoge la raíz positiva pues va en la dirección del movimiento.

- ***Tiempo:*** El tiempo de desplazamiento de $C$ a $B$ se obtiene de la [Ec. 1.3](#Ec1_3). Reemplazando la expresión del espacio, cuando $s=0.1m$ en $t=0$

$$ds=vdt=\pm 2 \sqrt{(s^2-0.01)}dt$$

integrando

$$\int_{0.1}^s \frac{ds}{2 \sqrt{s^2-0.01}}=\int_0^t dt$$

$$\left. Ln \left( 2 \sqrt{s^2-0.01} + s \right) \right|_{0.1}^s=\left. t \right|_0^t$$

$$Ln \left( 2 \sqrt{s^2-0.01} + s \right) +2.303 = t$$

evaluando en $s=0.2 m$

$$t=\frac{Ln \left( 2 \sqrt{(0.2)^2-0.01} + 0.2 \right) +2.303 }{2}=0.658s$$

***Solución computacional***

- ***Velocidad:***

Ahora vamos a plantear la solución computacional como en el primer ejemplo. Para encontrar una expresión analítica para la velocidad debemos integrar la ecuacíón $vdv=ads$.

```python
from sympy import *
t, x = symbols('t x')
a, v, s = symbols('a v s') #, cls = Function)
init_printing(use_latex='mathjax')
```

En este ejemplo se ofrece una función para la aceleración dada por $a=(4s) m/s$. Generaremos una variable en python para la aceleración

```python
a = 4 * s
```

integrando a ambos lados de la ecuación

```python
veloc = Eq(integrate(v, (v, 0, v)), integrate(a, (s, 0.1, s)))
veloc
```

Resolviendo para la variable $v$

```python
veloc = solve(veloc,v)
veloc
```

evaluando en $s=0.2 m$, para la raíz positiva (posición 1 de la lista), se tiene

```python
print("La velocidad de caída de la partícula es {0:3.0f} mm/s".format(veloc[1].subs(s,0.2)*1000))
```

- ***tiempo:*** Siguiendo lo presentado en la solución analítica

```python
space = Eq(integrate(1/(veloc[1]),(s, 0.1, s)), integrate(1, (t, 0, t)))
space
```

```python
time = solve(space,t)
time
```

```python
print("El tiempo de caída de la partícula es {0:3.3f} s".format(time[0].subs(s,0.2)))
```

## Cinemática rectilínea: Movimiento variable

Cuando el movimiento de una partícula es variable, su *posición*, *velocidad* y *aceleración* no pueden describirse mediante una sola función matemática continua a lo largo de toda la trayectoria. En su lugar, se requerirá una serie de funciones para especificar el movimiento en diferentes intervalos. Por eso, conviene representar el movimiento como una gráfica. Si se puede trazar una gráfica del movimiento que relacione dos de las variables $s$, $v$, $a$, $t$, entonces esta gráfica puede utilizarse para construir gráficas subsecuentes que relacionen otras dos variables, puesto que las variables están relacionadas por las relaciones diferenciales $v = ds/dt$, $a=dv/dt$ o $ads=vdv$. Con frecuencia ocurren varias situaciones.

### Gráficas de $s-t$, $v-t$ y $a-t$

 Hibbeler R. Engineering Mechanics: Dynamics

    La gráfica de $v-t$ se construye a partir de la gráfica de $s-t$, fig. (a), se utilizará la ecuación $v=ds/dt$, ya que relaciona las variables $s$ y $t$ con $v$. Esta ecuación establece que

    $$\underbrace{\frac{ds}{dt}}_{\text{pendiente gráfica s-t}}=\underbrace{v}_{velocidad}$$

   Por ejemplo, si se mide la pendiente en la gráfica de $s-t$ cuando $t=t_1$, la velocidad es $v_1$, la cual se traza en la fig. (b). La gráfica de $v-t$ se construye trazando ésta y otros valores en cada instante.

 Hibbeler R. Engineering Mechanics: Dynamics

    La gráfica de $a-t$ se construye a partir de la gráfica de $v-t$ del mismo modo, figs. (a) y (b) puesto que

    $$\underbrace{\frac{dv}{dt}}_{\text{pendiente gráfica v-t}}=\underbrace{a}_{acelereción}$$

Si la curva $s-t$ correspondiente a cada intervalo de movimiento puede
expresarse mediante una función matemática $s=s(t)$, entonces la ecuación
de la gráfica de $v-t$ correspondiente al mismo intervalo se obtiene
diferenciando esta función con respecto al tiempo puesto que $v=ds/dt$.

Asimismo, la ecuación de la gráfica de $a-t$ en el mismo intervalo se determina
al diferenciar $v=v(t)$ puesto que $a=dv/dt$. Como la diferenciación
reduce un polinomio de grado $n$ a uno de grado $n-1$, en tal caso si la
gráfica de $s-t$ es parabólica (una curva de segundo grado), la gráfica de
$v-t$ será una línea inclinada (una curva de primer grado) y la gráfica de $a-t$
será una constante o una línea horizontal (una curva de grado cero).

 Hibbeler R. Engineering Mechanics: Dynamics

    Si se tiene la gráfica de $a-t$, como se muestra en la figura al lado, la gráfica de $v-t$ se construye mediante $a=dv/dt$, escrita como

$$\underbrace{\Delta v}_{\text{Cambio de la velocidad}}=\underbrace{\int adt}_{\text{área bajo la curva de a-t}}$$

Para construir la gráfica $v-t$, se parte de la velocidad inicial de la partícula, $v_0$ y luego se va adicionando pequeños incrementos de área ($\Delta v$) determinados a partir de la gráfica $a-t$. Con esto, se tienen una serie de puntos sucesivos, $v_i=v_{i-1}+\Delta v$ que irán conformando la gráfica $v-t$

La adición algebráica de los incrementos de área de la gráfica $a-t$ es necesaria, ya que las áreas situadas por encima del eje $t$ corresponden a un incremento de $v$ (área "positiva"), mientras que las que quedan debajo del eje indican una reducción de $v$ (área "negativa").

 Hibbeler R. Engineering Mechanics: Dynamics

    De igual forma, si se tiene la gráfica de $v-t$, como se muestra en la figura al lado, la gráfica de $s-t$ se construye mediante $v=ds/dt$, escrita como

$$\underbrace{\Delta s}_{\text{desplazamiento}}=\underbrace{\int vdt}_{\text{área bajo la curva de v-t}}$$

igual que en la anterior gráfica, se parte de la posición inicial de la partícula, $s_0$ y luego se va adicionando pequeños incrementos de área ($\Delta s$) determinados a partir de la gráfica $v-t$.

Los segmentos de la gráfica $a-t$ pueden describirse mediante una serie de ecuaciones, que a su vez pueden integrarse para obtener los segmentos correspondientes a l gráfica $v-t$. Por lo tanto, si la gráfica $a-t$ es lineal, la integración dará una gráfica para $v-t$ cuadrática, y para $s-t$, una cúbica.

### Gráficas de $v-s$ y $a-s$

 Hibbeler R. Engineering Mechanics: Dynamics

    Los puntos de la gráfica $v-s$ se determinana por medio de la ecuación $vdv=ads$. Integrando esta ecuación en los límites $v=v_0$ con $s=s_0$ y $v=v_1$ con $s=s_1$, se tiene

$$\frac{1}{2}\left( v_1^2 - v_0^2\right)=\underbrace{\int_{s_0}^{s_1} ads}_{\text{área bajo la curva de a-s}}$$

Si se determina el área de color gris y se conoce la velocidad $v_0$ en $s_0=0$, entonces $v_1=\left( 2 \int_{s_0}^{s_1}ads+v_0^2\right)^{1/2}$. De esta forma se pueden marcar puntos sucesivos en la gráfica $v-s$.

 Hibbeler R. Engineering Mechanics: Dynamics

Si se conoce la gráfica $v-s$, la aceleración $a$ en cualquier posición $s$ se determinar por $ads=vdv$, que se escribe como

$$\underbrace{a}_\text{aceleración}=\underbrace{v \left( \frac{dv}{ds} \right)}_{\text{velocidad por la pendiente de la gráfica de v-s}}$$

Entonces, en cualquier punto $(s,v)$ se mide la pendiente $ds/dv$ de la gráfica de $v-s$. Entonces, con $v$ y $dv/ds$ conocidas, se calcula el valor de $a$.

La gráfica de $v-s$ también se construye a partir de la gráfica de $a-s$ o viceversa, por aproximación de la gráfica conocida en varios intervalos con funciones matemáticas, $v=f(s)$ o $a=g(s)$ y luego por $ads=vdv$ para obtener la otra gráfica.

### Ejemplos

#### Desplazamiento en bicicleta

 Ejemplo 12.6: Hibbeler R. Engineering Mechanics: Dynamics

Una bicicleta rueda a lo largo de una carretera recta de modo que la gráfica de la figura describe su posición. Construya las gráficas de $v-t$ y $a-t$ en el intervalo $0 \leq t \leq 30 s$

***Solución analítica:***

- Gráfica $v-t$: teniendo que $v=ds/dt$, la gráfica de $v-t$ se determina diferenciando las ecuaciones que definen la gráfica $s-t$. En la gráfica se observan dos segmentos:

  - ***Segmento 1:*** en el intervalo $0\leq t<10s$ la función de desplazamiento está dada por la ecuación $s=t^2 pies$, diferenciando esta ecuación respecto al tiempo para determinar la velocidad en ese trayecto, quedaría $v=\frac{ds}{dt}=(2t) pies/s$.

  - ***Segmento 2:*** en el intervalo $10s\leq t<30s$ la función de desplazamiento está dada por la ecuación $s=(20t-100)pies$, diferenciando esta ecuación respecto al tiempo para determinar la velocidad en ese trayecto, quedaría $v=\frac{ds}{dt}=(20)pies/s$.

|$0\leq t<s$|$s=t^2 pies$|$v=\frac{ds}{dt}=(2t) pies/s$|
|:-:|:-:|:-:|
|$10s<t\leq 30s$|$s=(20t-100)pies$|$v=\frac{ds}{dt}=(20)pies/s$|

Se observa que la primera gráfica $v-t$ es una línea recta con pendiente $+2$, y en el segundo tramo se tiene una línea recta constante. Éstas se trazan en la gráfica

- Gráfica $a-t$: Similarmente, como $a=dv/dt$, la gráfica de $a-t$ se determina diferenciando las ecuaciones que definen la gráfica $v-t$:

  - ***Segmento 1:*** en el intervalo $0\leq t<10s$ la función de velocidad está dada por la ecuación $s=2t pies/s$, diferenciando esta ecuación respecto al tiempo para determinar la aceleración en ese trayecto, quedaría $a=\frac{dv}{dt}=(2) pies/s^2$.

  - ***Segmento 2:*** en el intervalo $10s\leq t<30s$ la función de velocidad está dada por la ecuación $v=(20)pies/s$, diferenciando esta ecuación respecto al tiempo para determinar la aceleración en ese trayecto, quedaría $a=\frac{dv}{dt}=(0)pies/s^2$.

Se observa que el primer tramo de la gráfica $a-t$ es una constante de valor $2$, y en el segundo tramo también se tiene una constante, pero de valor cero, $0$.

***Solución computacional:***

Igual que en los primeros ejemplos, se empleará el módulo `sympy` de `python` para realizar los cálculos correspondientes, de forma computacional.

```python
from sympy import *
import seaborn as sns
t = symbols('t')
init_printing(use_latex='mathjax')
```

```python
# definición de las funciones a evaluar
def s1(t):
    return t**2

def s2(t):
    return 20 * t - 100
```

```python
# Gráfica s-t
sns.set()
sns.set_style("whitegrid", {'grid.linestyle': '--'})
plot((s1(t), (t,0,10)), (s2(t), (t,10,30)));
```

```python
#Gráfica v-t
plot((diff(s1(t),t), (t,0,10)), (diff(s2(t),t), (t,10,30)));
```

```python
#Gráfica a-t
plot((diff(s1(t),t,2), (t,0,10)), (diff(s2(t),t,2), (t,10,30)));
```

[nbviewer](https://nbviewer.jupyter.org/github/carlosalvarezh/Dinamica/blob/main/C01_CinematicaCineticaParticulas.ipynb)