commit dc2cf45b108e905c15d9fb4e283dd6a89cd4c1f6 Author: Gerardo Marx Date: Wed Mar 26 13:45:37 2025 -0600 model ok for lecture diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..87620ac --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.ipynb_checkpoints/ diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..3493eb3 --- /dev/null +++ b/Readme.md @@ -0,0 +1,248 @@ +```python +#!pip3 install tensorflow +import tensorflow as tf +import numpy as np +import matplotlib.pyplot as plt +``` + + +```python +# data for training the ann mode +# option 1: +celsius = np.array([-40, -10, 0, 8, 15, 22, 38], dtype=float) +fahrenheit = np.array([-40, 14, 32, 46, 59, 72, 100], dtype=float) + +# option 2: (X°C x 9/5) + 32 = 41 °F +points = 100 +np.random.seed(99) +dataIn = np.linspace (-40,60, points) +target = dataIn*9/5 + 32 +4*np.random.randn(points) + +plt.plot(celsius, fahrenheit, 'or', label='data-set 1') +plt.plot(dataIn, target, '.b', alpha=0.3, label='data-set 2') +plt.legend() +plt.grid() +plt.show() +``` + + + +![png](Readme_files/Readme_1_0.png) + + + + +```python +from tensorflow.keras.models import Sequential # ANN type +from tensorflow.keras.layers import Dense, Input # All nodes connected + +# NN definition +hn=2 +model = Sequential() +model.add(Input(shape=(1,), name='input')) +model.add(Dense(hn, activation='linear', name='hidden')) +model.add(Dense(1, activation='linear', name='output')) +model.summary() +``` + + +
Model: "sequential_1"
+
+ + + + +
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
+┃ Layer (type)                     Output Shape                  Param # ┃
+┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
+│ hidden (Dense)                  │ (None, 2)              │             4 │
+├─────────────────────────────────┼────────────────────────┼───────────────┤
+│ output (Dense)                  │ (None, 1)              │             3 │
+└─────────────────────────────────┴────────────────────────┴───────────────┘
+
+ + + + +
 Total params: 7 (28.00 B)
+
+ + + + +
 Trainable params: 7 (28.00 B)
+
+ + + + +
 Non-trainable params: 0 (0.00 B)
