{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "173d88ba-3333-4eea-80df-f891d10c0127",
   "metadata": {},
   "source": [
    "# MobsPy Operators \n",
    "\n",
    "MobsPy possesses several operators to facilitate reaction design further and simplify models. We go over them in this section.\n",
    "\n",
    "## Rev Operator\n",
    "\n",
    "Firstly, Rev stands for Reversible. It is the operator that allows one to define a reaction and its reversed reaction at the same time. \n",
    "This operator also requires two rates instead of one, one for the direct reaction sense and the other for the inverse. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "7fbafb3a-6f98-48de-9642-624ec56875cf",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Compiling model\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Species\n",
      "A,0\n",
      "Ab,0\n",
      "L,0\n",
      "\n",
      "Mappings\n",
      "A :\n",
      "A\n",
      "Ab :\n",
      "Ab\n",
      "L :\n",
      "L\n",
      "\n",
      "Parameters\n",
      "volume,1\n",
      "\n",
      "Reactions\n",
      "reaction_0,{'re': [(1, 'A'), (3, 'L')], 'pr': [(1, 'Ab')], 'kin': 'A * L * L * L * 1 * volume^-3'}\n",
      "reaction_1,{'re': [(1, 'Ab')], 'pr': [(1, 'A'), (3, 'L')], 'kin': 'Ab * 2'}\n",
      "\n"
     ]
    }
   ],
   "source": [
    "from mobspy import *\n",
    "from mobspy.modules.order_operators import Rev\n",
    "\n",
    "A, L, Ab = BaseSpecies()\n",
    "\n",
    "Rev[A + 3*L >> Ab][1, 2]\n",
    "\n",
    "S = Simulation(A | L | Ab)\n",
    "print(S.compile())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f584829c-c4a2-4b2d-bd60-8a11a38a13fd",
   "metadata": {},
   "source": [
    "## All Operator\n",
    "\n",
    "The All operator was already mentioned in the Assignments, Initial Conditions and Born Species sections.  So we summarize all its functions here. It can set the initial amounts of and assign an operation to all states of a meta-species instead of only the default one one. Further, it can create define reactions to all states of a meta-species instead of only one.\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "c0e7dfca-f905-4f1d-a6eb-a5948ae02177",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Compiling model\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Species\n",
      "A.a1,0\n",
      "A.a2,0\n",
      "A.a3,0\n",
      "A.a4,0\n",
      "B.b1,10\n",
      "B.b2,10\n",
      "\n",
      "Mappings\n",
      "A :\n",
      "A.a1\n",
      "A.a2\n",
      "A.a3\n",
      "A.a4\n",
      "B :\n",
      "B.b1\n",
      "B.b2\n",
      "\n",
      "Parameters\n",
      "volume,1\n",
      "\n",
      "Reactions\n",
      "reaction_0,{'re': [(1, 'A.a1')], 'pr': [(1, 'A.a1')], 'kin': 'A.a1 * 1'}\n",
      "reaction_1,{'re': [(1, 'A.a1')], 'pr': [(1, 'A.a2')], 'kin': 'A.a1 * 1'}\n",
      "reaction_2,{'re': [(1, 'A.a1')], 'pr': [(1, 'A.a3')], 'kin': 'A.a1 * 1'}\n",
      "reaction_3,{'re': [(1, 'A.a1')], 'pr': [(1, 'A.a4')], 'kin': 'A.a1 * 1'}\n",
      "\n",
      "Assignments\n",
      "assignment_0,{'species': 'A.a1', 'expression': '(2*(B.b1))'}\n",
      "assignment_1,{'species': 'A.a2', 'expression': '(2*(B.b1))'}\n",
      "assignment_2,{'species': 'A.a3', 'expression': '(2*(B.b1))'}\n",
      "assignment_3,{'species': 'A.a4', 'expression': '(2*(B.b1))'}\n",
      "\n"
     ]
    }
   ],
   "source": [
    "from mobspy import *\n",
    "\n",
    "A, B = BaseSpecies()\n",
    "A.a1, A.a2, A.a3, A.a4\n",
    "B.b1, B.b2\n",
    "\n",
    "All[A].assign(2*B.b1)\n",
    "\n",
    "All[B](10)\n",
    "\n",
    "A.a1 >> All[A] [1]\n",
    "\n",
    "S = Simulation(A | B)\n",
    "print(S.compile())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "089e8b00-0119-46dc-a35e-38aab8169c68",
   "metadata": {},
   "source": [
    "## Any Operator\n",
    "\n",
    "The Any operator is used to simplify sets of reactions where all reactants have a common query. For instance, it is useful when the user implements compartments (or locations) as characteristics. In this case, the user is likely to implement reactions that happen only in specific locations. \n",
    "\n",
    "To use the Any operator, one must use Python's native \"with\" and put the Any operator under context with a dot operator query. The query will then be performed automatically in all reactions defined under this context. In the example below, we show a group of reactions defined with the Any operator and the equivalent reactions defined without it. \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "3df9f5d3-5dc8-4a39-80a7-181461d70d7c",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Compiling model\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Species\n",
      "A.l1,0\n",
      "A.l2,0\n",
      "B.l1,0\n",
      "B.l2,0\n",
      "C.l1,0\n",
      "C.l2,0\n",
      "\n",
      "Mappings\n",
      "A :\n",
      "A.l1\n",
      "A.l2\n",
      "B :\n",
      "B.l1\n",
      "B.l2\n",
      "C :\n",
      "C.l1\n",
      "C.l2\n",
      "\n",
      "Parameters\n",
      "volume,1\n",
      "\n",
      "Reactions\n",
      "reaction_0,{'re': [(1, 'A.l1'), (1, 'B.l1')], 'pr': [(2, 'A.l1')], 'kin': 'A.l1 * B.l1 * 1 * volume^-1'}\n",
      "reaction_1,{'re': [(1, 'A.l1'), (1, 'B.l1')], 'pr': [(2, 'A.l1')], 'kin': 'A.l1 * B.l1 * 1 * volume^-1'}\n",
      "reaction_2,{'re': [(1, 'A.l1')], 'pr': [(1, 'C.l1')], 'kin': 'A.l1 * 1'}\n",
      "reaction_3,{'re': [(1, 'A.l1')], 'pr': [(1, 'C.l1')], 'kin': 'A.l1 * 1'}\n",
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[91mWARNING: The following reaction: \n",
      "{'re': [(1, 'A_dot_l1'), (1, 'B_dot_l1')], 'pr': [(2, 'A_dot_l1')], 'kin': 'A_dot_l1 * B_dot_l1 * 1 * volume^-1'} \n",
      "Is doubled. Was that intentional? \n",
      "\u001b[0m\n",
      "\u001b[91mWARNING: The following reaction: \n",
      "{'re': [(1, 'A_dot_l1')], 'pr': [(1, 'C_dot_l1')], 'kin': 'A_dot_l1 * 1'} \n",
      "Is doubled. Was that intentional? \n",
      "\u001b[0m\n",
      "\u001b[91mWARNING: The following reaction: \n",
      "{'re': [(1, 'A_dot_l1'), (1, 'B_dot_l1')], 'pr': [(2, 'A_dot_l1')], 'kin': 'A_dot_l1 * B_dot_l1 * 1 * volume^-1'} \n",
      "Is doubled. Was that intentional? \n",
      "\u001b[0m\n",
      "\u001b[91mWARNING: The following reaction: \n",
      "{'re': [(1, 'A_dot_l1')], 'pr': [(1, 'C_dot_l1')], 'kin': 'A_dot_l1 * 1'} \n",
      "Is doubled. Was that intentional? \n",
      "\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "Location = BaseSpecies()\n",
    "Location.l1, Location.l2\n",
    "A, B, C = New(Location)\n",
    "\n",
    "# Any operator\n",
    "with Any.l1:\n",
    "    A + B >> 2*A [1]\n",
    "    A >> C [1]\n",
    "\n",
    "# Equivalent reactions\n",
    "A.l1 + B.l1 >> 2*A.l1 [1]\n",
    "A.l1 >> C.l1 [1]\n",
    "\n",
    "S = Simulation(A | B | C)\n",
    "print(S.compile())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e81ba3d-e424-4818-afce-237feaecd3b7",
   "metadata": {},
   "source": [
    "The Any operator can also be replaced by any meta-species. The model above can be equality written using the Location meta-species. The Any operator offers the advantage that it can be used with any characteristics. However, use the Location meta-species offers more legibility. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "58b2ca56-6720-49f0-9d1c-7e2683b47117",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Compiling model\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Species\n",
      "A.l1,0\n",
      "A.l2,0\n",
      "B.l1,0\n",
      "B.l2,0\n",
      "C.l1,0\n",
      "C.l2,0\n",
      "\n",
      "Mappings\n",
      "A :\n",
      "A.l1\n",
      "A.l2\n",
      "B :\n",
      "B.l1\n",
      "B.l2\n",
      "C :\n",
      "C.l1\n",
      "C.l2\n",
      "\n",
      "Parameters\n",
      "volume,1\n",
      "\n",
      "Reactions\n",
      "reaction_0,{'re': [(1, 'A.l1'), (1, 'B.l1')], 'pr': [(2, 'A.l1')], 'kin': 'A.l1 * B.l1 * 1 * volume^-1'}\n",
      "reaction_1,{'re': [(1, 'A.l1')], 'pr': [(1, 'C.l1')], 'kin': 'A.l1 * 1'}\n",
      "\n"
     ]
    }
   ],
   "source": [
    "Location = BaseSpecies()\n",
    "Location.l1, Location.l2\n",
    "A, B, C = New(Location)\n",
    "\n",
    "# Any operator\n",
    "with Location.l1:\n",
    "    A + B >> 2*A [1]\n",
    "    A >> C [1]\n",
    "\n",
    "S = Simulation(A | B | C)\n",
    "print(S.compile())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0a670469-f823-48dc-a71b-288f8ffaf729",
   "metadata": {},
   "source": [
    "These contexts can also be chained together for further simplification. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5e20f663-2bc3-4e4d-859c-63fbe244f873",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
