```pyspark
from IPython.display import Image
Image(url='http://python.org/images/python-logo.gif')

```

# IPython notebook

```pyspark
Image(url='http://ipython.org/_static/IPy_header.png')
```

```pyspark
Image(url='http://jupyter.org/images/jupyter-sq-text.svg', width=300, height=300)
```

# Jupyter
IPython will continue to exist as a Python kernel for Jupyter, but the notebook and other language-agnostic parts of IPython will move to new projects under the Jupyter name. IPython 3.0 will be the last monolithic release of IPython.

- Let's continue to call this IPython for now

# IPython
- interactive shell
- browser-based notebook (this)
- 'Kernel'
- great support for visualization library (eg. matplotlib)
- built on pyzmq, tornado

## IPython notebook
### Notebook == browser-based REPL
IPython Notebook is a web-based interactive computational environment for creating IPython notebooks. An IPython notebook is a JSON document containing an ordered list of input/output cells which can contain code, text, mathematics, plots and rich media.

## matplotlib
matplotlib tries to make easy things easy and hard things possible. You can generate plots, histograms, power spectra, bar charts, errorcharts, scatterplots, etc, with just a few lines of code, with familiar MATLAB APIs.

```py
plt.barh(y_pos, performance, xerr=error, align='center', alpha=0.4)
plt.yticks(y_pos, people)
plt.xlabel('Performance')
plt.title('How fast do you want to go today?')
plt.show()
```

## PySpark
Spark on Python, this serves as the Kernel, integrating with IPython
- Each notebook spins up a new instance of the Kernal (ie. PySpark running as the Spark Driver)

## Environment

- CentOS 6.5
- CDH 5.3.0 cluster
- Spark
- PySpark [(YARN client mode)](http://spark.apache.org/docs/latest/running-on-yarn.html)
- matplotlib and other packages installed

# Maxwell's Equations
\begin{align}
\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = \frac{4\pi}{c}\vec{\mathbf{j}} \\   \nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\
\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\
\nabla \cdot \vec{\mathbf{B}} & = 0
\end{align}

```Python
# Markdown code block
if not full:
    print 'eat more!'
```

```pyspark
import matplotlib
matplotlib.__version__
```

    '1.4.3'

# Spark

```pyspark
print sys.version
print sc.version

```

    VBox()

    Starting Spark application

ID	YARN Application ID	Kind	State	Spark UI	Driver log	Current session?

2	application_1571347151292_0003	pyspark	idle	Link	Link	✔

    FloatProgress(value=0.0, bar_style='info', description='Progress:', layout=Layout(height='25px', width='50%'),…

    SparkSession available as 'spark'.

    FloatProgress(value=0.0, bar_style='info', description='Progress:', layout=Layout(height='25px', width='50%'),…

    Missing parentheses in call to 'print'. Did you mean print(sys.version)? (<stdin>, line 1)
      File "<stdin>", line 1
        print sys.version
                ^
    SyntaxError: Missing parentheses in call to 'print'. Did you mean print(sys.version)?

```pyspark
lines = sc.parallelize(['This is Bezos Jeff, not Jeff Bezos. Its fun to have fun,','but you have to know how.'])
wordcounts = lines.map( lambda x: x.replace(',',' ').replace('.',' ').replace('-',' ').lower()) \
        .flatMap(lambda x: x.split()) \
        .map(lambda x: (x, 1)) \
        .reduceByKey(lambda x,y:x+y) \
        .map(lambda x:(x[1],x[0])) \
        .sortByKey(False)
wordcounts.take(10)

```

    VBox()

    FloatProgress(value=0.0, bar_style='info', description='Progress:', layout=Layout(height='25px', width='50%'),…

    [(2, 'bezos'), (2, 'have'), (2, 'to'), (2, 'jeff'), (2, 'fun'), (1, 'but'), (1, 'you'), (1, 'how'), (1, 'this'), (1, 'is')]

```pyspark
pagecounts = sc.textFile('/user/fcheung/pagecounts') # HDFS
pagecounts.take(10)
```

    VBox()

    FloatProgress(value=0.0, bar_style='info', description='Progress:', layout=Layout(height='25px', width='50%'),…

    An error occurred while calling o154.partitions.
    : org.apache.hadoop.mapred.InvalidInputException: Input path does not exist: hdfs://ip-10-0-1-35.ec2.internal:8020/user/fcheung/pagecounts
    	at org.apache.hadoop.mapred.FileInputFormat.singleThreadedListStatus(FileInputFormat.java:260)
    	at org.apache.hadoop.mapred.FileInputFormat.listStatus(FileInputFormat.java:208)
    	at org.apache.hadoop.mapred.FileInputFormat.getSplits(FileInputFormat.java:288)
    	at org.apache.spark.rdd.HadoopRDD.getPartitions(HadoopRDD.scala:204)
    	at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:253)
    	at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:251)
    	at scala.Option.getOrElse(Option.scala:121)
    	at org.apache.spark.rdd.RDD.partitions(RDD.scala:251)
    	at org.apache.spark.rdd.MapPartitionsRDD.getPartitions(MapPartitionsRDD.scala:49)
    	at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:253)
    	at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:251)
    	at scala.Option.getOrElse(Option.scala:121)
    	at org.apache.spark.rdd.RDD.partitions(RDD.scala:251)
    	at org.apache.spark.api.java.JavaRDDLike$class.partitions(JavaRDDLike.scala:61)
    	at org.apache.spark.api.java.AbstractJavaRDDLike.partitions(JavaRDDLike.scala:45)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at py4j.reflection.MethodInvoker.invoke(MethodInvoker.java:244)
    	at py4j.reflection.ReflectionEngine.invoke(ReflectionEngine.java:357)
    	at py4j.Gateway.invoke(Gateway.java:282)
    	at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)
    	at py4j.commands.CallCommand.execute(CallCommand.java:79)
    	at py4j.GatewayConnection.run(GatewayConnection.java:238)
    	at java.lang.Thread.run(Thread.java:748)

    Traceback (most recent call last):
      File "/usr/lib/spark/python/lib/pyspark.zip/pyspark/rdd.py", line 1327, in take
        totalParts = self.getNumPartitions()
      File "/usr/lib/spark/python/lib/pyspark.zip/pyspark/rdd.py", line 391, in getNumPartitions
        return self._jrdd.partitions().size()
      File "/usr/lib/spark/python/lib/py4j-0.10.7-src.zip/py4j/java_gateway.py", line 1257, in __call__
        answer, self.gateway_client, self.target_id, self.name)
      File "/usr/lib/spark/python/lib/pyspark.zip/pyspark/sql/utils.py", line 63, in deco
        return f(*a, **kw)
      File "/usr/lib/spark/python/lib/py4j-0.10.7-src.zip/py4j/protocol.py", line 328, in get_return_value
        format(target_id, ".", name), value)
    py4j.protocol.Py4JJavaError: An error occurred while calling o154.partitions.
    : org.apache.hadoop.mapred.InvalidInputException: Input path does not exist: hdfs://ip-10-0-1-35.ec2.internal:8020/user/fcheung/pagecounts
    	at org.apache.hadoop.mapred.FileInputFormat.singleThreadedListStatus(FileInputFormat.java:260)
    	at org.apache.hadoop.mapred.FileInputFormat.listStatus(FileInputFormat.java:208)
    	at org.apache.hadoop.mapred.FileInputFormat.getSplits(FileInputFormat.java:288)
    	at org.apache.spark.rdd.HadoopRDD.getPartitions(HadoopRDD.scala:204)
    	at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:253)
    	at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:251)
    	at scala.Option.getOrElse(Option.scala:121)
    	at org.apache.spark.rdd.RDD.partitions(RDD.scala:251)
    	at org.apache.spark.rdd.MapPartitionsRDD.getPartitions(MapPartitionsRDD.scala:49)
    	at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:253)
    	at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:251)
    	at scala.Option.getOrElse(Option.scala:121)
    	at org.apache.spark.rdd.RDD.partitions(RDD.scala:251)
    	at org.apache.spark.api.java.JavaRDDLike$class.partitions(JavaRDDLike.scala:61)
    	at org.apache.spark.api.java.AbstractJavaRDDLike.partitions(JavaRDDLike.scala:45)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at py4j.reflection.MethodInvoker.invoke(MethodInvoker.java:244)
    	at py4j.reflection.ReflectionEngine.invoke(ReflectionEngine.java:357)
    	at py4j.Gateway.invoke(Gateway.java:282)
    	at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)
    	at py4j.commands.CallCommand.execute(CallCommand.java:79)
    	at py4j.GatewayConnection.run(GatewayConnection.java:238)
    	at java.lang.Thread.run(Thread.java:748)

```pyspark
enPages = pagecounts.filter(lambda x: x.split(" ")[1] == "en")
enPages.map(lambda x: x.split(" ")).map(lambda x: (x[2], int(x[3]))).reduceByKey(lambda x, y: x + y, 40).filter(lambda x: x[1] > 200000).map(lambda x: (x[1], x[0])).collect()
# This runs in the cluster
```

    [(451126, u'Main_Page'), (1066734, u'404_error/'), (468159, u'Special:Search')]

# To be or not to be

```pyspark
words = sc.textFile('/user/fcheung/hamlet.txt')
words.take(5)
```

    [u'', u'1604', u'', u'', u'THE TRAGEDY OF HAMLET, PRINCE OF DENMARK']

