{ "cells": [ { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "# Usage\n", "In this tutorial we use [Braess network](https://en.wikipedia.org/wiki/Braess%27s_paradox#Mathematical_approach)\n", "as an example." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Import Modules\n", "Import grapharray module." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import grapharray as ga" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Define Variables\n", "First, create a BaseGraph object, which describes the network on that variables are defined. It plays two roles when we define arrays:\n", "\n", "* Identifying on which network the variable is defined\n", "* Memory of the network structure. " ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "BG = ga.BaseGraph()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "BaseGraph class is a subclass of [networkx.DiGraph](https://networkx.org/documentation/stable/reference/classes/digraph.html#networkx.DiGraph) so you can add edges and nodes to BaseGraph instance in the same way as to DiGraph.Note that GraphArray accepts any hashable objects as nodes, as does NetworkX." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "BG.add_edges_from([\n", " ('start', 'A'),\n", " ('start', 'B') ,\n", " ('A', 'B'),\n", " ('A', 'end'),\n", " ('B', 'end')\n", "])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then, freeze BaseGraph object to prevent being modified after defining variables. " ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "BG.freeze()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, create NodeArray instance to define node variables or EdgeArray instance to define edge variables. We must pass a **frozen** BaseGraph object to array classes." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "index\tvalue\n", "start\t0.0\n", "A\t0.0\n", "B\t0.0\n", "end\t0.0\n", "\n", "index\tvalue\n", "('start', 'A')\t0.0\n", "('start', 'B')\t0.0\n", "('A', 'B')\t0.0\n", "('A', 'end')\t0.0\n", "('B', 'end')\t0.0\n", "\n" ] } ], "source": [ "od_flow = ga.NodeArray(BG)\n", "print(repr(od_flow))\n", "edge_cost = ga.EdgeArray(BG)\n", "print(repr(edge_cost))" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "These codes make variables defined on all nodes or edges of BG,\n", "all of whose values are zero." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can set initial values of variables as you want by giving a\n", "keyword argument ```init_val```.\n", "The argument ```init_val``` accepts several types of variables.\n", "if you want to set all initial values as the same value, simply give a scalar:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "index\tvalue\n", "start\t10.0\n", "A\t10.0\n", "B\t10.0\n", "end\t10.0\n", "\n", "index\tvalue\n", "('start', 'A')\t10.0\n", "('start', 'B')\t10.0\n", "('A', 'B')\t10.0\n", "('A', 'end')\t10.0\n", "('B', 'end')\t10.0\n", "\n" ] } ], "source": [ "od_flow = ga.NodeArray(BG, init_val=10)\n", "print(repr(od_flow))\n", "edge_cost = ga.EdgeArray(BG, init_val=10)\n", "print(repr(edge_cost))" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "or if you want to set each value in detail, give\n", "* a dictionary that has node- or edge- indexes as keys and initial values as values:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "index\tvalue\n", "start\t-6.0\n", "A\t0.0\n", "B\t0.0\n", "end\t6.0\n", "\n", "index\tvalue\n", "('start', 'A')\t0.0\n", "('start', 'B')\t50.0\n", "('A', 'B')\t10.0\n", "('A', 'end')\t50.0\n", "('B', 'end')\t0.0\n", "\n" ] } ], "source": [ "od_flow = ga.NodeArray(BG, init_val={\n", " 'start': -6,\n", " 'A': 0,\n", " 'B': 0,\n", " 'end': 6\n", "})\n", "print(repr(od_flow))\n", "edge_cost = ga.EdgeArray(BG, init_val={\n", " ('start', 'A'): 0,\n", " ('start', 'B'): 50 ,\n", " ('A', 'B'): 10,\n", " ('A', 'end'): 50,\n", " ('B', 'end'): 0\n", "})\n", "print(repr(edge_cost))" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "* a NodeArray or EdgeArray object (initializing by them is faster than that\n", "by dictionary)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "index\tvalue\n", "start\t-6.0\n", "A\t0.0\n", "B\t0.0\n", "end\t6.0\n", "\n", "index\tvalue\n", "('start', 'A')\t0.0\n", "('start', 'B')\t50.0\n", "('A', 'B')\t10.0\n", "('A', 'end')\t50.0\n", "('B', 'end')\t0.0\n", "\n" ] } ], "source": [ "new_od_flow = ga.NodeArray(BG, init_val=od_flow)\n", "print(repr(new_od_flow))\n", "new_edge_cost = ga.EdgeArray(BG, init_val=edge_cost)\n", "print(repr(new_edge_cost))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Update array values" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "You can modify values after creating instances as we show below." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "index\tvalue\n", "start\t-6.0\n", "A\t100.0\n", "B\t0.0\n", "end\t6.0\n", "\n", "index\tvalue\n", "('start', 'A')\t0.0\n", "('start', 'B')\t50.0\n", "('A', 'B')\t100.0\n", "('A', 'end')\t50.0\n", "('B', 'end')\t0.0\n", "\n" ] } ], "source": [ "new_od_flow['A'] = 100\n", "print(repr(new_od_flow))\n", "new_edge_cost['A', 'B'] = 100\n", "print(repr(new_edge_cost))\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "## Mathematical Operations" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "NodeArray and EdgeArray objects can be added to, subtracted from, multiplied by and divided\n", "by another objects of the same classes." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "nbsphinx": "hidden" }, "outputs": [], "source": [ "import warnings\n", "warnings.filterwarnings(\"ignore\")" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "index\tvalue\n", "start\t-12.0\n", "A\t100.0\n", "B\t0.0\n", "end\t12.0\n", "\n", "index\tvalue\n", "start\t0.0\n", "A\t100.0\n", "B\t0.0\n", "end\t0.0\n", "\n", "index\tvalue\n", "start\t36.0\n", "A\t0.0\n", "B\t0.0\n", "end\t36.0\n", "\n", "index\tvalue\n", "start\t1.0\n", "A\tinf\n", "B\tnan\n", "end\t1.0\n", "\n" ] } ], "source": [ "print(repr(new_od_flow + od_flow))\n", "print(repr(new_od_flow - od_flow))\n", "print(repr(new_od_flow * od_flow))\n", "print(repr(new_od_flow / od_flow)) # this raises warnings because of the zero division" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "NodeArray and EdgeArray objects also operated with scalar values." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "nbsphinx": "hidden" }, "outputs": [], "source": [ "import warnings\n", "warnings.filterwarnings(\"ignore\")" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "index\tvalue\n", "start\t-1.0\n", "A\t105.0\n", "B\t5.0\n", "end\t11.0\n", "\n", "index\tvalue\n", "start\t-11.0\n", "A\t95.0\n", "B\t-5.0\n", "end\t1.0\n", "\n", "index\tvalue\n", "start\t-30.0\n", "A\t500.0\n", "B\t0.0\n", "end\t30.0\n", "\n", "index\tvalue\n", "start\t-1.2\n", "A\t20.0\n", "B\t0.0\n", "end\t1.2\n", "\n" ] } ], "source": [ "print(repr(new_od_flow + 5))\n", "print(repr(new_od_flow - 5))\n", "print(repr(new_od_flow * 5))\n", "print(repr(new_od_flow / 5))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Visualizing Values" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(Coming soon...)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "## Computational Efficiency" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "NodeArray and EdgeArray stores variables' values as np.ndarray and\n", "the mathematical operations shown above are operated with these arrays." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ -6. 100. 0. 6.]\n", "[ -6. 100. 0. 6.]\n" ] } ], "source": [ "print(new_od_flow.array) # You can see the array by .array property.\n", "new_od_flow.array[1] = 5 # .array is read-only\n", "print(new_od_flow.array)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } }, "source": [ "Thus, these operation is as fast as that of np.ndarray.\n", "The larger the network is, the smaller the difference between the speed of\n", "these two methods are." ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "# Create a huge graph to show computational efficiency.\n", "import random\n", "import numpy as np\n", "import time\n", "import timeit\n", "\n", "BG = ga.BaseGraph()\n", "BG.add_nodes_from(list(range(10000)))\n", "for i in range(20000):\n", " edge = random.sample(BG.nodes, 2)\n", " BG.add_edge(*edge)\n", "BG.freeze()\n", "timeit_args = {\n", " 'timer': time.process_time, 'number': 100000, 'globals': globals()\n", "}" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "calculation with NodeArray ============\n", "0.5805510000000003\n", "calculation with np.ndarray =========\n", "0.36343000000000014\n" ] } ], "source": [ "print(\"calculation with NodeArray ============\")\n", "e1 = ga.NodeArray(BG, init_val = 1)\n", "e2 = ga.NodeArray(BG, init_val = 2.5739)\n", "print(timeit.timeit(\"e1 + e2\", **timeit_args))\n", "print(\"calculation with np.ndarray =========\")\n", "a1 = e1.array\n", "a2 = e2.array\n", "print(timeit.timeit(\"a1 + a2\", **timeit_args))" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "calculation with EdgeArray ============\n", "0.887826\n", "calculation with np.ndarray =========\n", "0.6614020000000003\n" ] } ], "source": [ "print(\"calculation with EdgeArray ============\")\n", "e1 = ga.EdgeArray(BG, init_val = 1)\n", "e2 = ga.EdgeArray(BG, init_val = 2.5739)\n", "print(timeit.timeit(\"e1 + e2\", **timeit_args))\n", "print(\"calculation with np.ndarray =========\")\n", "a1 = e1.array\n", "a2 = e2.array\n", "print(timeit.timeit(\"a1 + a2\", **timeit_args))" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false, "pycharm": { "is_executing": true, "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "calculation with graphvar ============\n", "5.138795000000001\n", "calculation with np.ndarray =========\n", "4.9411369999999994\n" ] } ], "source": [ "print(\"calculation with graphvar ============\")\n", "e = ga.EdgeArray(BG, init_val = 1)\n", "A = ga.IncidenceMatrix(BG)\n", "print(timeit.timeit(\"A @ e\", **timeit_args))\n", "print(\"calculation with np.ndarray =========\")\n", "e = e.array\n", "A = A.array\n", "print(timeit.timeit(\"A @ e\", **timeit_args))" ] } ], "metadata": { "interpreter": { "hash": "f2ffb8b5334c49f8c6c65d9f2528980ed76d4aaae3218e239d160dc27767b75d" }, "kernelspec": { "display_name": "Python 3.8.11 64-bit ('tnpsav': conda)", "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.8.11" } }, "nbformat": 4, "nbformat_minor": 1 }