+
+ + + + +```python +### veri important note implement a python code +# to show the ANN model connection using ascii +``` + + +```python +from tensorflow.keras.optimizers import Adam + +#hyper parameters +epoch = 500 +lr = 0.01 +hn = 2 # hidden nodes +tf.random.set_seed(42) # For TensorFlow + + +model.compile(optimizer=Adam(lr), loss='mean_squared_error') +print("Starting training ...") +historial = model.fit(dataIn, target, epochs=epoch, verbose=False,) +print("Model trainned!") +``` + + Starting training ... + Model trainned! + + + +```python +predict = model.predict(dataIn) +plt.plot(dataIn, predict, ':r', label='estimated') +plt.plot(dataIn,target, '.b', label='real', alpha=0.4) +plt.legend() +plt.grid() +plt.show() +``` + + 4/4 ━━━━━━━━━━━━━━━━━━━━ 0s 4ms/step + + + + +![png](Readme_files/Readme_5_1.png) + + + + +```python +# Get weights +for layer in model.layers: + weights = layer.get_weights() + print(f"Layer: {layer.name}") + print(f" Weights (Kernel): {weights[0].shape} \n{weights[0]}") + print(f" Biases: {weights[1].shape} \n{weights[1]}") +``` + + Layer: hidden + Weights (Kernel): (1, 2) + [[-0.27738443 0.7908125 ]] + Biases: (2,) + [-8.219968 6.714554] + Layer: output + Weights (Kernel): (2, 1) + [[-1.9934888] + [ 1.5958738]] + Biases: (1,) + [5.1361823] + + +# Testing the model + + +```python +inTest = np.array([100]) +model.predict(inTest) +``` + + 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 87ms/step + + + + + + array([[213.73816]], dtype=float32) + + + + +```python +# Do the Maths: +inTest = np.array(inTest) +whi = np.array([[-0.27738443, 0.7908125 ]]) +bh = np.array([-8.219968, 6.714554]) +Oh = np.dot(inTest,whi)+bh +who = np.array([[-1.9934888],[ 1.5958738]]) +bo = np.array([5.1361823]) +Oo = np.dot(Oh,who)+bo +Oo +``` + + + + + array([213.73814765]) + + + + +```python +def generate_ascii_ann(model): + ascii_diagram = "\nArtificial Neural Network Architecture:\n" + + for i, layer in enumerate(model.layers): + weights = layer.get_weights() + + # Determine layer type and number of neurons + if isinstance(layer, Dense): + input_dim = weights[0].shape[0] # Number of inputs + output_dim = weights[0].shape[1] # Number of neurons + + ascii_diagram += f"\nLayer {i+1}: {layer.name} ({layer.__class__.__name__})\n" + ascii_diagram += f" Inputs: {input_dim}, Neurons: {output_dim}\n" + ascii_diagram += f" Weights Shape: {weights[0].shape}\n" + + if len(weights) > 1: # If bias exists + ascii_diagram += f" Biases Shape: {weights[1].shape}\n" + + # ASCII representation of neurons + ascii_diagram += " " + " o " * output_dim + " <- Output Neurons\n" + ascii_diagram += " | " * output_dim + "\n" + ascii_diagram += " " + " | " * input_dim + " <- Inputs\n" + + return ascii_diagram + +# Generate and print the ASCII diagram +ascii_ann = generate_ascii_ann(model) +print(ascii_ann) +``` + + + Artificial Neural Network Architecture: + + Layer 1: hidden (Dense) + Inputs: 1, Neurons: 2 + Weights Shape: (1, 2) + Biases Shape: (2,) + o o <- Output Neurons + | | + | <- Inputs + + Layer 2: output (Dense) + Inputs: 2, Neurons: 1 + Weights Shape: (2, 1) + Biases Shape: (1,) + o <- Output Neurons + | + | | <- Inputs + + + +```mermaid +graph LR +I1((I_1)) --> H1((H_1)) & H2((H_1)) +H1 & H2 --> O1((O_1)) & O2((O_2)) +``` diff --git a/Readme_files/Readme_1_0.png b/Readme_files/Readme_1_0.png new file mode 100644 index 0000000..e52ea87 Binary files /dev/null and b/Readme_files/Readme_1_0.png differ diff --git a/Readme_files/Readme_5_1.png b/Readme_files/Readme_5_1.png new file mode 100644 index 0000000..e79a372 Binary files /dev/null and b/Readme_files/Readme_5_1.png differ diff --git a/main.ipynb b/main.ipynb new file mode 100644 index 0000000..9d5c0ad --- /dev/null +++ b/main.ipynb @@ -0,0 +1,408 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "#!pip3 install tensorflow\n", + "import tensorflow as tf\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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I3adsWjXrl1yxx13SNeuXaVp06bSrVs3U1leXV3tdhzjHBwvvPCCdOnSxYxjnz595NNPP430JcW0mTNnyhVXXGE6Yrdt21ZGjx4t27ZtczumsrJSJk2aJDk5OdKsWTMZO3asfPfddxG75njw5JNPmt/HU6ZMcT7HOAfHvn375Kc//akZR/2dfPHFF8uGDRucr+u6m0cffVRyc3PN60OHDpXt27dLOBCo1OOBBx4wrX09tRQePny4dO7cWTZu3CjPPPOMTJ8+XebMmROR64xFX331ldn+4I9//KNs3bpVfve738lLL70kDz/8sPMYxjk4Fi5cKFOnTjWB4L/+9S/p2bOnjBgxQg4cOBDpS4tZBQUF5sNx3bp1snz5crNxm/6slpeXO4+5//775d1335VFixaZ43WrjzFjxkT0umPZZ599Zn5f9OjRw+15xrnxSktL5Qc/+IHZdHDZsmXyxRdfyG9+8xvJzs52HqN/JD7//PPm9/T69eslMzPT/B7RQDHkdHky6vr73/9uP//88+1bt27V5dv2//u//3O+9oc//MGenZ1tr6qqcj734IMP2s8777wIXW18ePrpp+1du3Z1Pmacg6N37972SZMmOR/X1NTYO3ToYJ85c2ZEryueHDhwwPyeKCgoMI+PHDliT0lJsS9atMh5zJdffmmOWbt2bQSvNDZ9//339nPOOce+fPly+6BBg+z33XefeZ5xDg79vdq/f3+vr586dcrevn17+zPPPON8Tsc+LS3N/pe//MUeamRUPNC04cSJE+WNN96QjIyMOq+vXbtWBg4cKKmpqc7nNLLU1K9GpgjM0aNHpVWrVs7HjHPj6VSaZqM0Teu6P5Y+1vFF8H52lfXzq2OuWRbXcT///POlU6dOjHsANHv1wx/+0G08FeMcHO+8845cfvnlcsMNN5ipzEsuuURefvll5+s7d+6U4uJit3HWPXp0Gjkc40ygUovOw916661y1113mW+cJ/oNa9eundtz1mN9Df7bsWOHzJ49W372s585n2OcG+/gwYNSU1PjcRwZw+DQKUytmdDU+UUXXWSe07HVALtly5ZuxzLu/luwYIGZstS6oNoY5+D49ttv5cUXX5RzzjlH/vGPf8jdd98t9957r7z++uvmdWssI/V7JGEClYceesgUYdV307oJ/bDUbaenTZsW6UuO63GuXcR19dVXm2heM1lArP21v2XLFvOBiuAqLCyU++67T+bNm2cKwRG6YPvSSy+V//mf/zHZlDvvvNP8LtZ6lGiQLAni5z//ucmU1Oess86SFStWmFRW7X0NNLvyk5/8xESY7du3r1NVbj3W1xKZr+Ns0cK3IUOGSL9+/eoUyTLOjde6dWtJSkryOI6MYeNNnjxZ3nvvPVm5cqXk5eU5n9ex1Wm3I0eOuP21z7j7R6d2tOhbP0QtmiHU8f79739v/vpnnBtPV/JceOGFbs9dcMEFsmTJEvNvayx1XPVYiz7WlbEhF/IqmBize/du+7///W/n7R//+IcpzFq8eLG9sLDQrcizurra+b5p06ZR5OmnvXv3mgK5m266yX7y5Mk6rzPOwSumnTx5slsxbceOHSmmbQQtLtQCZS1K/vrrr+u8bhV56u8Ny1dffUWRp5/Kysrcfh/r7fLLL7f/9Kc/Nf9mnIPj5ptvrlNMO2XKFHvfvn3dimmfffZZ5+tHjx4NWzEtgUoDdu7cWWfVj/6fo127dvb//M//tG/ZssW+YMECe0ZGhv2Pf/xjRK811oKUs88+237VVVeZfxcVFTlvFsY5OHTc9BfKa6+9Zv/iiy/sd955p71ly5b24uLiSF9azLr77rvtLVq0sH/88cduP7sVFRXOY+666y57p06d7CtWrLBv2LDB/NK3fvEjcK6rfhTj3HiffvqpPTk52f7f//3f9u3bt9vnzZtnfte++eabzmOefPJJ83vj7bfftm/evNk+atQos0rz+PHj9lAjUAkgUFGff/65iUD1A0D/OtVvInw3d+5cM66ebq4Y5+CYPXu2+WWemppqMizr1q2L9CXFNG8/u/pzbdFf4P/1X/9lsoL6S//66693C8QRnECFcQ6Od999137RRReZ37XammPOnDlur2tW5ZFHHjF/POox+kfmtm3b7OFg0/8J/QQTAACA/xJm1Q8AAIg9BCoAACBqEagAAICoRaACAACiFoEKAACIWgQqAAAgahGoAACAqEWgAgAAohaBCgAAiFoEKgAAIGoRqAAAgKhFoAIAACRa/f8KoEylxJgcJgAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# data for training the ann mode\n", + "# option 1:\n", + "celsius = np.array([-40, -10, 0, 8, 15, 22, 38], dtype=float)\n", + "fahrenheit = np.array([-40, 14, 32, 46, 59, 72, 100], dtype=float)\n", + "\n", + "# option 2: (X°C x 9/5) + 32 = 41 °F\n", + "points = 100\n", + "np.random.seed(99)\n", + "dataIn = np.linspace (-40,60, points)\n", + "target = dataIn*9/5 + 32 +4*np.random.randn(points)\n", + "\n", + "plt.plot(celsius, fahrenheit, 'or', label='data-set 1')\n", + "plt.plot(dataIn, target, '.b', alpha=0.3, label='data-set 2')\n", + "plt.legend()\n", + "plt.grid()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Model: \"sequential_1\"\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1mModel: \"sequential_1\"\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
+       "┃ Layer (type)                     Output Shape                  Param # ┃\n",
+       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
+       "│ hidden (Dense)                  │ (None, 2)              │             4 │\n",
+       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+       "│ output (Dense)                  │ (None, 1)              │             3 │\n",
+       "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
+       "
\n" + ], + "text/plain": [ + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n", + "┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n", + "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n", + "│ hidden (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m2\u001b[0m) │ \u001b[38;5;34m4\u001b[0m │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ output (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1\u001b[0m) │ \u001b[38;5;34m3\u001b[0m │\n", + "└─────────────────────────────────┴────────────────────────┴───────────────┘\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Total params: 7 (28.00 B)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m7\u001b[0m (28.00 B)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Trainable params: 7 (28.00 B)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m7\u001b[0m (28.00 B)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Non-trainable params: 0 (0.00 B)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from tensorflow.keras.models import Sequential # ANN type\n", + "from tensorflow.keras.layers import Dense, Input # All nodes connected\n", + "\n", + "# NN definition\n", + "hn=2\n", + "model = Sequential()\n", + "model.add(Input(shape=(1,), name='input'))\n", + "model.add(Dense(hn, activation='linear', name='hidden'))\n", + "model.add(Dense(1, activation='linear', name='output'))\n", + "model.summary()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "### veri important note implement a python code \n", + "# to show the ANN model connection using ascii" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Starting training ...\n", + "Model trainned!\n" + ] + } + ], + "source": [ + "from tensorflow.keras.optimizers import Adam\n", + "\n", + "#hyper parameters\n", + "epoch = 500\n", + "lr = 0.01\n", + "hn = 2 # hidden nodes\n", + "tf.random.set_seed(42) # For TensorFlow\n", + "\n", + "\n", + "model.compile(optimizer=Adam(lr), loss='mean_squared_error')\n", + "print(\"Starting training ...\")\n", + "historial = model.fit(dataIn, target, epochs=epoch, verbose=False,)\n", + "print(\"Model trainned!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m4/4\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4ms/step \n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "predict = model.predict(dataIn)\n", + "plt.plot(dataIn, predict, ':r', label='estimated')\n", + "plt.plot(dataIn,target, '.b', label='real', alpha=0.4)\n", + "plt.legend()\n", + "plt.grid()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Layer: hidden\n", + " Weights (Kernel): (1, 2) \n", + "[[-0.27738443 0.7908125 ]]\n", + " Biases: (2,) \n", + "[-8.219968 6.714554]\n", + "Layer: output\n", + " Weights (Kernel): (2, 1) \n", + "[[-1.9934888]\n", + " [ 1.5958738]]\n", + " Biases: (1,) \n", + "[5.1361823]\n" + ] + } + ], + "source": [ + "# Get weights\n", + "for layer in model.layers:\n", + " weights = layer.get_weights()\n", + " print(f\"Layer: {layer.name}\")\n", + " print(f\" Weights (Kernel): {weights[0].shape} \\n{weights[0]}\")\n", + " print(f\" Biases: {weights[1].shape} \\n{weights[1]}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Testing the model" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 87ms/step\n" + ] + }, + { + "data": { + "text/plain": [ + "array([[213.73816]], dtype=float32)" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "inTest = np.array([100])\n", + "model.predict(inTest)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([213.73814765])" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Do the Maths:\n", + "inTest = np.array(inTest)\n", + "whi = np.array([[-0.27738443, 0.7908125 ]])\n", + "bh = np.array([-8.219968, 6.714554])\n", + "Oh = np.dot(inTest,whi)+bh\n", + "who = np.array([[-1.9934888],[ 1.5958738]])\n", + "bo = np.array([5.1361823])\n", + "Oo = np.dot(Oh,who)+bo\n", + "Oo" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Artificial Neural Network Architecture:\n", + "\n", + "Layer 1: hidden (Dense)\n", + " Inputs: 1, Neurons: 2\n", + " Weights Shape: (1, 2)\n", + " Biases Shape: (2,)\n", + " o o <- Output Neurons\n", + " | | \n", + " | <- Inputs\n", + "\n", + "Layer 2: output (Dense)\n", + " Inputs: 2, Neurons: 1\n", + " Weights Shape: (2, 1)\n", + " Biases Shape: (1,)\n", + " o <- Output Neurons\n", + " | \n", + " | | <- Inputs\n", + "\n" + ] + } + ], + "source": [ + "def generate_ascii_ann(model):\n", + " ascii_diagram = \"\\nArtificial Neural Network Architecture:\\n\"\n", + " \n", + " for i, layer in enumerate(model.layers):\n", + " weights = layer.get_weights()\n", + " \n", + " # Determine layer type and number of neurons\n", + " if isinstance(layer, Dense):\n", + " input_dim = weights[0].shape[0] # Number of inputs\n", + " output_dim = weights[0].shape[1] # Number of neurons\n", + " \n", + " ascii_diagram += f\"\\nLayer {i+1}: {layer.name} ({layer.__class__.__name__})\\n\"\n", + " ascii_diagram += f\" Inputs: {input_dim}, Neurons: {output_dim}\\n\"\n", + " ascii_diagram += f\" Weights Shape: {weights[0].shape}\\n\"\n", + "\n", + " if len(weights) > 1: # If bias exists\n", + " ascii_diagram += f\" Biases Shape: {weights[1].shape}\\n\"\n", + "\n", + " # ASCII representation of neurons\n", + " ascii_diagram += \" \" + \" o \" * output_dim + \" <- Output Neurons\\n\"\n", + " ascii_diagram += \" | \" * output_dim + \"\\n\"\n", + " ascii_diagram += \" \" + \" | \" * input_dim + \" <- Inputs\\n\"\n", + "\n", + " return ascii_diagram\n", + "\n", + "# Generate and print the ASCII diagram\n", + "ascii_ann = generate_ascii_ann(model)\n", + "print(ascii_ann)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```mermaid\n", + "graph LR\n", + "I1((I_1)) --> H1((H_1)) & H2((H_1))\n", + "H1 & H2 --> O1((O_1)) & O2((O_2))\n", + "```" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}