```pyspark
import re
hamlet = words.flatMap(lambda line: re.split('\W+', line.lower().strip()))
hamlet.take(5)
```

    [u'', u'1604', u'', u'', u'the']

```pyspark
tmp = hamlet.filter(lambda x: len(x) > 2 )
print tmp.take(5)
```

    [u'1604', u'the', u'tragedy', u'hamlet', u'prince']

```pyspark
tmp = tmp.map(lambda word: (word, 1))
tmp.take(5)
```

    [(u'1604', 1), (u'the', 1), (u'tragedy', 1), (u'hamlet', 1), (u'prince', 1)]

```pyspark
tmp = tmp.reduceByKey(lambda a, b: a + b)
tmp.take(5)

```

    [(u'pardon', 9),
     (u'nunnery', 5),
     (u'lunacies', 1),
     (u'needful', 1),
     (u'foul', 12)]

```pyspark
tmp = tmp.map(lambda x: (x[1], x[0])).sortByKey(False)
tmp.take(20)
```

    [(1091, u'the'),
     (969, u'and'),
     (558, u'you'),
     (405, u'that'),
     (358, u'ham'),
     (315, u'not'),
     (304, u'his'),
     (300, u'this'),
     (278, u'with'),
     (274, u'but'),
     (252, u'for'),
     (242, u'your'),
     (226, u'lord'),
     (219, u'what'),
     (203, u'king'),
     (197, u'him'),
     (183, u'have'),
     (173, u'will'),
     (132, u'are'),
     (125, u'all')]

```pyspark
tmp = tmp.map(lambda x: (x[1], x[0]))
tmp.take(20)
```

    [(u'the', 1091),
     (u'and', 969),
     (u'you', 558),
     (u'that', 405),
     (u'ham', 358),
     (u'not', 315),
     (u'his', 304),
     (u'this', 300),
     (u'with', 278),
     (u'but', 274),
     (u'for', 252),
     (u'your', 242),
     (u'lord', 226),
     (u'what', 219),
     (u'king', 203),
     (u'him', 197),
     (u'have', 183),
     (u'will', 173),
     (u'are', 132),
     (u'all', 125)]

```pyspark
%matplotlib inline
import matplotlib.pyplot as plt

def plot(words):
    values = map(lambda x: x[1], words)
    labels = map(lambda x: x[0], words)
    plt.barh(range(len(values)), values, color='grey')
    plt.yticks(range(len(values)), labels)
    plt.show()
```

```pyspark
plot(tmp.take(15))
```

# Word vector
Word2Vec computes distributed vector representation of words. Distributed vector representation is showed to be useful in many natural language processing applications such as named entity recognition, disambiguation, parsing, tagging and machine translation.
https://code.google.com/p/word2vec/

Spark implements the Skip-gram approach. With Skip-gram we want to predict a window of words given a single word.

It was recently shown that the word vectors capture many linguistic regularities, for example vector operations vector('Paris') - vector('France') + vector('Italy') results in a vector that is very close to vector('Rome'), and vector('king') - vector('man') + vector('woman') is close to vector('queen') [3, 1].

## Data set
Wikipedia dump http://mattmahoney.net/dc/textdata
`grep -o -E '\w+(\W+\w+){0,15}' text8 > text8_lines`
then randomly sampled to ~200k lines

```pyspark
from pyspark.mllib.feature import Word2Vec

textpath = '/user/fcheung/text8_linessmall'
inp = sc.textFile(textpath).map(lambda row: row.split(" "))

word2vec = Word2Vec()
model = word2vec.fit(inp)

# This takes a while....
```

```pyspark
synonyms = model.findSynonyms('car', 40)

for word, cosine_distance in synonyms:
  print "{}: {}".format(word, cosine_distance)

```

    driver: 0.717452287674
    accident: 0.540586173534
    pilot: 0.534710288048
    cable: 0.533736109734
    flying: 0.524660527706
    marlin: 0.52224111557
    slim: 0.515641212463
    revolver: 0.512815892696
    launched: 0.512356519699
    serie: 0.511943757534
    racing: 0.507736027241
    geoff: 0.507051408291
    mickey: 0.502854526043
    engined: 0.496125161648
    miniaturized: 0.495229810476
    harrier: 0.49293076992
    mclaren: 0.490967661142
    rf: 0.48476678133
    fighter: 0.482738018036
    passenger: 0.480480760336
    bomb: 0.476699143648
    mctaggart: 0.474561154842
    chase: 0.473450392485
    race: 0.472357422113
    crash: 0.472341090441
    kirby: 0.472037523985
    drunken: 0.471260607243
    window: 0.470358043909
    raf: 0.470099359751
    button: 0.466545432806
    factory: 0.46252438426
    killer: 0.462217181921
    shot: 0.461643457413
    trainer: 0.459573149681
    jockey: 0.456390231848
    runner: 0.454748958349
    mario: 0.454734921455
    lane: 0.453607857227
    singh: 0.453275740147
    debuts: 0.451825499535

```pyspark
values = map(lambda x: x[1], synonyms)
labels = map(lambda x: x[0], synonyms)
plt.barh(range(len(values)), values, color='blue')
plt.yticks(range(len(values)), labels)
plt.show()

```

```pyspark
from wordcloud import WordCloud, STOPWORDS

words = " ".join([x[0] for x in synonyms for times in range(0, int(x[1]*10))])

wordcloud = WordCloud(font_path='/home/fcheung/CabinSketch-Bold.ttf',
                      stopwords=STOPWORDS,
                      background_color='white',
                      width=1800,
                      height=1400
                     ).generate(words)

plt.imshow(wordcloud)
plt.axis('off')
plt.show()
```

#### wordcloud package uses PIL/Image

```pyspark

```


##### 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.
```

# QAOA: Max-Cut

    View on QuantumAI

    Run in Google Colab

    View source on GitHub

    Download notebook

In this tutorial, we implement the quantum approximate optimization algorithm (QAOA) for determining the Max-Cut of the Bristlecone processor's hardware graph (with random edge weights). To do so, we will:

1. Define a random set of weights over the hardware graph.
2. Construct a QAOA circuit using Cirq.
3. Calculate the expected value of the QAOA cost function.
4. Create an outer loop optimization to minimize the cost function.
5. Compare cuts found from QAOA with random cuts.

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

## 1. Defining a random set of weights over the hardware graph
In order to make the problem easily embeddable on a quantum device, we will look at the problem of Max-Cut on the same graph that the device's qubit connectivity defines, but with random valued edge weights.

```
import cirq
import sympy
import numpy as np
import matplotlib.pyplot as plt
working_device = cirq.google.Bristlecone
print(working_device)
```

                                                 (0, 5)────(0, 6)
                                                 │         │
                                                 │         │
                                        (1, 4)───(1, 5)────(1, 6)────(1, 7)
                                        │        │         │         │
                                        │        │         │         │
                               (2, 3)───(2, 4)───(2, 5)────(2, 6)────(2, 7)───(2, 8)
                               │        │        │         │         │        │
                               │        │        │         │         │        │
                      (3, 2)───(3, 3)───(3, 4)───(3, 5)────(3, 6)────(3, 7)───(3, 8)───(3, 9)
                      │        │        │        │         │         │        │        │
                      │        │        │        │         │         │        │        │
             (4, 1)───(4, 2)───(4, 3)───(4, 4)───(4, 5)────(4, 6)────(4, 7)───(4, 8)───(4, 9)───(4, 10)
             │        │        │        │        │         │         │        │        │        │
             │        │        │        │        │         │         │        │        │        │
    (5, 0)───(5, 1)───(5, 2)───(5, 3)───(5, 4)───(5, 5)────(5, 6)────(5, 7)───(5, 8)───(5, 9)───(5, 10)───(5, 11)
             │        │        │        │        │         │         │        │        │        │
             │        │        │        │        │         │         │        │        │        │
             (6, 1)───(6, 2)───(6, 3)───(6, 4)───(6, 5)────(6, 6)────(6, 7)───(6, 8)───(6, 9)───(6, 10)
                      │        │        │        │         │         │        │        │
                      │        │        │        │         │         │        │        │
                      (7, 2)───(7, 3)───(7, 4)───(7, 5)────(7, 6)────(7, 7)───(7, 8)───(7, 9)
                               │        │        │         │         │        │
                               │        │        │         │         │        │
                               (8, 3)───(8, 4)───(8, 5)────(8, 6)────(8, 7)───(8, 8)
                                        │        │         │         │
                                        │        │         │         │
                                        (9, 4)───(9, 5)────(9, 6)────(9, 7)
                                                 │         │
                                                 │         │
                                                 (10, 5)───(10, 6)

Since a circuit covering the entire Bristlecone device cannot be easily simulated, a small subset of the device graph will be used instead.

```
import networkx as nx

# Set the seed to determine the problem instance.
np.random.seed(seed=11)

# Identify working qubits from the device.
device_qubits = working_device.qubits
working_qubits = sorted(device_qubits)[:12]

# Populate a networkx graph with working_qubits as nodes.
working_graph = nx.Graph()
for qubit in working_qubits:
  working_graph.add_node(qubit)

# Pair up all neighbors with random weights in working_graph.
for qubit in working_qubits:
  for neighbor in working_device.neighbors_of(qubit):
    if neighbor in working_graph:
      # Generate a randomly weighted edge between them. Here the weighting
      # is a random 2 decimal floating point between 0 and 5.
      working_graph.add_edge(
          qubit, neighbor, weight=np.random.randint(0, 500) / 100
      )

nx.draw_circular(working_graph, node_size=1000, with_labels=True)
plt.show()
```

## 2. Construct the QAOA circuit
Now that we have created a Max-Cut problem graph, it's time to generate the QAOA circuit following [Farhi et al.](https://arxiv.org/abs/1411.4028). For simplicity $p = 1$ is chosen.

```
from cirq.contrib.svg import SVGCircuit

# Symbols for the rotation angles in the QAOA circuit.
alpha = sympy.Symbol('alpha')
beta = sympy.Symbol('beta')

qaoa_circuit = cirq.Circuit(
    # Prepare uniform superposition on working_qubits == working_graph.nodes
    cirq.H.on_each(working_graph.nodes()),

    # Do ZZ operations between neighbors u, v in the graph. Here, u is a qubit,
    # v is its neighboring qubit, and w is the weight between these qubits.
    (cirq.ZZ(u, v) ** (alpha * w['weight']) for (u, v, w) in working_graph.edges(data=True)),

    # Apply X operations along all nodes of the graph. Again working_graph's
    # nodes are the working_qubits. Note here we use a moment
    # which will force all of the gates into the same line.
    cirq.Moment(cirq.X(qubit) ** beta for qubit in working_graph.nodes()),

    # All relevant things can be computed in the computational basis.
    (cirq.measure(qubit) for qubit in working_graph.nodes()),
)
SVGCircuit(qaoa_circuit)
```

    findfont: Font family ['Arial'] not found. Falling back to DejaVu Sans.

## 3. Calculating the expected value of the QAOA cost Hamiltonian
Now that we have created a parameterized QAOA circuit, we need a way to calculate expectation values of the cost Hamiltonian. For Max-Cut, the cost Hamiltonian is

$$
    H_C = \frac{1}{2} \sum_{\langle i, j\rangle} w_{ij} (1 - Z_i Z_j )
$$

where $\langle i, j \rangle$ denotes neighboring qubits, $w_{ij}$ is the weight of edge $ij$, and $Z$ is the usual Pauli-$Z$ matrix. The expectation value of this cost Hamiltonian is $\langle \alpha, \beta | H_C | \alpha, \beta \rangle$ where $|\alpha, \beta\rangle$ is the quantum state prepared by our `qaoa_circuit`. This is the cost function we need to estimate.

> Pauli-$Z$ has eigenvalues $\pm 1$. If qubits $i$ and $j$ are in the same eigenspace, then $\langle Z_i Z_j \rangle = 1$ and so $\frac{1}{2} w_{ij} \langle 1 - Z_i Z_j \rangle = 0$. In the Max-Cut language, this means that edge $ij$ does not contribute to the cost. If qubits $i$ and $j$ are in the opposite eigenspace, then $\langle Z_i Z_j \rangle = -1$ and so $\frac{1}{2} w_{ij} \langle 1 - Z_i Z_j \rangle = w_{ij}$. In the Max-Cut language, this means that edge $ij$ contributes its weight $w_{ij}$ to the cost.

To estimate the cost function, we need to estimate the (weighted) sum of all $ZZ$ pairs in the graph. Since these terms are diagonal in the same basis (namely, the computational basis), they can measured simultaneously. Given a set of measurements (samples), the function below estimates the cost function.

> *Note*: We say "estimate the cost" instead of "compute the cost" since we are sampling from the circuit. This is how the cost would be evaluated when running QAOA on a real quantum processor.

```
def estimate_cost(graph, samples):
    """Estimate the cost function of the QAOA on the given graph using the
    provided computational basis bitstrings."""
    cost_value = 0.0

    # Loop over edge pairs and compute contribution.
    for u, v, w in graph.edges(data=True):
      u_samples = samples[str(u)]
      v_samples = samples[str(v)]

      # Determine if it was a +1 or -1 eigenvalue.
      u_signs = (-1)**u_samples
      v_signs = (-1)**v_samples
      term_signs = u_signs * v_signs

      # Add scaled term to total cost.
      term_val = np.mean(term_signs) * w['weight']
      cost_value += term_val

    return -cost_value
```

Now we can sample from the `qaoa_circuit` and use `estimate_expectation` to calculate the expectation value of the cost function for the circuit. Below, we use arbitrary values for $\alpha$ and $\beta$.

```
alpha_value = np.pi / 4
beta_value = np.pi / 2
sim = cirq.Simulator()

sample_results = sim.sample(
    qaoa_circuit,
    params={alpha: alpha_value, beta: beta_value},
    repetitions=20_000
)
print(f'Alpha = {round(alpha_value, 3)} Beta = {round(beta_value, 3)}')
print(f'Estimated cost: {estimate_cost(working_graph, sample_results)}')
```

    Alpha = 0.785 Beta = 1.571
    Estimated cost: -0.22279300000000013

## 4. Outer loop optimization
Now that we can compute the cost function, we want to find the optimal cost. There are lots of different techniques to choose optimal parameters for the `qaoa_circuit`. Since there are only two parameters here ($\alpha$ and $\beta$), we can keep things simple and sweep over incremental pairings using `np.linspace` and track the minimum value found along the way.

```
# Set the grid size = number of points in the interval [0, 2π).
grid_size = 5

exp_values = np.empty((grid_size, grid_size))
par_values = np.empty((grid_size, grid_size, 2))

for i, alpha_value in enumerate(np.linspace(0, 2 * np.pi, grid_size)):
  for j, beta_value in enumerate(np.linspace(0, 2 * np.pi, grid_size)):
    samples = sim.sample(
        qaoa_circuit,
        params={alpha: alpha_value, beta: beta_value},
        repetitions=20000
    )
    exp_values[i][j] = estimate_cost(working_graph, samples)
    par_values[i][j] = alpha_value, beta_value
```

We can now visualize the cost as a function of $\alpha$ and $\beta$.

```
plt.title('Heatmap of QAOA Cost Function Value')
plt.xlabel(r'$\alpha$')
plt.ylabel(r'$\beta$')
plt.imshow(exp_values);
```

This heatmap is coarse because we selected a small `grid_size`. To see more detail in the heatmap, one can increase the `grid_size`.

## 5. Compare cuts

We now compare the optimal cut found by QAOA to a randomly selected cut. The helper function draws the `working_graph` and colors nodes in different sets different colors. Additionally, we print out the cost function for the given cut.

```
def output_cut(S_partition):
  """Plot and output the graph cut information."""

  # Generate the colors.
  coloring = []
  for node in working_graph:
    if node in S_partition:
      coloring.append('blue')
    else:
      coloring.append('red')

  # Get the weights
  edges = working_graph.edges(data=True)
  weights = [w['weight'] for (u,v, w) in edges]

  nx.draw_circular(
      working_graph,
      node_color=coloring,
      node_size=1000,
      with_labels=True,
      width=weights)
  plt.show()
  size = nx.cut_size(working_graph, S_partition, weight='weight')
  print(f'Cut size: {size}')
```

As an example, we can test this function with all nodes in the same set, for which the cut size should be zero.

```
# Test with the empty S and all nodes placed in T.
output_cut([])
```

To get cuts using the QAOA we will first need to extract the best control parameters found during the sweep:

```
best_exp_index = np.unravel_index(np.argmax(exp_values), exp_values.shape)
best_parameters = par_values[best_exp_index]
print(f'Best control parameters: {best_parameters}')
```

    Best control parameters: [3.14159265 6.28318531]

Each bitstring can be seen as a candidate cut in the graph. The qubits that measured 0 correspond to that qubit being in one cut partition and a qubit that measured to 1 corresponds to that qubit being in the other cut partition. Now that we've found good parameters for the `qaoa_circuit`, we can just sample some bistrings, iterate over them and pick the one that gives the best cut:

```
# Number of candidate cuts to sample.
num_cuts = 100
candidate_cuts = sim.sample(
    qaoa_circuit,
    params={alpha: best_parameters[0], beta: best_parameters[1]},
    repetitions=num_cuts
)

# Variables to store best cut partitions and cut size.
best_qaoa_S_partition = set()
best_qaoa_T_partition = set()
best_qaoa_cut_size = -np.inf

# Analyze each candidate cut.
for i in range(num_cuts):
  candidate = candidate_cuts.iloc[i]
  one_qubits = set(candidate[candidate==1].index)
  S_partition = set()
  T_partition = set()
  for node in working_graph:
    if str(node) in one_qubits:
      # If a one was measured add node to S partition.
      S_partition.add(node)
    else:
      # Otherwise a zero was measured so add to T partition.
      T_partition.add(node)

  cut_size = nx.cut_size(
      working_graph, S_partition, T_partition, weight='weight')

  # If you found a better cut update best_qaoa_cut variables.
  if cut_size > best_qaoa_cut_size:
    best_qaoa_cut_size = cut_size
    best_qaoa_S_partition = S_partition
    best_qaoa_T_partition = T_partition
```

The QAOA is known to do just a little better better than random guessing for Max-Cut on 3-regular graphs at `p=1`. You can use very similar logic to the code above, but now instead of relying on the QAOA to decied your `S_partition` and `T_partition` you can just pick then randomly:

```
import random

best_random_S_partition = set()
best_random_T_partition = set()
best_random_cut_size = -9999

# Randomly build candidate sets.
for i in range(num_cuts):
  S_partition = set()
  T_partition = set()
  for node in working_graph:
    if random.random() > 0.5:
      # If we flip heads add to S.
      S_partition.add(node)
    else:
      # Otherwise add to T.
      T_partition.add(node)

  cut_size = nx.cut_size(
      working_graph, S_partition, T_partition, weight='weight')

  # If you found a better cut update best_random_cut variables.
  if cut_size > best_random_cut_size:
    best_random_cut_size = cut_size
    best_random_S_partition = S_partition
    best_random_T_partition = T_partition
```

```
print('-----QAOA-----')
output_cut(best_qaoa_S_partition)

print('\n\n-----RANDOM-----')
output_cut(best_random_S_partition)
```

For this problem instance, one should see that $p = 1$ QAOA performs better, on average, than randomly guessing.


```python
from IPython.core.display import display_html
from urllib.request import urlopen

cssurl = 'http://j.mp/1DnuN9M'
display_html(urlopen(cssurl).read(), raw=True)
```

<link href='http://fonts.googleapis.com/css?family=EB+Garamond' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Lato:100,100italic' rel='stylesheet' type='text/css'>

<style>
	@font-face{
   		font-family: "Computer Modern";
        	src: url('http://mirrors.ctan.org/fonts/cm-unicode/fonts/otf/cmunss.otf');}

        div.cell{
	        max-width:    800px;
	        margin-left:  auto;
	        margin-right: auto;}

	h1 {
        	font-family: 'Lato', sans-serif;}

	h2 {
        	font-family: 'Lato', serif;}

	h3{
		font-family:   'Lato', serif;
        	margin-top:    12px;
		margin-bottom: 3px;}

        h4{
		font-family: 'Lato', serif;}

	h5 {
        	font-family: 'Lato', serif;}

	div.text_cell_render{
        	font-family:  'EB Garamond', 'Computer Modern', 'Helvetica Neue', Arial, Helvetica, Geneva, sans-serif;
	        line-height:  140%;
	        font-size:    14pt;
		max-width:    650px;
		margin-left:  auto;
        	margin-right: auto;}

	.CodeMirror{
        	font-family: 'Consolas';}

	.text_cell_render h1 {
	        font-weight:   100;
	        font-size:     48pt;
		line-height:   100%;
	        color:         #CD2305;
	        margin-bottom: 0.5em;
	        margin-top:    0.5em;
	        display:       block;}

	.text_cell_render h2 {
        	font-weight:   100;
        	font-size:     36pt;}

	.text_cell_render h3 {
        	font-weight:   100;
        	font-size:     21pt;}

	.text_cell_render h4 {
        	font-weight:   100;
        	font-size:     18pt;}

	.text_cell_render h5 {
	        font-weight:   100;
	        font-size:     16pt;
	        color:         #CD2305;
	        font-style:    italic;
	        margin-bottom: 0.5em;
	        margin-top:    0.5em;
	        display:       block;}

	.text_cell_render h6 {
	        font-weight:   100;
	        font-size:     14pt;
	        color:         #CD2305;
	        font-style:    italic;
	        margin-bottom: 0.5em;
	        margin-top:    0.5em;
	        display:       block;}

	.warning{
	    	background-color: #FFFFE0;
	    	border-color: #FFCC99;
	    	border-left: 5px solid #FFCC99;
	    	padding: 0.5em;}

	.error{
	    	background-color: #fcf2f2;
	    	border-color: #dFb5b4;
	    	border-left: 5px solid #dfb5b4;
	    	padding: 0.5em;}

</style>

# Tarea 8

## Transformada de Laplace de una integral de convolución

Queremos obtener:

$$
\mathcal{L} \left\{ \int_{-\tau}^0 G(\theta) x(\tau + \theta) d\theta \right\}
$$

Podemos definir la integral de convolución para dos funciones continuas $f(t)$ y $g(t)$, tales que la convolución $(f*g)(t)$ es de la forma:

$$
(f*g)(t) = \int_0^t f(t - \tau) g(\tau) d\tau
$$

y la transformada de Laplace de esta integral de convolución es:

$$
\mathcal{L} \left\{ (f*g)(t) \right\} = F(s)G(s)
$$

por lo que nos interesa poner nuestra integral original de manera que sea una integral de convolución.

Podemos ver que al aplicar el cambio de variable $\delta = \theta + \tau$, cuando $\theta$ variaba de $-\tau \to 0$, $\delta$ variará de $0 \to \tau$ y el diferencial $d\theta$ es equivalente a $d\delta$, por lo que nuestra integral quedará:

$$
\mathcal{L} \left\{ \int_{0}^{\tau} G(\delta - \tau) x(\tau + \delta - \tau) d\delta \right\} = \mathcal{L} \left\{ \int_{0}^{\tau} G(\delta - \tau) x(\delta) d\delta \right\}
$$

y etsa integral ya es de la forma de la integral de convolución, por lo que podemos escribirla como:

$$
\mathcal{L} \left\{ (G*x)(t) \right\} = G(s) x(s)
$$

## Diseño de un controlador predictivo para un sistema con retardo en la entrada

Dado el sistema con retardo en la entrada:

$$
\dot{x}(t) = A x(t) + B u(t - h)
$$

$$
y(t) = C x(t)
$$

Empezaremos creando un modelo sin retardo para el diseño del controlador predictor de Smith. Si logramos diseñar un controlador $C(s)$ que estabilice de manera aceptable al sistema sin retardos, podremos diseñar otro $\tilde{C}(s)$ que tenga el mismo comportamiento agregado el efecto del retardo.

en donde $\tilde{C}(s)$ será de la forma:

es decir:

$$
\tilde{C}(s) = \frac{C(s)}{1 + C(s) \hat{G}(s) \left( 1 - e^{-sh} \right)}
$$

en donde $\hat{G}(s)$ es la parte de la función de transferencia del sistema que no incluye al retardo. Por lo que nuestra primera tarea es encontrar la función de transferencia para nuestro sistema sin el efecto del retardo.

Consideremos pues el sistema

$$
\dot{x}(t) = A x(t) + B u(t)
$$

$$
y(t) = C x(t)
$$

para el cual la función de transferencia se puede obtener por la siguiente ecuación:

$$
\hat{G}(s) = C \left( sI - A \right)^{-1} B
$$

cabe mencionar que la función de transferencia para el sistema con retardo es:

$$
G(s) = C \left( sI - A \right)^{-1} B e^{-sh}
$$

por lo que en efecto $\hat{G}(s)$ es la parte de la función de transferencia del sistema sin el efecto del retardo:

$$
G(s) = \hat{G}(s) e^{-sh}
$$

```python
# Se importan las librerias para calculo simbolico
from IPython.display import display

from sympy import var, simplify, collect, expand, solve, sin, cos, Matrix, eye, diff, Function, expand_power_base
from sympy.physics.mechanics import mlatex, mechanics_printing
mechanics_printing()
```

```python
%matplotlib inline
from matplotlib.pyplot import plot, style, figure, legend
style.use("ggplot")
```

```python
from control import tf, step, pade, acker, ss, feedback
from numpy import linspace, matrix, eye
```

```python
var("s")
```

Empezaremos con el sistema $A_1 = \begin{pmatrix} 0 & 1 \\ 0 & 0 \end{pmatrix}$, $B_1 = \begin{pmatrix} 0 \\ 1 \end{pmatrix}$, $C_1 = \begin{pmatrix} 1 & 0 \end{pmatrix}$ y $h = 1$.

```python
A1 = Matrix([[0, 1], [0, 0]])
B1 = Matrix([[0], [1]])
C1 = Matrix([[1, 0]])

G1 = (C1*(s*eye(2) - A1).inv()*B1)[0]
G1
```

```python
t = linspace(0, 10, 100)
t.max()
```

Podemos notar que la función de transferencia de este sistema es:

$$
G(s) = \frac{1}{s^2}
$$

```python
# Convertimos las matrices simbolicas en matrices de tipo numerico
A1 = matrix(A1.tolist(), dtype=float)
B1 = matrix(B1.tolist(), dtype=float)
C1 = matrix(C1.tolist(), dtype=float)
```

Para obtener dos polos en $-1$ podemos usar la función ```acker()``` para obtener las ganancias de nuestro controlador PD, el cual utilizaremos para estabilizar nuestro sistema.

```python
k1 = acker(A1, B1, (-1, -1))
k1
```

    matrix([[ 1.,  2.]])

Definimos una función que calculará todos los controladores que deseamos, segun la ecuación que ya dimos:

$$
\tilde{C}(s) = \frac{C(s)}{1 + C(s) \hat{G}(s) \left( 1 - e^{-sh} \right)}
$$

Al final gráfica la respuesta del sistema con y sin efecto del retardo, asi como con y sin controlador.

```python
def smith_predictor(A, B, C, D, k, tau=1, t=(0, 10)):
    '''Predictor de Smith

    Esta función toma los arreglos A, B, C, D de un sistema con retardo en la entrada
    y crea un controlador PD con los valores de k = [kp, kd] que estabiliza al sistema
    sin retardos. Ademas crea un controlador que estabiliza al sistema con retardo,
    dada la condición de que este sistema sea estable, y grafica la salida de los
    con y sin realimentación y con y sin retardo tau del tiempo t0 al tiempo t1
    especificados en t = (t0, t1).

    Ejemplo
    -------
    >>> A1 = [[0, 1], [0, 0]]
    >>> B1 = [[0], [1]]
    >>> C1 = [[1, 0]]
    >>> D1 = 0
    >>> tau1 = 1
    >>> t = (0, 10)
    >>> smith_predictor(A1, B1, C1, D1, [1, 2], tau, t)
    '''
    from control import ss, tf, pade, step, feedback
    from numpy import linspace
    from matplotlib.pyplot import figure, plot, legend

    kp, kd = k
    ts = linspace(t[0], t[1], 1000)

    sis = ss(A, B, C, D)
    cont = tf([kd, kp], [0, 1])

    num, den = pade(T=tau, n=10)
    delay = tf(num, den)

    delcont = ((1 - delay)*sis)

    y, t1 = step(sis, ts)
    yd, td = step(sis*delay, ts)
    ycont, tcont = step((cont*sis).feedback(), ts)
    ycontdel, tcontdel = step(feedback(feedback(cont, delcont)*sis), ts)

    f = figure(figsize=(10, 6))

    p1, = plot(td, yd)
    p2, = plot(t1, y)
    p3, = plot(tcont, ycont)
    p4, = plot(tcontdel, ycontdel)

    ax = f.gca()
    ax.set_xlim(t[0] - 0.1, t[1])
    ax.set_ylim(-0.10*ycont.max(), 1.1*ycont.max())

    ax.set_ylabel(r"$y(t)$", fontsize=20)
    ax.set_xlabel(r"$t$", fontsize=20)

    legend([p1, p2, p3, p4],
           [r"$G(s)$",
            r"$\hat{G}(s)$",
            r"$\hat{G}_F(s)$",
            r"$G_F(s)$"], loc=4, fontsize=16);
```

Por lo que si le damos nuestro sistema con las ganancias deseadas, asi como el tiempo para el que nos interesa, y el retardo, tendremos:

```python
smith_predictor(A1, B1, C1, 0, k=[3, 3], t=(0, 7), tau=1)
```

Ahora definimos el sistema $A_2 = \begin{pmatrix} 0 & 1 \\ -1 & 0 \end{pmatrix}$, $B_2 = \begin{pmatrix} 0 \\ 1 \end{pmatrix}$, $C_2 = \begin{pmatrix} 1 & 0 \end{pmatrix}$ y $h = 1$.

```python
A2 = Matrix([[0, 1], [-1, 0]])
B2 = Matrix([[0], [1]])
C2 = Matrix([[1, 0]])

G2 = (C2*(s*eye(2) - A2).inv()*B2)[0]
G2
```

Por lo que la función de transferencia de este sistema es:

$$
G(s) = \frac{1}{s^2 + 1}
$$

```python
# Convertimos las matrices simbolicas en matrices de tipo numerico
A2 = matrix(A2.tolist(), dtype=float)
B2 = matrix(B2.tolist(), dtype=float)
C2 = matrix(C2.tolist(), dtype=float)
```

Para obtener dos polos en $-1$ podemos usar la función ```acker()``` para obtener las ganancias de nuestro controlador PD.

```python
k2 = acker(A2, B2, (-1, -1))
k2
```

    matrix([[ 0.,  2.]])

Y la respuesta del sistema es:

```python
smith_predictor(A2, B2, C2, 0, k=[3, 3], t=(0, 8))
```

Puedes acceder a este notebook a traves de la página

http://bit.ly/1wiwlpl

o escaneando el siguiente código:

```python
# Codigo para generar codigo :)
from qrcode import make
img = make("http://bit.ly/1wiwlpl")
img.save("codigos/codigo8.jpg")
```

IPythonNotebooks/Sistemas con retardo en la entrada/Tarea 8.ipynb


Dinámica

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

Movimiento parabólico

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  Movimiento parabólico

1.1  Introducción

1.2  Análisis cinemático

1.3  Movimiento horizontal

1.4  Movimiento vertical

1.5  Comentarios al movimiento curvilíneo

1.6  Ejemplos movimiento parabólico

2  Movimiento curvilíneo: Componentes normal y tangencial

2.1  Introducción

2.2  Movimiento plano

2.3  Velocidad

2.4  Aceleración

2.5  Ejemplos componentes normal y tangencial

3  Movimiento curvilíneo: Componentes cilíndricos

3.1  Introducción

3.2  Coordenadas polares

3.2.1  Posición

3.2.2  Velocidad

3.2.3  Aceleración

3.3  Coordenadas cilíndricas

3.4  Derivadas respecto al tiempo

3.5  Ejemplos componentes cilíndricos

 Fuente: Wikipedia

## Movimiento parabólico

### Introducción

El [movimiento parabólico](https://en.wikipedia.org/wiki/Projectile_motion) es el realizado por cualquier objeto cuya trayectoria describe una [parábola](https://en.wikipedia.org/wiki/Parabola), y que corresponde con la trayectoria ideal de un proyectil que se mueve en un medio que no ofrece resistencia al avance y que esté sujeto a un campo gravitatorio uniforme. El movimiento parabólico es un ejemplo de un movimiento realizado por un objeto en dos dimensiones o sobre un plano. Puede considerarse como la combinación de dos movimientos que son un [movimiento rectilíneo uniforme](https://es.wikipedia.org/wiki/Movimiento_rectil%C3%ADneo_uniforme), en la dirección horizontal ($\longleftrightarrow$), y un [movimiento rectilíneo uniformemente acelerado](https://es.wikipedia.org/wiki/Movimiento_rectil%C3%ADneo_uniformemente_acelerado) en la dirección vertical ($\updownarrow$).

### Análisis cinemático

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

Considere un proyectil lanzado en el punto $(x_0, y_0)$, con una velocidad inicial de $v_0$, cuyas componentes son $v_{0x}$ y $v_{0y}$. Cuando se hace caso omiso de la resistencia del aire, la única fuerza que actúa en el proyectil es su peso, el cual hace que el proyectil tenga una aceleración dirigida hacia abajo constante de aproximadamente $a_c=g=9.81 m/s^2=32.2 pies/s^2$.

### Movimiento horizontal

Como $a_x=0$, se pueden aplicar las ecuaciones de aceleración constante vistas en el [Capítulo 1: Movimiento Rectilíneo, numeral 2.6 Aceleración constante](./C01_CinematicaCineticaParticulas_MovRectilineo.ipynb#ac), resultando en:

\begin{equation*}
\begin{array}{crl}
\left(\underrightarrow{+}\right) &v=&v_0+a_ct&                   \quad &v_x=v_{0x} \\
\left(\underrightarrow{+}\right) &x=&x_0+v_0t+\frac{1}{2}a_ct^2& \quad &x=x_0+v_{0x}t \\
\left(\underrightarrow{+}\right) &v^2=&v_0^2+2a_c(x-x_0)&        \quad &v_x=v_{0x} \\
\end{array}
\label{eq:Ec3_1} \tag{3.1}
\end{equation*}

### Movimiento vertical

Estableciendo el sistema de coordenadas con el eje $y$ positivo hacia arriba, se tiene entonces que $a_y=-g$ y aplicando las ecuaciones de aceleración constante como visto en el ítem anterior, se llega a:

\begin{equation*}
\begin{array}{crl}
\left(+\uparrow \right) &v=&v_0+a_ct&                   \quad &v_y=v_{0y}-gt \\
\left(+\uparrow \right) &y=&y_0+v_0t+\frac{1}{2}a_ct^2& \quad &y=y_0+v_{0y}t-\frac{1}{2}gt^2 \\
\left(+\uparrow \right) &v^2=&v_0^2+2a_c(y-y_0)&        \quad &v_y^2=v_{0y}^2-2g \left(y-y_0  \right) \\
\end{array}
\label{eq:Ec3_2} \tag{3.2}
\end{equation*}

### Comentarios al movimiento curvilíneo

- En el movimiento horizontal la primera y la tercera ecuación implican que la componente horizontal de la velocidad siempre permanece constante durante la realización del movimiento.

- En el movimiento vertical, la última ecuación puede formularse eliminando el término del tiempo de las dos primeras ecuaciones, por lo que, solo dos de las tres ecuaciones son independientes entre ellas.

- De lo anterior se concluye que los problemas que involucran movimiento parabólico pueden tener como máximo tres incógnitas, ya que solo se podrán escribir tres ecuaciones independientes: una ecuación en la dirección horizontal y dos en la dirección vertical.

- La velocidad resultante $v$, que siempre será tangente a la trayectoria, se determinará por medio de la suma vectorial de sus componentes $v_x$ y $v_y$.

### Ejemplos movimiento parabólico

 Ejemplo 12.11: Hibbeler R. Engineering Mechanics: Dynamics

Un saco se desliza por la rampa, como se ve en la figura, con una velocidad horizontal de $12 m/s$. Si la altura de la rampa es de $6 m$, determine el tiempo necesario para que el saco choque con el suelo y la distancia $R$ donde los sacos comienzan a apilarse

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

- ***Sistema de coordenadas*** Se establece el origen en el punto $A$, donde comienza la trayectoria de la partícula (saco). Se observa que la velocidad inicial del saco presenta dos componentes, donde $v_{Ax}=12m/s$ y $v_{Ay}=0$. La acelaración en todo el recorrido, entre $A$ y $B$, es de $a_y=-9.81 m/s^2$. También se observa que se cumple que $v_{Bx}=v_{Ax}=12m/s$ (por qué?). Con lo anterior, las tres incógnitas restantes son $v_{By}$, $R$, y el tiempo de vuelo $t_{AB}$.

- ***Movimiento vertical $\left(+\uparrow \right)$:*** Del enunciado, se conoce la distancia vertical $A-B$, que será $y_B=6m$

$$y_B=y_A+v_{Ay}t_{AB}+\frac{1}{2}a_ct_{AB}^2$$

reemplazando valores se tiene

$$0=6m+0 \times t_{AB}+\frac{1}{2}(-9.81m/s^2)t_{AB}^2$$

$$t_{AB}=1.11 s$$

Una vez calculado el tiempo, la distancia horizontal, $R$ se determina así:

- ***Movimiento horizontal $\left(\underrightarrow{+}\right)$:***

$$x_B=x_A+v_{Ax}t_{AB}$$
$$R=0+12m/s(1.11s)$$
$$R=13.3m$$

***Solución computacional:***

```python
import numpy as np
import matplotlib.pyplot as plt
from sympy import *
import seaborn as sns

t,R = symbols('t R')
init_printing(use_latex='mathjax')
```

```python
# condiciones iniciales
x0 = 0     # coordenada xA
y0 = 6     # coordenada yA
v0x = 12   # Veloc en A en la dirección x
v0y = 0    # Veloc en A en la dirección y
y = 0      # Altura final
ac = -9.81 # aceleración debida a la gravedad
```

```python
# Ecuación del movimiento vertical
yd2 = Eq(y, y0 + v0y * t + ac * t**2 / 2)
yd2
```

```python
# Resolviendo para t
tiempo = solve(yd2,t)
print("El tiempo de caída de cada saco es de {0:6.4f} s".format(tiempo[1]))
```

```python
tiempo
```

```python
xd2 = Eq(R, x0 + v0x * tiempo[0])
xd2
```

```python
# Ecuación del movimiento horizontal
R = float(x0 + v0x * tiempo[0])
print("La distancia a la que caerá cada saco es de {0:6.4f} m".format(R))
```

```python
# Graficando
t = np.linspace(0,np.around(float(tiempo[1]), decimals = 4),100)

x = x0 + v0x * t
y = y0 + v0y * t + ac * t**2 / 2

plt.plot(x,y);
plt.xlabel("x(m)")
plt.ylabel("y(m)")
plt.grid(True)
```

## Movimiento curvilíneo: Componentes normal y tangencial

### Introducción

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

A veces es más conveniente emplear como sistema de referencia las coordenadas $n-t$, que expresan las componentes *normal* y *tangencial* a la trayectoria.

### Movimiento plano

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

Sea una partícula que se desplaza en el plano a lo largo de una curva fija, tal que en un instante dado está en la posición $s$ medida respecto a $O'$. Considere un sistema de ejes coordenados con origen en un punto fijo de la curva y, en un instante determinado, éste coincide con la ubicación de la partícula. El eje $t$ es tangente a la curva en el punto y positivo en la dirección de $s$, denominada con el vector unitario $\vec{\boldsymbol{u}}_t$. La determinación del eje normal, $\vec{\boldsymbol{u}}_n$ es inmediata, ya que solo existe una única posibilidad, siendo positivo en la dirección hacia el centro de la curva. La curva se forma por una serie de segmentos de arco de tamaño $ds$ y cada uno de estos segmentos es formado por el arco de un círculo con radio de curvatura $\rho$ y centro $O'$. El plano que se genera por los ejes $n-t$ se denomina *[plano osculador](https://es.wikipedia.org/wiki/Geometr%C3%ADa_diferencial_de_curvas#Plano_osculador)*, y está fijo en el plano del movimiento.

### Velocidad

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

Como se ha indicado en las secciones anteriores, la partícula se encuentra en movimiento, por lo que el desplazamiento es una función del tiempo, $s(t)$. La dirección de la velocidad de la partícula siempre es tangente a la trayectoria y su magnitud se determina por la derivada respecto al tiempo de la función de la trayectoria. Entonces:

\begin{equation*}
\boldsymbol{v}=v\boldsymbol{u}_t
\label{eq:Ec3_3} \tag{3.3}
\end{equation*}

donde

\begin{equation*}
v=\dot{s}
\label{eq:Ec3_4} \tag{3.4}
\end{equation*}

### Aceleración

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

El cambio de la velocidad de la partícula respecto al tiempo es la aceleración. Entonces

\begin{equation*}
\boldsymbol{a}=\dot{\boldsymbol{v}}=\dot{v}\boldsymbol{u}_t + v\dot{\boldsymbol{u}}_t
\label{eq:Ec3_5} \tag{3.5}
\end{equation*}

Falta determinar la derivada de $\dot{\boldsymbol{u}}_t$ respecto al tiempo. A medida que la partícula se desplaza a lo largo de un arco $ds$ en un diferencial de tiempo $dt$, $\boldsymbol{u}_t$ su dirección varía y pasa a ser $\boldsymbol{u}'_t$, donde $\boldsymbol{u}'_t=\boldsymbol{u}_t+d\boldsymbol{u}_t$. Observe que $d\boldsymbol{u}_t$ va de las puntas de $\boldsymbol{u}_t$ a $\boldsymbol{u}'_t$, que se extienden en un arco infinitesimal de magnitud $u_t=1$ (unitaria). Por lo tanto, $d\boldsymbol{u}_t=d\theta \boldsymbol{u}_n$, por lo que la derivada con respecto al tiempo es $\dot{\boldsymbol{u}}_t=\dot{\theta}\boldsymbol{u}_n$.

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

Observe también que $ds=\rho d\theta$, entonces $\dot{\theta}=\dot{s}/\rho$, resultando

$$\dot{\boldsymbol{u}}_t=\dot{\theta}\boldsymbol{u}_n=\frac{\dot{s}}{\rho}\boldsymbol{u}_n=\frac{v}{\rho}\boldsymbol{u}_n$$

Sustituyendo en la [Ec. 3.4](#Ec3_4) se puede reescribir $\boldsymbol{a}$ como la suma de las componentes tangencial y normal:

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

\begin{equation*}
\boldsymbol{a} = a_t \boldsymbol{u}_t + a_n \boldsymbol{u}_n
\label{eq:Ec3_6} \tag{3.6}
\end{equation*}

donde la componente tangencial es dada por

\begin{equation*}
a_t = \dot{v} \qquad \text{o} \qquad a_t ds = vdv
\label{eq:Ec3_7} \tag{3.7}
\end{equation*}

la componente normal, por

\begin{equation*}
a_n = \frac{v^2}{\rho}
\label{eq:Ec3_8} \tag{3.8}
\end{equation*}

y la magnitud de la aceleración está dada por

\begin{equation*}
a = \sqrt{a^2_t + a^2_n}
\label{eq:Ec3_9} \tag{3.9}
\end{equation*}

***Comentarios***

- Si la partícula se mueve a lo largo de una línea recta entonces $\rho \rightarrow \infty$ y por la [Ec. 3.8](#Ec3_8), $a_=0$. Con esto $a=a_t = \dot{v}$, y se puede concluir que *la componente tangencial de la aceleración representa el cambio en la magnitud de la velocidad*.

- Si la partícula se mueve a lo largo de una curva con velocidad constante, entonces $a_t=\dot{v}=0$ y $a=a_n=v^2/\rho$. Por lo tanto, *la componente normal de la aceleración representa el cambio en la dirección de la velocidad*. Como $a_n$ siempre actúa hacia el centro de la curvatura, esta componente en ocasiones se conoce como la [aceleración centrípeta](https://en.wikipedia.org/wiki/Centripetal_force) ("*que busca el centro*").

- Expresando la trayectoria de la partícula como $y=f(x)$, el radio de curvatura en cualquier punto de la trayectoria se determina por la ecuación:

\begin{equation*}
\rho=\frac{\left[1 + (dy/dx)^2\right]^{3/2}}{|d^2y/dx^2|}
\label{eq:Ec3_10} \tag{3.10}
\end{equation*}

Como consecuencia de lo anterior, una partícula que se mueve a lo largo de una trayectoria curva tendrá una aceleración como la mostrada en la figura:

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

### Ejemplos componentes normal y tangencial

 Ejemplo 12.14: Hibbeler R. Engineering Mechanics: Dynamics

Cuando el esquiador llega al punto $A$ a lo largo de la trayectoria parabólica en la figura, su rapidez es de $6 m/s$, la cual se incrementa a $2 m/s^2$. Determine la dirección de su velocidad y la dirección y magnitud de su aceleración en este instante. Al hacer el cálculo, pase por alto la estatura del esquiador..

- ***Sistema de coordenadas:***

Se establece el origen de los ejes $n-t$ en el punto fijo $A$ de la trayectoria.

- ***Velocidad:***

Como se definió, la velocidad será siempre tangente a la trayectoria. Como $y = \frac{1}{20}x^2$, su derivada es $\frac{dy}{dx}=\frac{1}{10}x$, reemplazando cuando $x=10m$, $\frac{dy}{dx}=1$. Por lo tanto, en $A$, $\boldsymbol{v}$ forma un ángulo $\theta=\tan^{-1}(1)=45^{\circ}$ con el eje $x$. Con esto, la velocidad en $A$ es

$$v_A=6m/s \quad 45^{\circ}\measuredangle$$

- ***Aceleración:***

Reemplazando las [Ecs. 3.7 y 3.8](#Ec3_7) en la [Ec. 3.6](#Ec3_6) para determinar la aceleración, se llega a:

$$\boldsymbol{a}=\dot{v}\boldsymbol{u}_t+\frac{v^2}{\rho}\boldsymbol{u}_n$$

De esta ecuación se desconoce el radio de curvatura $\rho$ de la trayectoria en el punto $A(10,5)$. Empleando la [Ec. 3.10](#Ec3.10) y reemplazando el valor de la coordenada:

$$\rho=\frac{\left[1 + (dy/dx)^2\right]^{3/2}}{|d^2y/dx^2|}=\left. \frac{\left[1 + (x/10)^2\right]^{3/2}}{|1/10|} \right|_{x=10m}=28.28m$$

Con lo anterior, la dirección de la aceleración está dada por

$$
\begin{align*}
\boldsymbol{a} & = \dot{v} \boldsymbol{u}_t + \frac{v^2}{\rho} \boldsymbol{u}_n \\
 & = 2 \boldsymbol{u}_t + \frac{(6m/s)^2}{28.28m} \boldsymbol{u}_n \\
 & = (2 \boldsymbol{u}_t + 1.273 \boldsymbol{u}_n) m/s^2
\end{align*}
$$

y cada una de las componentes se representan en la siguiente figura.

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

por último, la magnitud de la aceleración está dada por

$$a=\sqrt{(2m/s^2)^2+(1.273 m/s^2)^2}=2.37 m/s^2$$

el ángulo sería

$$\phi = \tan^{-1}\left(\frac{2}{1.273} \right)=57.5^{\circ}$$

De la figura:

$$45^{\circ}+90^{\circ}+57.5^{\circ}-180^{\circ}=12.5^{\circ}$$

entonces,

$$\boldsymbol{a}=2.37 m/s^2 \quad 12.5^{\circ} \measuredangle$$

Ahora vamos a realizar la solución empleando programación con el ecosistema `python`

```python
x = symbols('x')
ut, un = symbols('ut un')
```

La ecuación que determina la trayectoria de la partícula está dada por

```python
y = x**2 / 20
```

Y la velocidad de la partícula, cuya magnitud es la misma rapidez, segun el enunciado es

```python
v = 6
```

Ahora se deriva la ecuación de la trayectoria respecto a la variable $x$

```python
dydx = diff(y,x)
dydx
```

reemplazando en $x=10m$

```python
dydx = N(dydx.subs(x,10),4)
print("{0:6.1f}".format(dydx))
```

con esto, se calcula el ángulo que determina la direccion de la velocidad

```python
theta = N(atan(dydx)*180/np.pi,4)
print("{0:6.1f}".format(theta))
```

El cálculo de la aceleración se realiza mediante la siguiente ecuación:

$$\boldsymbol{a} = \dot{v} \boldsymbol{u}_t + \frac{v^2}{\rho} \boldsymbol{u}_n$$

se debe calcular el radio de curvatura $\rho$ con la [Ec. 3.10](#Ec3_10), que a su vez requiere del cálculo de la segunda derivada de la función de la trayectoria, $y$, respecto a $x$. Del enunciado se determina que $\dot{v}=2 m/s$.

```python
d2ydx2 = diff(y,x,2)
d2ydx2
```

```python
rho = N((1 + dydx**2)**(3/2) / d2ydx2,4)
print("{0:6.4f}".format(rho))
```

```python
v_dot = 2
```

Con lo anterior, se construye la expresión para la aceleración

```python
v2rho = v**2 / rho
```

```python
a_A = v_dot * ut + v2rho * un
a_A
```

Ahora se calculará la magnitud de la aceleración, dada por la [Ec. 3.9](#Ec3_9)

```python
a_mag = sqrt(v_dot**2 + v2rho**2)
print("{0:6.1f}".format(a_mag))
```

por último, calculamos el ángulo para la dirección de la aceleración

```python
phi = atan(v_dot / v2rho) * 180 / np.pi
print("{0:6.1f}".format(phi))
```

De la [figura](#Fig_angulos) donde se expresan los ángulos, se determina cuál sería la dirección

```python
a = 45 + 90 + phi - 180
print("{0:6.1f}".format(a))
```

$\color{red}{\textbf{Actividad para ser realizada por el estudiante:}}$

Realizar computacionalmente los otros ejemplos del capítulo que aparecen en el libro de Hibbeler, sección 12.7, ejemplos 12-15 y 12-16 (pags. 58 y 59).

También se invita a que desarrollen al menos un ejercicio de los problemas fundamentales (pag. 60), y ejercicios de los problemas (pags. 61 - 67), dividiendolos en tres partes: dos ejercicios del tercio inferior, dos del tercio medio y dos del tercio superior, tanto analíticamente ("a mano") como computacionalmente.

## Movimiento curvilíneo: Componentes cilíndricos

### Introducción

En ciertos problemas cuyo movimiento de la partícula describe una trayectoria curva, la descripción de dicho movimiento se describe de mejor forma (más simple) empleando un [sistema de coordenadas cilíndricas](https://en.wikipedia.org/wiki/Cylindrical_coordinate_system). Si el movimiento se limita a un plano se emplea un [sistema de coordenadas polares](https://en.wikipedia.org/wiki/Polar_coordinate_system).

### Coordenadas polares

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

La posición de la partícula en la figura se determina mediante una coordenada radial $r$, que se extiende desde el origen $O$ hasta la partícula, y el ángulo $\theta$ entre un eje horizontal que sirve como referencia y $r$, medido en sentido antihorario. Las componentes $\boldsymbol{u}_r$ y $\boldsymbol{u}_{\theta}$ se defienen en la dirección positiva de $r$ y $\theta$ respectivamente.

#### Posición

La posición de la partícula se define por el vector posición

\begin{equation*}
\boldsymbol{r}=r\boldsymbol{u}_r
\label{eq:Ec3_11} \tag{3.11}
\end{equation*}

#### Velocidad

La velocidad es la derivada de $\boldsymbol{r}$ respecto al tiempo

\begin{equation*}
\boldsymbol{v}=\boldsymbol{\dot{r}}=\dot{r}\boldsymbol{u}_r+r\boldsymbol{\dot{u}}_r
\label{eq:Ec3_12} \tag{3.12}
\end{equation*}

En la evaluación de $\boldsymbol{\dot{u}}_r$, obsérvese que $\boldsymbol{u}_r$ únicamente cambia de dirección respecto al tiempo, ya que por definición la magnitud del vector es unitaria. En un tiempo $\Delta t$, el cambio $\Delta r$ no cambiará la dirección de $\boldsymbol{u}_r$, sin embargo, un cambio $\Delta \theta$ proporcionará que $\boldsymbol{u}_r$ cambie a $\boldsymbol{u}'_r$, con $\boldsymbol{u}'_r=\boldsymbol{u}_r+\Delta \boldsymbol{u}_r$. Entonces, el cambio de $\boldsymbol{u}_r$ es por lo tanto $\Delta \boldsymbol{u}_r$. Si $\Delta \theta$ es pequeño, la magnitud del vector es $\Delta u_r \approx 1 (\Delta \theta)$, en la dirección $\boldsymbol{u}_{\theta}$. Entonces $\Delta \boldsymbol{u}_r=\Delta \theta \boldsymbol{u}_{\theta}$, y

$$\boldsymbol{\dot{u}}_r=\lim \limits_{\Delta t \to 0} \frac{\Delta \boldsymbol{u}_r}{\Delta t} = \left( \lim \limits_{\Delta t \to 0} \frac{\Delta \theta}{\Delta t}\right) \boldsymbol{u}_{\theta}
$$

\begin{equation*}
\boldsymbol{\dot{u}}_r=\dot{\theta}\boldsymbol{u}_{\theta}
\label{eq:Ec3_13} \tag{3.13}
\end{equation*}

Sustituyendo en la ecuación anterior, la velocidad se escribe a través de sus componentes como

\begin{equation*}
\boldsymbol{v}=v_r \boldsymbol{u}_r+v_{\theta}\boldsymbol{u}_{\theta}
\label{eq:Ec3_14} \tag{3.14}
\end{equation*}

donde

\begin{equation*}
v_r=\dot{r} \\
v_{\theta} = r\dot{\theta}
\label{eq:Ec3_15} \tag{3.15}
\end{equation*}

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

En la gráfica se observa la descomposición del vector velocidad en las componentes radial, $\boldsymbol{v}_r$, que mide la tasa de incremento (decremento) de la longitud en la coordenada radial, o sea, $\dot{r}$, y la componente transversal, $\boldsymbol{v}_{\theta}$, que es la tasa de movimiento a lo largo de una circunferencia de radio $r$. El término $\dot{\theta}=d\theta / dt$ también se conoce como *velocidad angular*, ya que es la razón de cambio del ángulo $\theta$ respecto al tiempo. Las unidades de la velocidad angular se dan en $rad/s$.

Considerando que $\boldsymbol{v}_r$ y $\boldsymbol{v}_{\theta}$ son perpendiculares, la magnitud de la velocidad estará dada por el valor positivo de:

\begin{equation*}
v = \sqrt{(\dot{r})^2+(r\dot{\theta})^2}
\label{eq:Ec3_16} \tag{3.16}
\end{equation*}

donde la dirección de $\boldsymbol{v}$ es tangente a la trayectoria.

#### Aceleración

La aceleración es la derivada de la velocidad respecto al tiempo. De las ecs. [(3.14)](#Ec3_14) y [(3.15)](#Ec3_15), se llega a la aceleración instantánea de la partícula.

\begin{equation*}
\boldsymbol{a}=\boldsymbol{\dot{v}}=\ddot{r}\boldsymbol{u}_r+\dot{r}\dot{\boldsymbol{u}}_r+\dot{r}\dot{\theta}\boldsymbol{u}_{\theta}+r\ddot{\theta}\boldsymbol{u}_{\theta}+r\dot{\theta}\boldsymbol{\dot{u}}_{\theta}
\label{eq:Ec3_17} \tag{3.17}
\end{equation*}

De la anterior ecuación se requiere determinar el valor de $\dot{\boldsymbol{u}}_{\theta}$, que es el cambio de la dirección $\boldsymbol{u}_{\theta}$ respecto al tiempo, con magnitud unitaria.

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

De la gráfica se tiene que en un tiempo $\Delta t$, un cambio $\Delta r$ no cambiará la dirección $\boldsymbol{u}_{\theta}$, sin embargo, un cambio $\Delta \theta$ hará que $\boldsymbol{u}_{\theta}$ pase a $\boldsymbol{u}'_{\theta}$, con $\boldsymbol{u}'_{\theta}=\boldsymbol{u}_{\theta}+\Delta\boldsymbol{u}_{\theta}$. Para pequeñas variaciones del ángulo, la magnitud del vector es $\Delta u_{\theta}\approx 1(\Delta \theta)$, actuando en la dirección $-\boldsymbol{u}_r$, o sea, $\Delta u_{\theta}=-\Delta \theta\boldsymbol{u}_r$, entonces

$$\boldsymbol{\dot{u}}_{\theta}=\lim \limits_{\Delta t \to 0} \frac{\Delta \boldsymbol{u}_{\theta}}{\Delta t} = -\left( \lim \limits_{\Delta t \to 0} \frac{\Delta \theta}{\Delta t}\right) \boldsymbol{u}_{r}
$$

\begin{equation*}
\boldsymbol{\dot{u}}_{\theta}=-\dot{\theta}\boldsymbol{u}_{r}
\label{eq:Ec3_18} \tag{3.18}
\end{equation*}

Sustituyendo el anterior resultado y la Ec. [(3.13)](#Ec3_13) en la ecuación para la aceleración, se escribe la aceleración en forma de componentes como

\begin{equation*}
\boldsymbol{a}=a_r\boldsymbol{u}_{r}+a_{\theta}\boldsymbol{u}_{\theta}
\label{eq:Ec3_19} \tag{3.19}
\end{equation*}

con

\begin{equation*}
a_r=\ddot{r}-r\dot{\theta}^2 \\
a_{\theta}=r\ddot{\theta}+2\dot{r}\dot{\theta}
\label{eq:Ec3_20} \tag{3.20}
\end{equation*}

donde $\ddot{\theta}=d^2\theta/dt^2=d/dt(d\theta /dt)$ se conoce como *aceleración angular y sus unidades son $rad/s^2$*. $\boldsymbol{a}_r$ y $\boldsymbol{a}_{\theta}$ son perpendiculares, entonces la magnitud d ela aceleración está dada por el valor positivo de

\begin{equation*}
a=\sqrt{(\ddot{r}-r\dot{\theta}^2)^2+(r\ddot{\theta}+2\dot{r}\dot{\theta})^2}
\label{eq:Ec3_21} \tag{3.21}
\end{equation*}

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

### Coordenadas cilíndricas

 Fuente: Hibbeler R. Engineering Mechanics: Dynamics

Si la partícula se mueve a lo largo de una curva espacial, entonces su ubicación se especifica por medio de las tres coordenadas cilíndricas, $r$, $\theta$, $z$. La coordenada $z$ es idéntica a la que se utilizó para coordenadas rectangulares. Como el vector unitario que define su dirección $\boldsymbol{u}_z$, es constante, las derivadas con respecto al tiempo de este vector son cero, y por consiguiente la posición, velocidad y aceleración de la partícula se escriben en función de sus coordenadas cilíndricas como sigue:

\begin{equation*}
\begin{split}
\boldsymbol{r}_p &= r\boldsymbol{u}_r+z\boldsymbol{u}_z \\
\boldsymbol{v} &= \dot{r}\boldsymbol{u}_r+r\dot{\theta}\boldsymbol{u}_{\theta}+\dot{z}\boldsymbol{u}_{z} \\
\boldsymbol{a} &= (\ddot{r}-r\dot{\theta}^2)\boldsymbol{u}_r+(r\ddot{\theta}+2\dot{r}\dot{\theta})\boldsymbol{u}_{\theta}+\ddot{z}\boldsymbol{u}_z
\end{split}
\label{eq:Ec3_22} \tag{3.22}
\end{equation*}

### Derivadas respecto al tiempo

Las ecuaciones anteriores requieren que obtengamos las derivadas con respecto al tiempo $\dot{r}$, $\ddot{r}$, $\dot{\theta}$ y $\ddot{\theta}$, para evaluar las componentes $r$ y $\theta$ de $\boldsymbol{v}$ y $\boldsymbol{a}. En general se presentan dos tipos de problema:

1. Si las coordenadas polares se especifican como ecuaciones paramétricas en función del tiempo, $r = r(t)$ y $\theta=\theta(t)$, entonces las derivadas con respecto al tiempo pueden calcularse directamente.

2. Si no se dan las ecuaciones paramétricas en función del tiempo, entonces debe conocerse la trayectoria $r=f(\theta)$. Si utilizamos la regla de la cadena del cálculo podemos encontrar entonces la relación entre $\dot{r}$ y $\dot{\theta}$ y entre $\ddot{r}$ y $\ddot{\theta}$

### Ejemplos componentes cilíndricos

 Ejemplo 12.20: Hibbeler R. Engineering Mechanics: Dynamics

Debido a la rotación de la barra ahorquillada, la bola en la figura se mueve alrededor de una trayectoria ranurada, una parte de la cual tiene la forma de un cardioide, $r=0.5(1 - cos(\theta)) pies$, donde $\theta$ está en radianes. Si la velocidad de la bola es $v=4 pies/s$ y su aceleración es $a=30 pies/s^2$ en el instante $\theta=180^{\circ}$, determine la velocidad angular $\dot{theta}$ y la aceleración angular $\ddot{\theta}$ de la horquilla.

- ***Sistema de coordenadas:***
Esta trayectoria es muy rara, y matemáticamente se expresa mejor por medio de coordenadas polares, como se hace aquí, en lugar de coordenadas rectangulares. También, como $\dot{theta}$ y $\ddot{\theta}$ deben determinarse, entonces las coordenadas $r$, $\theta$ no son una opción obvia.

- ***Velocidad y aceleración:***

Empleando la regla de la cadena para determinar las derivadas de $r$ y $\theta$:

\begin{equation*}
\begin{split}
r&=0.5(1-\cos\theta) \\
\dot{r}&=0.5(\sin\theta)\dot{\theta}\\
\ddot{r}&=0.5(\cos\theta)\dot{\theta}(\dot{\theta})+0.5(\sin\theta)\ddot{\theta}
\end{split}
\end{equation*}

evaluando cuando $\theta=180^{\circ}$, se tiene

$$r=1 pie \quad\quad \dot{r}=0\quad\quad\ddot{r}=-0.5\dot{\theta}^2$$

como $v=4 pie/s$, utilizando la ecuación [(3.16)](#Ec3_16) para determinar $\dot{\theta}$ se tiene

\begin{equation*}
\begin{split}
v&=\sqrt{(\dot{r})^2+(r\dot{\theta})^2} \\
4&=\sqrt{(0)^2+(1\dot{\theta})^2}\\
\dot{\theta}&=4rad/s
\end{split}
\end{equation*}

Ahora calculando $\ddot{\theta}$, empleando la ecuacion [3.21](#Ec3_21)

\begin{equation*}
\begin{split}
a&=\sqrt{(\ddot{r}-r\dot{\theta}^2)^2+(r\ddot{\theta}+2\dot{r}\dot{\theta})^2} \\
30&=\sqrt{[-0.5(4)^2-1(4)^2]^2+[1\ddot{\theta}+2(0)(4)]^2}\\
(30)^2&=(-24)^2+\ddot{\theta}^2 \\
\ddot{\theta}&=18rad/s^2
\end{split}
\end{equation*}

- ***Solución computacional:***

```python
import numpy as np
import matplotlib.pyplot as plt
from sympy import *
from sympy.physics.mechanics import dynamicsymbols, init_vprinting

theta = dynamicsymbols(r'\theta')
t = Symbol('t')

init_vprinting()
```

Graficando primero la funcion cardioide

```python
phi = np.linspace(0, 2*np.pi, 1000)

r = 0.5 * (1 - np.cos(phi))
plt.polar(phi, r, 'r')
plt.show()

```

Ahora obtenemos los valores de $\dot{r}$ y $\ddot{r}$

```python
r = 0.5 * (1 - cos(theta))
rdot = diff(r, t)
rdot
```

```python
rddot = diff(rdot, t)
rddot
```

Evaluando los anteriores resultados cuando $\theta=180^{\circ}$

```python
rN = r.subs(theta, 180 * pi / 180)
rN
```

```python
rdotN = rdot.subs(theta, 180 * pi / 180)
rdotN
```

```python
rddotN = rddot.subs(theta, 180 * pi / 180)
rddotN
```

Ahora vamos a determinar el valor numérico para $\dot{\theta}$, cuando $v=4pie/s$

```python
thetadot = N(Eq(4, sqrt(rdotN**2 + (rN * theta)**2)))
thetadot
```

```python
thetadot = solve(thetadot,theta)
thetadot
```