diff --git a/examples/door.ipynb b/examples/door.ipynb index cfa2923..ebc36d2 100644 --- a/examples/door.ipynb +++ b/examples/door.ipynb @@ -2,21 +2,21 @@ "cells": [ { "cell_type": "code", - "execution_count": 5, "id": "initial_id", "metadata": { "collapsed": true, "ExecuteTime": { - "end_time": "2024-04-02T06:11:00.232894Z", - "start_time": "2024-04-02T06:11:00.190359Z" + "end_time": "2024-05-31T15:17:37.003610Z", + "start_time": "2024-05-31T15:17:36.947152Z" } }, "source": [ - "from random_events.events import Event, ComplexEvent\n", - "from random_events.variables import Continuous\n", - "import portion\n", + "from random_events.product_algebra import Event, SimpleEvent\n", + "from random_events.variable import Continuous\n", + "from random_events.interval import *\n", + "import plotly\n", "import plotly.graph_objects as go\n", - "\n", + "plotly.offline.init_notebook_mode()\n", "\n", "grey = \"#7f7f7f\"\n", "gold = \"#bcbd22\"\n", @@ -25,37 +25,81 @@ "y = Continuous(\"y\")\n", "z = Continuous(\"z\")\n", "\n", - "lock = Event({x: portion.closedopen(0, 6), y: portion.closedopen(0, 10), z: portion.closedopen(0, 10)})\n", + "lock = Event({x: closed_open(0, 6), y: closed_open(0, 10), z: closed_open(0, 10)})\n", "\n", - "keyhole = Event({y: portion.closedopen(0, 5), x: portion.closedopen(2, 4), z: portion.closedopen(6, 8)})\n", - "keyhole_rod = Event({y: portion.closedopen(0, 5), x: portion.closedopen(2.5, 3.5), z: portion.closedopen(3, 6)})\n", + "keyhole = Event({y: closed_open(0, 5), x: closed_open(2, 4), z: closed_open(6, 8)})\n", + "keyhole_rod = Event({y: closed_open(0, 5), x: closed_open(2.5, 3.5), z: closed_open(3, 6)})\n", "keyhole |= keyhole_rod\n", "\n", - "keyhole_teeth = ComplexEvent([])\n", - "keyhole_teeth |= Event({y: portion.closedopen(4, 5), z: portion.closedopen(6, 7), x: portion.openclosed(1, 2)})\n", - "keyhole_teeth |= Event({y: portion.closedopen(3, 4), z: portion.closedopen(7, 8), x: portion.openclosed(4, 5)})\n", - "keyhole_teeth |= Event({y: portion.closedopen(2, 3), z: portion.closedopen(8, 9), x: portion.openclosed(2, 4)})\n", + "keyhole_teeth = Event([SimpleEvent({y: closed_open(4, 5), z: closed_open(6, 7), x: closed_open(1, 2)})])\n", + "keyhole_teeth |= Event([SimpleEvent({y: closed_open(3, 4), z: closed_open(7, 8), x: closed_open(4, 5)})])\n", + "keyhole_teeth |= Event([SimpleEvent({y: closed_open(2, 3), z: closed_open(8, 9), x: closed_open(2, 4)})])\n", "keyhole |= keyhole_teeth\n", "\n", "lock = lock.difference(keyhole)\n", + "print(lock)\n", "fig = go.Figure()\n", "fig.add_traces(lock.plot(color=\"grey\"))\n", "fig.add_traces(keyhole.plot(gold))\n", "fig.show()" ], - "outputs": [] + "outputs": [ + { + "data": { + "text/html": [ + " \n", + " " + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "ename": "AttributeError", + "evalue": "'Continuous' object has no attribute 'variables'", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mAttributeError\u001B[0m Traceback (most recent call last)", + "Cell \u001B[0;32mIn[8], line 15\u001B[0m\n\u001B[1;32m 12\u001B[0m y \u001B[38;5;241m=\u001B[39m Continuous(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124my\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m 13\u001B[0m z \u001B[38;5;241m=\u001B[39m Continuous(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mz\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[0;32m---> 15\u001B[0m lock \u001B[38;5;241m=\u001B[39m \u001B[43mEvent\u001B[49m\u001B[43m(\u001B[49m\u001B[43m{\u001B[49m\u001B[43mx\u001B[49m\u001B[43m:\u001B[49m\u001B[43m \u001B[49m\u001B[43mclosed_open\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;241;43m0\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m6\u001B[39;49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43my\u001B[49m\u001B[43m:\u001B[49m\u001B[43m \u001B[49m\u001B[43mclosed_open\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;241;43m0\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m10\u001B[39;49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mz\u001B[49m\u001B[43m:\u001B[49m\u001B[43m \u001B[49m\u001B[43mclosed_open\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;241;43m0\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m10\u001B[39;49m\u001B[43m)\u001B[49m\u001B[43m}\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 17\u001B[0m keyhole \u001B[38;5;241m=\u001B[39m Event({y: closed_open(\u001B[38;5;241m0\u001B[39m, \u001B[38;5;241m5\u001B[39m), x: closed_open(\u001B[38;5;241m2\u001B[39m, \u001B[38;5;241m4\u001B[39m), z: closed_open(\u001B[38;5;241m6\u001B[39m, \u001B[38;5;241m8\u001B[39m)})\n\u001B[1;32m 18\u001B[0m keyhole_rod \u001B[38;5;241m=\u001B[39m Event({y: closed_open(\u001B[38;5;241m0\u001B[39m, \u001B[38;5;241m5\u001B[39m), x: closed_open(\u001B[38;5;241m2.5\u001B[39m, \u001B[38;5;241m3.5\u001B[39m), z: closed_open(\u001B[38;5;241m3\u001B[39m, \u001B[38;5;241m6\u001B[39m)})\n", + "File \u001B[0;32m~/random-events/src/random_events/product_algebra.py:267\u001B[0m, in \u001B[0;36mEvent.__init__\u001B[0;34m(self, simple_sets)\u001B[0m\n\u001B[1;32m 265\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m__init__\u001B[39m(\u001B[38;5;28mself\u001B[39m, simple_sets: Iterable[SimpleEvent]):\n\u001B[1;32m 266\u001B[0m \u001B[38;5;28msuper\u001B[39m()\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__init__\u001B[39m(simple_sets)\n\u001B[0;32m--> 267\u001B[0m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mfill_missing_variables\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n", + "File \u001B[0;32m~/random-events/src/random_events/product_algebra.py:278\u001B[0m, in \u001B[0;36mEvent.fill_missing_variables\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 274\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mfill_missing_variables\u001B[39m(\u001B[38;5;28mself\u001B[39m):\n\u001B[1;32m 275\u001B[0m \u001B[38;5;250m \u001B[39m\u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[1;32m 276\u001B[0m \u001B[38;5;124;03m Fill all simple sets with the missing variables.\u001B[39;00m\n\u001B[1;32m 277\u001B[0m \u001B[38;5;124;03m \"\"\"\u001B[39;00m\n\u001B[0;32m--> 278\u001B[0m all_variables \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mall_variables\u001B[49m\n\u001B[1;32m 279\u001B[0m \u001B[38;5;28;01mfor\u001B[39;00m simple_set \u001B[38;5;129;01min\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39msimple_sets:\n\u001B[1;32m 280\u001B[0m simple_set\u001B[38;5;241m.\u001B[39mfill_missing_variables(all_variables)\n", + "File \u001B[0;32m~/random-events/src/random_events/product_algebra.py:272\u001B[0m, in \u001B[0;36mEvent.all_variables\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 269\u001B[0m \u001B[38;5;129m@property\u001B[39m\n\u001B[1;32m 270\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mall_variables\u001B[39m(\u001B[38;5;28mself\u001B[39m) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m SortedSet[Variable]:\n\u001B[1;32m 271\u001B[0m result \u001B[38;5;241m=\u001B[39m SortedSet()\n\u001B[0;32m--> 272\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m result\u001B[38;5;241m.\u001B[39munion(\u001B[38;5;241m*\u001B[39m[SortedSet(simple_set\u001B[38;5;241m.\u001B[39mvariables) \u001B[38;5;28;01mfor\u001B[39;00m simple_set \u001B[38;5;129;01min\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39msimple_sets])\n", + "File \u001B[0;32m~/random-events/src/random_events/product_algebra.py:272\u001B[0m, in \u001B[0;36m\u001B[0;34m(.0)\u001B[0m\n\u001B[1;32m 269\u001B[0m \u001B[38;5;129m@property\u001B[39m\n\u001B[1;32m 270\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mall_variables\u001B[39m(\u001B[38;5;28mself\u001B[39m) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m SortedSet[Variable]:\n\u001B[1;32m 271\u001B[0m result \u001B[38;5;241m=\u001B[39m SortedSet()\n\u001B[0;32m--> 272\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m result\u001B[38;5;241m.\u001B[39munion(\u001B[38;5;241m*\u001B[39m[SortedSet(\u001B[43msimple_set\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mvariables\u001B[49m) \u001B[38;5;28;01mfor\u001B[39;00m simple_set \u001B[38;5;129;01min\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39msimple_sets])\n", + "\u001B[0;31mAttributeError\u001B[0m: 'Continuous' object has no attribute 'variables'" + ] + } + ], + "execution_count": 8 }, { + "metadata": {}, "cell_type": "markdown", "source": [ "# Task\n", "\n", "Open the door to more powerful tools by crafting the key to this lock." ], - "metadata": { - "collapsed": false - }, - "id": "c0d592a9fdb0ea1b" + "id": "3b7bba368ae82ab6" } ], "metadata": { diff --git a/examples/example.ipynb b/examples/example.ipynb index ab06571..7715f24 100644 --- a/examples/example.ipynb +++ b/examples/example.ipynb @@ -16,32 +16,55 @@ }, { "cell_type": "code", - "execution_count": 12, "id": "initial_id", "metadata": { "collapsed": true, "ExecuteTime": { - "end_time": "2024-03-28T11:49:17.716003Z", - "start_time": "2024-03-28T11:49:17.678852Z" + "end_time": "2024-05-31T14:59:41.792755Z", + "start_time": "2024-05-31T14:59:41.613041Z" } }, + "source": [ + "from random_events.variable import Symbolic, Integer, Continuous\n", + "from random_events.product_algebra import SimpleEvent, Event\n", + "from random_events.interval import *\n", + "from random_events.set import *\n", + "import plotly\n", + "import plotly.graph_objects as go\n", + "plotly.offline.init_notebook_mode()" + ], "outputs": [ { "data": { - "text/html": " \n " + "text/html": [ + " \n", + " " + ] }, "metadata": {}, "output_type": "display_data" } ], - "source": [ - "from random_events.variables import Symbolic, Integer, Continuous\n", - "from random_events.events import Event, ComplexEvent\n", - "import portion\n", - "import plotly\n", - "import plotly.graph_objects as go\n", - "plotly.offline.init_notebook_mode()" - ] + "execution_count": 1 }, { "cell_type": "markdown", @@ -55,31 +78,35 @@ }, { "cell_type": "code", - "execution_count": 13, + "source": [ + "class SymbolElement(SetElement):\n", + " EMPTY_SET = 0\n", + " APPLE = 1\n", + " DOG = 2\n", + " RAIN = 3\n", + "\n", + "symbol = Symbolic(\"symbol\", SymbolElement)\n", + "integer = Integer(\"integer\")\n", + "real = Continuous(\"real\")\n", + "symbol, integer, real" + ], + "metadata": { + "collapsed": false + }, + "id": "49b07deb8aecb5d0", "outputs": [ { "data": { - "text/plain": "(Symbolic(symbol), Integer(integer), Continuous(real))" + "text/plain": [ + "(Symbolic(symbol), Integer(integer), Continuous(real))" + ] }, - "execution_count": 13, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], - "source": [ - "symbol = Symbolic(\"symbol\", {\"Apple\", \"Dog\", \"Rain\"})\n", - "integer = Integer(\"integer\", {1, 2, 5, 6})\n", - "real = Continuous(\"real\")\n", - "symbol, integer, real" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-03-28T11:49:17.720159Z", - "start_time": "2024-03-28T11:49:17.717130Z" - } - }, - "id": "49b07deb8aecb5d0" + "execution_count": 2 }, { "cell_type": "markdown", @@ -93,17 +120,6 @@ }, { "cell_type": "code", - "execution_count": 14, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'name': 'symbol', 'type': 'random_events.variables.Symbolic', 'domain': ('Apple', 'Dog', 'Rain')}\n", - "Symbolic(symbol, ('Apple', 'Dog', 'Rain'))\n" - ] - } - ], "source": [ "print(symbol.to_json())\n", "print(Symbolic.from_json(symbol.to_json()))" @@ -111,11 +127,22 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2024-03-28T11:49:17.755498Z", - "start_time": "2024-03-28T11:49:17.753307Z" + "end_time": "2024-05-31T14:59:41.834073Z", + "start_time": "2024-05-31T14:59:41.799067Z" } }, - "id": "a3aed36278dab281" + "id": "a3aed36278dab281", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'type': 'random_events.variable.Symbolic', 'name': 'symbol', 'domain': {'type': 'random_events.set.Set', 'simple_sets': [{'type': '__main__.SymbolElement', 'value': 1}, {'type': '__main__.SymbolElement', 'value': 2}, {'type': '__main__.SymbolElement', 'value': 3}]}}\n", + "Symbolic(symbol, {APPLE u DOG u RAIN})\n" + ] + } + ], + "execution_count": 3 }, { "cell_type": "markdown", @@ -129,29 +156,31 @@ }, { "cell_type": "code", - "execution_count": 15, - "outputs": [ - { - "data": { - "text/plain": "{Symbolic(symbol): ('Rain',), Continuous(real): (-inf,2)}" - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ - "event = Event({symbol: \"Rain\", real: portion.open(-portion.inf, 2)})\n", + "event = Event([SimpleEvent({symbol: Set([SymbolElement.RAIN]), real: open(-float(\"inf\"), 2)})])\n", "event" ], "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2024-03-28T11:49:17.761778Z", - "start_time": "2024-03-28T11:49:17.756709Z" + "end_time": "2024-05-31T14:59:41.840160Z", + "start_time": "2024-05-31T14:59:41.835210Z" } }, - "id": "a81cd22d80129c04" + "id": "a81cd22d80129c04", + "outputs": [ + { + "data": { + "text/plain": [ + "{{real = {(-inf, 2)}, symbol = {RAIN}}}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 4 }, { "cell_type": "markdown", @@ -166,35 +195,33 @@ }, { "cell_type": "code", - "execution_count": 16, + "source": [ + "print(event.simple_sets[0][\"real\"])\n", + "print(event.simple_sets[0][real])" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-05-31T14:59:41.844979Z", + "start_time": "2024-05-31T14:59:41.840793Z" + } + }, + "id": "4975045ed9540d52", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "(-inf,2)\n", - "(-inf,2)\n" + "{(-inf, 2)}\n", + "{(-inf, 2)}\n" ] } ], - "source": [ - "print(event[\"real\"])\n", - "print(event[real])" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-03-28T11:49:17.768157Z", - "start_time": "2024-03-28T11:49:17.762723Z" - } - }, - "id": "4975045ed9540d52" + "execution_count": 5 }, { "cell_type": "markdown", - "source": [ - "Events can also be intersected with another event using the intersection method or `&` operator." - ], + "source": "Events can also be intersected with another event using the `intersection_with` method or `&` operator.", "metadata": { "collapsed": false }, @@ -202,30 +229,30 @@ }, { "cell_type": "code", - "execution_count": 17, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{real: (1,2), symbol: ('Rain',)}\n", - "{real: (1,2), symbol: ('Rain',)}\n" - ] - } - ], "source": [ - "second_event = Event({symbol: (\"Rain\", \"Apple\"), real: portion.open(1, 4)})\n", - "print(event.intersection(second_event))\n", + "second_event = Event([SimpleEvent({symbol: Set([SymbolElement.RAIN, SymbolElement.APPLE]), real: open(1, 4)})])\n", + "print(event.intersection_with(second_event))\n", "print(event & second_event)" ], "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2024-03-28T11:49:17.773573Z", - "start_time": "2024-03-28T11:49:17.768994Z" + "end_time": "2024-05-31T14:59:41.850532Z", + "start_time": "2024-05-31T14:59:41.845582Z" } }, - "id": "b4da0a20e367a1c0" + "id": "b4da0a20e367a1c0", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{{real = {(1, 2)}, symbol = {RAIN}}}\n", + "{{real = {(1, 2)}, symbol = {RAIN}}}\n" + ] + } + ], + "execution_count": 6 }, { "cell_type": "markdown", @@ -239,67 +266,31 @@ }, { "cell_type": "code", - "execution_count": 18, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{real: (-inf,2), symbol: ('Rain',)} u {real: [2,4), symbol: ('Apple', 'Rain')} u {real: (1,2), symbol: ('Apple',)}\n", - "{real: [2,4), symbol: ('Apple', 'Rain')} u {real: (1,2), symbol: ('Apple',)}\n", - "{real: (-inf,+inf), symbol: ('Apple', 'Dog')} u {real: [2,+inf), symbol: ('Rain',)}\n" - ] - } - ], "source": [ - "print(event | second_event) # or event.union(second_event)\n", - "print(second_event - event) # or second_event.difference(event)\n", - "print(~event) # or event.complement" + "print(event | second_event) # or event.union_with(second_event)\n", + "print(second_event - event) # or second_event.difference_with(event)\n", + "print(~event) # or event.complement()" ], "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2024-03-28T11:49:17.779131Z", - "start_time": "2024-03-28T11:49:17.775125Z" + "end_time": "2024-05-31T14:59:41.859661Z", + "start_time": "2024-05-31T14:59:41.851206Z" } }, - "id": "e8bb102d6d36e9a8" - }, - { - "cell_type": "markdown", - "source": [ - "Next, the EncodedEvent converts from value assignments to indexed assignments. These can be easily used for array indexing and similar things. For continuous variables, the encoding does not change anything. " - ], - "metadata": { - "collapsed": false - }, - "id": "d7b67ceb54bc41ac" - }, - { - "cell_type": "code", - "execution_count": 19, + "id": "e8bb102d6d36e9a8", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "{symbol: (2,), real: (-inf,2)}\n", - "{symbol: (0, 2), real: (1,4)}\n" + "{{real = {(-inf, 2)}, symbol = {RAIN}} u {real = {(1, 2)}, symbol = {APPLE}}}\n", + "{{real = {(1, 2)}, symbol = {APPLE}} u {real = {[2, 4)}, symbol = {APPLE u RAIN}}}\n", + "{{real = {(-inf, 2)}, symbol = {APPLE u DOG}} u {real = {[2, inf)}, symbol = {APPLE u DOG u RAIN}}}\n" ] } ], - "source": [ - "print(event.encode())\n", - "print(second_event.encode())" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-03-28T11:49:17.786224Z", - "start_time": "2024-03-28T11:49:17.780012Z" - } - }, - "id": "1463b40805ebaddd" + "execution_count": 7 }, { "cell_type": "markdown", @@ -313,6 +304,21 @@ }, { "cell_type": "code", + "source": [ + "x = Continuous(\"x\")\n", + "y = Continuous(\"y\")\n", + "event = Event([SimpleEvent({x: open(0, 1), y: open(0, 1)})])\n", + "fig = go.Figure(event.plot(), event.plotly_layout())\n", + "fig.show()" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-05-31T14:59:41.871566Z", + "start_time": "2024-05-31T14:59:41.860314Z" + } + }, + "id": "8c25f3846c860230", "outputs": [ { "data": { @@ -320,8 +326,13 @@ "data": [ { "fill": "toself", + "legendgroup": "140135962936272", + "line": { + "color": "#636EFA" + }, "mode": "lines", "name": "Event", + "showlegend": true, "x": [ 0, 0, @@ -1182,34 +1193,43 @@ "plotlyServerURL": "https://plot.ly" } }, - "text/html": "
" + "text/html": [ + "
" + ] }, "metadata": {}, "output_type": "display_data" } ], - "source": [ - "x = Continuous(\"x\")\n", - "y = Continuous(\"y\")\n", - "event = Event({x: portion.open(0, 1), y: portion.open(0, 1)})\n", - "fig = go.Figure(event.plot(), event.plotly_layout())\n", - "fig.show()" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-03-28T11:49:17.798205Z", - "start_time": "2024-03-28T11:49:17.786860Z" - } - }, - "id": "8c25f3846c860230", - "execution_count": 20 + "execution_count": 8 }, { "cell_type": "markdown", - "source": [ - "Complex events can also be plotted." - ], + "source": "More complex events can also be plotted.", "metadata": { "collapsed": false }, @@ -1217,6 +1237,21 @@ }, { "cell_type": "code", + "source": [ + "complement = event.complement()\n", + "limiting_event = Event([SimpleEvent({x: closed(-1, 2), y: closed(-1, 2)})])\n", + "result = complement & limiting_event\n", + "fig = go.Figure(result.plot(), result.plotly_layout())\n", + "fig.show()" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-05-31T14:59:41.880501Z", + "start_time": "2024-05-31T14:59:41.872411Z" + } + }, + "id": "d22ef1b9c9b7c767", "outputs": [ { "data": { @@ -1224,7 +1259,7 @@ "data": [ { "fill": "toself", - "legendgroup": "140569888183872", + "legendgroup": "140135962938336", "line": { "color": "#636EFA" }, @@ -1263,7 +1298,7 @@ }, { "fill": "toself", - "legendgroup": "140569888183872", + "legendgroup": "140135962938336", "line": { "color": "#636EFA" }, @@ -2142,28 +2177,39 @@ "plotlyServerURL": "https://plot.ly" } }, - "text/html": "
" + "text/html": [ + "
" + ] }, "metadata": {}, "output_type": "display_data" } ], - "source": [ - "complement = event.complement()\n", - "limiting_event = Event({x: portion.closed(-1, 2), y: portion.closed(-1, 2)})\n", - "result = complement.intersection(ComplexEvent([limiting_event]))\n", - "fig = go.Figure(result.plot(), result.plotly_layout())\n", - "fig.show()" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-03-28T11:49:17.807173Z", - "start_time": "2024-03-28T11:49:17.798871Z" - } - }, - "id": "d22ef1b9c9b7c767", - "execution_count": 21 + "execution_count": 9 }, { "cell_type": "markdown", @@ -2177,30 +2223,32 @@ }, { "cell_type": "code", - "outputs": [ - { - "data": { - "text/plain": "True" - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "complement_json = complement.to_json()\n", - "complement_from_json = ComplexEvent.from_json(complement_json)\n", + "complement_from_json = Event.from_json(complement_json)\n", "complement_from_json == complement" ], "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2024-03-28T11:49:17.813127Z", - "start_time": "2024-03-28T11:49:17.808962Z" + "end_time": "2024-05-31T14:59:41.885814Z", + "start_time": "2024-05-31T14:59:41.881606Z" } }, "id": "12b0c378134e8a09", - "execution_count": 22 + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 10 } ], "metadata": { diff --git a/examples/logo_generation.ipynb b/examples/logo_generation.ipynb index 4a8ed9e..caa136b 100644 --- a/examples/logo_generation.ipynb +++ b/examples/logo_generation.ipynb @@ -15,48 +15,75 @@ }, { "cell_type": "code", - "execution_count": 6, "id": "initial_id", "metadata": { "collapsed": true, "ExecuteTime": { - "end_time": "2024-03-28T11:49:24.529348Z", - "start_time": "2024-03-28T11:49:24.491102Z" + "end_time": "2024-05-31T15:13:30.492296Z", + "start_time": "2024-05-31T15:13:30.457391Z" } }, - "outputs": [ - { - "data": { - "text/html": " \n " - }, - "metadata": {}, - "output_type": "display_data" - } - ], "source": [ "import os.path\n", - "from random_events.events import Event, ComplexEvent\n", - "from random_events.variables import Continuous\n", + "from random_events.product_algebra import Event, SimpleEvent\n", + "from random_events.variable import Continuous\n", + "from random_events.interval import *\n", "from PIL import Image\n", "import numpy as np\n", "import portion\n", "import plotly\n", "plotly.offline.init_notebook_mode()\n", "import plotly.graph_objects as go" - ] + ], + "outputs": [ + { + "data": { + "text/html": [ + " \n", + " " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "execution_count": 36 }, { "cell_type": "code", - "outputs": [], "source": [ "x = Continuous(\"x\")\n", "y = Continuous(\"y\")" ], "metadata": { - "collapsed": false + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-05-31T15:13:30.495388Z", + "start_time": "2024-05-31T15:13:30.493590Z" + } }, "id": "29d0b28a5e6f48ca", - "execution_count": 7 + "outputs": [], + "execution_count": 37 }, { "cell_type": "markdown", @@ -70,31 +97,29 @@ }, { "cell_type": "code", + "source": [ + "path = os.path.join(\"..\", \"doc\", \"logo\", \"Tomato.png\")\n", + "image = im=Image.open(path)\n", + "image" + ], + "metadata": { + "collapsed": false + }, + "id": "6dfb4ca602b7491b", "outputs": [ { "data": { - "text/plain": "", + "text/plain": [ + "" + ], "image/png": "iVBORw0KGgoAAAANSUhEUgAAAMYAAAC7CAYAAAA+J+FCAAAGNklEQVR4Ae3dMZIUVxBFUUahJWDBpliNLJmyWI02NVjsAaEQEbj/datyyHoHCyN/Z+Z9daOM/jH98s6/Rwh8e+TQwZmXgxolAwR+G+ihBQLrCBBjXWQGniBAjAnKeqwjQIx1kRl4ggAxJijrsY4AMdZFZuAJAsSYoKzHOgLEWBeZgScIEGOCsh7rCBBjXWQGniDgCsJPysfXPP78+4+fp/7H//316XPyabJLaIW13hghMOUdBIjRkbMtQwLECIEp7yBAjI6cbRkSIEYITHkHAWJ05GzLkAAxQmDKOwgQoyNnW4YEiBECU95BgBgdOdsyJOBaQQjsR7nrI49xW3PKG2NNVAadJECMSdp6rSFAjDVRGXSSADEmaeu1hgAx1kRl0EkCxJikrdcaAsRYE5VBJwkQY5K2XmsIEGNNVAadJECMSdp6rSHw+5pJHxv0+OrGYx+/5tRVHG57pcgbY82zbdBJAsSYpK3XGgLEWBOVQScJEGOStl5rCBBjTVQGnSRAjEnaeq0hQIw1URl0kgAxJmnrtYYAMdZEZdBJAsSYpK3XGgK/ylf6l1xZuOoHXtake/Gg4Q/dJNO8+XPpjZHEpbaGADFqorZoQoAYCS21NQSIURO1RRMCxEhoqa0hQIyaqC2aECBGQkttDQFi1ERt0YQAMRJaamsIEKMmaosmBK786n3VNY/kesO2qya/wm7JDMkD/L32kmfYGyNMQXkHAWJ05GzLkAAxQmDKOwgQoyNnW4YEiBECU95BgBgdOdsyJECMEJjyDgLE6MjZliEBYoTAlHcQIEZHzrYMCaQ/HHN8zePrh4/Ho7z/8npcmxQm1xCieT99Ph7jqusjd94tyuLL6/Ez+T204+sj3hjHj7jCJgLEaErbrscEiHGMSmETAWI0pW3XYwLEOEalsIkAMZrStusxAWIco1LYRIAYTWnb9ZgAMY5RKWwiQIymtO16TOD4K/Ifn3j89Xv4tf7xwElhMkPyuUntVddd7PZfCiHf4+fdGyN5ytXWECBGTdQWTQgQI6GltoYAMWqitmhCgBgJLbU1BIhRE7VFEwLESGiprSFAjJqoLZoQIEZCS20NAWLURG3RhMC/X5Ffcs0jGUItAhMEkusj3hgTieixjgAx1kVm4AkCxJigrMc6AsRYF5mBJwgQY4KyHusIEGNdZAaeIECMCcp6rCNAjHWRGXiCADEmKOuxjgAx1kVm4AkCxJigrMc6AsRYF5mBJwgQY4KyHusIEGNdZAaeIECMCcp6rCNAjHWRGXiCADEmKOuxjgAx1kVm4AkCxJigrMc6AsRYF5mBJwgQY4KyHusIEGNdZAaeIECMCcp6rCNAjHWRGXiCADEmKOuxjgAx1kVm4AkCxJigrMc6AsRYF5mBJwgQY4KyHusIEGNdZAaeIECMCcp6rCNAjHWRGXiCADEmKOuxjgAx1kVm4AkCxJigrMc6AsRYF5mBJwgQY4KyHusIEGNdZAaeIECMCcp6rCNAjHWRGXiCADEmKOuxjgAx1kVm4AkCxJigrMc6Ai/hxN9O679++Hhaqg6Bhwm8//KanD1+3r0xEqxqawgQoyZqiyYEiJHQUltDgBg1UVs0IUCMhJbaGgLEqInaogkBYiS01NYQIEZN1BZNCBAjoaW2hgAxaqK2aEKAGAkttTUEiFETtUUTAsRIaKmtIUCMmqgtmhAgRkJLbQ0BYtREbdGEADESWmprCBCjJmqLJgSIkdBSW0OAGDVRWzQhQIyEltoaAsd/NeEBIv6iyAPQHHn37qq//JGw9cZIaKmtIUCMmqgtmhAgRkJLbQ0BYtREbdGEADESWmprCBCjJmqLJgSIkdBSW0OAGDVRWzQhQIyEltoaAsSoidqiCYErr4QkcxxfH0k+1I/XJLTy2vDqRtLgzZ9Lb4wkLrU1BIhRE7VFEwLESGiprSFAjJqoLZoQIEZCS20NAWLURG3RhAAxElpqawgQoyZqiyYEiJHQUltDgBg1UVs0IfDmX70nwz5Qe8lVkwfmuOuR2z4/3hh3fWTt9RQBYjyFz+G7EiDGXZO111MEiPEUPofvSoAYd03WXk8RIMZT+By+KwFi3DVZez1FgBhP4XP4rgSIcddk7fUUAWI8hc/huxL4B6D7SoucxoO8AAAAAElFTkSuQmCC" }, - "execution_count": 8, + "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], - "source": [ - "path = os.path.join(\"..\", \"doc\", \"logo\", \"Tomato.png\")\n", - "image = im=Image.open(path)\n", - "image" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-03-28T11:49:24.569031Z", - "start_time": "2024-03-28T11:49:24.565509Z" - } - }, - "id": "6dfb4ca602b7491b", - "execution_count": 8 + "execution_count": 38 }, { "cell_type": "markdown", @@ -108,6 +133,40 @@ }, { "cell_type": "code", + "source": [ + "image = np.array(image.resize((18, 17), Image.NEAREST))\n", + "colors = np.unique(image.reshape((image.shape[0] * image.shape[1], image.shape[2])), axis=0)[1:]\n", + "def indices_to_complex_event(indices: np.array) -> Event:\n", + " result = Event([])\n", + " for index in indices:\n", + " event = SimpleEvent({y: closed_open(-index[0] - 1, -index[0]),\n", + " x: closed_open(index[1], index[1] + 1)})\n", + " result.simple_sets.add(event)\n", + " return result.simplify()\n", + "\n", + "fig = go.Figure()\n", + "\n", + "complex_events = []\n", + "\n", + "for color in colors:\n", + " pixel_indices = np.transpose(np.nonzero(np.all(image == color, axis=-1)))\n", + " complex_event = indices_to_complex_event(pixel_indices)\n", + " complex_events.append(complex_event)\n", + " traces = complex_event.plot(f\"rgb({color[0]},{color[1]},{color[2]})\")\n", + " fig.update_layout(complex_event.plotly_layout())\n", + " fig.add_traces(traces)\n", + "\n", + "fig.update_layout(title=\"Random Events Tomato\")\n", + "fig.show()" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-05-31T15:13:31.051541Z", + "start_time": "2024-05-31T15:13:30.502467Z" + } + }, + "id": "767c932bc1a6beb", "outputs": [ { "data": { @@ -115,7 +174,7 @@ "data": [ { "fill": "toself", - "legendgroup": "139790934077200", + "legendgroup": "140230628706096", "line": { "color": "rgb(0,0,0)" }, @@ -123,26 +182,38 @@ "name": "Event", "showlegend": true, "x": [ - 5, - 5, - 13, - 13, - 5, + 1, + 1, + 2, + 2, + 1, + null, + 1, + 1, + 2, + 2, + 1, null ], "y": [ - -17, - -16, - -16, - -17, - -17, + -14, + -12, + -12, + -14, + -14, + null, + -8, + -6, + -6, + -8, + -8, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790934077200", + "legendgroup": "140230628706096", "line": { "color": "rgb(0,0,0)" }, @@ -150,62 +221,62 @@ "name": "Event", "showlegend": false, "x": [ + 2, + 2, 3, 3, - 5, - 5, - 3, + 2, null, + 2, + 2, 3, 3, - 5, - 5, - 3, + 2, null, - 13, - 13, 15, 15, - 13, + 16, + 16, + 15, null, - 13, - 13, 15, 15, - 13, + 16, + 16, + 15, null ], "y": [ - -16, + -15, + -14, + -14, -15, -15, - -16, - -16, null, - -5, - -4, - -4, + -6, -5, -5, + -6, + -6, null, - -16, + -15, + -14, + -14, -15, -15, - -16, - -16, null, - -5, - -4, - -4, + -6, -5, -5, + -6, + -6, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790934077200", + "legendgroup": "140230628706096", "line": { "color": "rgb(0,0,0)" }, @@ -213,38 +284,26 @@ "name": "Event", "showlegend": false, "x": [ - 2, - 2, - 3, - 3, - 2, - null, - 15, - 15, - 16, - 16, - 15, + 5, + 5, + 13, + 13, + 5, null ], "y": [ - -15, - -14, - -14, - -15, - -15, - null, - -15, - -14, - -14, - -15, - -15, + -17, + -16, + -16, + -17, + -17, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790934077200", + "legendgroup": "140230628706096", "line": { "color": "rgb(0,0,0)" }, @@ -252,38 +311,38 @@ "name": "Event", "showlegend": false, "x": [ + 0, + 0, 1, 1, - 2, - 2, - 1, + 0, null, - 16, - 16, 17, 17, - 16, + 18, + 18, + 17, null ], "y": [ - -14, + -12, + -8, + -8, -12, -12, - -14, - -14, null, - -14, + -12, + -8, + -8, -12, -12, - -14, - -14, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790934077200", + "legendgroup": "140230628706096", "line": { "color": "rgb(0,0,0)" }, @@ -291,38 +350,26 @@ "name": "Event", "showlegend": false, "x": [ - 0, - 0, - 1, - 1, - 0, - null, - 17, - 17, - 18, - 18, - 17, + 3, + 3, + 4, + 4, + 3, null ], "y": [ - -12, - -8, -8, - -12, - -12, - null, - -12, + -4, + -4, -8, -8, - -12, - -12, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790934077200", + "legendgroup": "140230628706096", "line": { "color": "rgb(0,0,0)" }, @@ -330,44 +377,71 @@ "name": "Event", "showlegend": false, "x": [ - 1, - 1, - 2, - 2, - 1, - null, 3, 3, 5, 5, 3, null, - 8, - 8, - 10, - 10, - 8, - null, 13, 13, 15, 15, 13, - null, - 16, - 16, - 17, - 17, - 16, null ], "y": [ - -8, - -7, - -7, - -8, - -8, - null, + -16, + -15, + -15, + -16, + -16, + null, + -16, + -15, + -15, + -16, + -16, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628706096", + "line": { + "color": "rgb(0,0,0)" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 4, + 4, + 5, + 5, + 4, + null, + 8, + 8, + 10, + 10, + 8, + null, + 13, + 13, + 15, + 15, + 13, + null, + 16, + 16, + 17, + 17, + 16, + null + ], + "y": [ -8, -7, -7, @@ -397,7 +471,7 @@ }, { "fill": "toself", - "legendgroup": "139790934077200", + "legendgroup": "140230628706096", "line": { "color": "rgb(0,0,0)" }, @@ -405,18 +479,45 @@ "name": "Event", "showlegend": false, "x": [ - 1, - 1, - 2, - 2, - 1, - null, - 3, - 3, 4, 4, - 3, + 5, + 5, + 4, + null, + 13, + 13, + 15, + 15, + 13, + null + ], + "y": [ + -5, + -4, + -4, + -5, + -5, null, + -5, + -4, + -4, + -5, + -5, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628706096", + "line": { + "color": "rgb(0,0,0)" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ 5, 5, 6, @@ -490,25 +591,52 @@ -6, -7, -7, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628706096", + "line": { + "color": "rgb(0,0,0)" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 5, + 5, + 8, + 8, + 5, null, - -7, - -6, - -6, - -7, - -7, + 10, + 10, + 13, + 13, + 10, + null + ], + "y": [ + -4, + -3, + -3, + -4, + -4, null, - -7, - -6, - -6, - -7, - -7, + -4, + -3, + -3, + -4, + -4, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790934077200", + "legendgroup": "140230628706096", "line": { "color": "rgb(0,0,0)" }, @@ -516,12 +644,45 @@ "name": "Event", "showlegend": false, "x": [ - 2, - 2, - 4, - 4, - 2, + 6, + 6, + 7, + 7, + 6, + null, + 9, + 9, + 10, + 10, + 9, + null + ], + "y": [ + -2, + -1, + -1, + -2, + -2, null, + -2, + -1, + -1, + -2, + -2, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628706096", + "line": { + "color": "rgb(0,0,0)" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ 6, 6, 7, @@ -536,8 +697,8 @@ null, 14, 14, - 16, - 16, + 15, + 15, 14, null ], @@ -559,58 +720,13 @@ -5, -6, -6, - null, - -6, - -5, - -5, - -6, - -6, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790934077200", - "line": { - "color": "rgb(0,0,0)" - }, - "mode": "lines", - "name": "Event", - "showlegend": false, - "x": [ - 5, - 5, - 8, - 8, - 5, - null, - 10, - 10, - 13, - 13, - 10, - null - ], - "y": [ - -4, - -3, - -3, - -4, - -4, - null, - -4, - -3, - -3, - -4, - -4, - null - ], - "type": "scatter" - }, - { - "fill": "toself", - "legendgroup": "139790934077200", + "legendgroup": "140230628706096", "line": { "color": "rgb(0,0,0)" }, @@ -649,7 +765,7 @@ }, { "fill": "toself", - "legendgroup": "139790934077200", + "legendgroup": "140230628706096", "line": { "color": "rgb(0,0,0)" }, @@ -657,38 +773,26 @@ "name": "Event", "showlegend": false, "x": [ - 6, - 6, 7, 7, - 6, - null, 9, 9, - 10, - 10, - 9, + 7, null ], "y": [ - -2, - -1, -1, - -2, - -2, - null, - -2, + 0, + 0, -1, -1, - -2, - -2, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790934077200", + "legendgroup": "140230628706096", "line": { "color": "rgb(0,0,0)" }, @@ -696,26 +800,26 @@ "name": "Event", "showlegend": false, "x": [ - 7, - 7, - 9, - 9, - 7, - null - ], - "y": [ - -1, - 0, - 0, - -1, - -1, + 16, + 16, + 17, + 17, + 16, + null + ], + "y": [ + -14, + -12, + -12, + -14, + -14, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790930816832", + "legendgroup": "140230628941584", "line": { "color": "rgb(124,176,118)" }, @@ -766,7 +870,7 @@ }, { "fill": "toself", - "legendgroup": "139790930816832", + "legendgroup": "140230628941584", "line": { "color": "rgb(124,176,118)" }, @@ -817,7 +921,7 @@ }, { "fill": "toself", - "legendgroup": "139790930816832", + "legendgroup": "140230628941584", "line": { "color": "rgb(124,176,118)" }, @@ -844,7 +948,7 @@ }, { "fill": "toself", - "legendgroup": "139790930816832", + "legendgroup": "140230628941584", "line": { "color": "rgb(124,176,118)" }, @@ -852,26 +956,26 @@ "name": "Event", "showlegend": false, "x": [ - 8, - 8, - 10, - 10, - 8, + 7, + 7, + 9, + 9, + 7, null ], "y": [ - -4, + -2, + -1, + -1, -2, -2, - -4, - -4, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790930816832", + "legendgroup": "140230628941584", "line": { "color": "rgb(124,176,118)" }, @@ -879,26 +983,26 @@ "name": "Event", "showlegend": false, "x": [ - 7, - 7, - 9, - 9, - 7, + 8, + 8, + 10, + 10, + 8, null ], "y": [ - -2, - -1, - -1, + -4, -2, -2, + -4, + -4, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790930904208", + "legendgroup": "140230629946272", "line": { "color": "rgb(236,26,27)" }, @@ -906,26 +1010,38 @@ "name": "Event", "showlegend": true, "x": [ - 5, - 5, - 13, - 13, - 5, + 3, + 3, + 4, + 4, + 3, + null, + 3, + 3, + 4, + 4, + 3, null ], "y": [ - -16, + -15, + -14, + -14, -15, -15, - -16, - -16, + null, + -13, + -9, + -9, + -13, + -13, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790930904208", + "legendgroup": "140230629946272", "line": { "color": "rgb(236,26,27)" }, @@ -933,26 +1049,50 @@ "name": "Event", "showlegend": false, "x": [ - 3, - 3, - 15, - 15, - 3, + 2, + 2, + 4, + 4, + 2, + null, + 5, + 5, + 6, + 6, + 5, + null, + 7, + 7, + 16, + 16, + 7, null ], "y": [ - -15, + -14, + -13, + -13, + -14, + -14, + null, + -14, + -13, + -13, + -14, + -14, + null, + -14, + -13, + -13, -14, -14, - -15, - -15, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790930904208", + "legendgroup": "140230629946272", "line": { "color": "rgb(236,26,27)" }, @@ -960,26 +1100,38 @@ "name": "Event", "showlegend": false, "x": [ - 2, - 2, - 16, - 16, - 2, + 5, + 5, + 7, + 7, + 5, + null, + 10, + 10, + 11, + 11, + 10, null ], "y": [ + -16, -14, - -12, - -12, + -14, + -16, + -16, + null, + -16, -14, -14, + -16, + -16, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790930904208", + "legendgroup": "140230629946272", "line": { "color": "rgb(236,26,27)" }, @@ -989,15 +1141,39 @@ "x": [ 1, 1, + 2, + 2, + 1, + null, + 7, + 7, + 10, + 10, + 7, + null, + 11, + 11, 17, 17, - 1, + 11, null ], "y": [ -12, - -8, - -8, + -11, + -11, + -12, + -12, + null, + -12, + -11, + -11, + -12, + -12, + null, + -12, + -11, + -11, -12, -12, null @@ -1006,7 +1182,7 @@ }, { "fill": "toself", - "legendgroup": "139790930904208", + "legendgroup": "140230629946272", "line": { "color": "rgb(236,26,27)" }, @@ -1014,62 +1190,50 @@ "name": "Event", "showlegend": false, "x": [ - 2, - 2, 3, 3, - 2, + 4, + 4, + 3, null, 5, 5, - 8, - 8, + 6, + 6, 5, null, - 10, - 10, - 13, - 13, - 10, - null, - 15, - 15, - 16, - 16, - 15, + 7, + 7, + 17, + 17, + 7, null ], "y": [ - -8, - -7, - -7, - -8, - -8, - null, - -8, - -7, - -7, + -9, -8, -8, + -9, + -9, null, - -8, - -7, - -7, + -9, -8, -8, + -9, + -9, null, - -8, - -7, - -7, + -9, -8, -8, + -9, + -9, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790930904208", + "legendgroup": "140230629946272", "line": { "color": "rgb(236,26,27)" }, @@ -1077,62 +1241,482 @@ "name": "Event", "showlegend": false, "x": [ - 2, - 2, - 3, - 3, - 2, - null, - 6, - 6, 7, 7, - 6, + 10, + 10, + 7, null, 11, 11, - 12, - 12, + 13, + 13, 11, - null, - 15, - 15, - 16, - 16, - 15, null ], "y": [ - -7, - -6, - -6, - -7, - -7, - null, - -7, - -6, - -6, - -7, - -7, - null, - -7, - -6, - -6, - -7, - -7, + -16, + -15, + -15, + -16, + -16, null, - -7, - -6, - -6, - -7, - -7, + -16, + -15, + -15, + -16, + -16, null ], "type": "scatter" - } - ], - "layout": { - "template": { + }, + { + "fill": "toself", + "legendgroup": "140230629946272", + "line": { + "color": "rgb(236,26,27)" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 7, + 7, + 10, + 10, + 7, + null, + 11, + 11, + 15, + 15, + 11, + null + ], + "y": [ + -15, + -14, + -14, + -15, + -15, + null, + -15, + -14, + -14, + -15, + -15, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230629946272", + "line": { + "color": "rgb(236,26,27)" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 4, + 4, + 5, + 5, + 4, + null + ], + "y": [ + -15, + -8, + -8, + -15, + -15, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230629946272", + "line": { + "color": "rgb(236,26,27)" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 6, + 6, + 7, + 7, + 6, + null + ], + "y": [ + -14, + -8, + -8, + -14, + -14, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230629946272", + "line": { + "color": "rgb(236,26,27)" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 5, + 5, + 6, + 6, + 5, + null, + 7, + 7, + 16, + 16, + 7, + null + ], + "y": [ + -13, + -12, + -12, + -13, + -13, + null, + -13, + -12, + -12, + -13, + -13, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230629946272", + "line": { + "color": "rgb(236,26,27)" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 2, + 2, + 3, + 3, + 2, + null + ], + "y": [ + -13, + -7, + -7, + -13, + -13, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230629946272", + "line": { + "color": "rgb(236,26,27)" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 7, + 7, + 10, + 10, + 7, + null, + 11, + 11, + 17, + 17, + 11, + null + ], + "y": [ + -11, + -10, + -10, + -11, + -11, + null, + -11, + -10, + -10, + -11, + -11, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230629946272", + "line": { + "color": "rgb(236,26,27)" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 10, + 10, + 11, + 11, + 10, + null, + 10, + 10, + 11, + 11, + 10, + null + ], + "y": [ + -12, + -10, + -10, + -12, + -12, + null, + -8, + -7, + -7, + -8, + -8, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230629946272", + "line": { + "color": "rgb(236,26,27)" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 1, + 1, + 2, + 2, + 1, + null + ], + "y": [ + -11, + -8, + -8, + -11, + -11, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230629946272", + "line": { + "color": "rgb(236,26,27)" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 2, + 2, + 3, + 3, + 2, + null, + 6, + 6, + 7, + 7, + 6, + null, + 11, + 11, + 12, + 12, + 11, + null, + 15, + 15, + 16, + 16, + 15, + null + ], + "y": [ + -7, + -6, + -6, + -7, + -7, + null, + -7, + -6, + -6, + -7, + -7, + null, + -7, + -6, + -6, + -7, + -7, + null, + -7, + -6, + -6, + -7, + -7, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230629946272", + "line": { + "color": "rgb(236,26,27)" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 5, + 5, + 6, + 6, + 5, + null, + 5, + 5, + 6, + 6, + 5, + null + ], + "y": [ + -12, + -9, + -9, + -12, + -12, + null, + -8, + -7, + -7, + -8, + -8, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230629946272", + "line": { + "color": "rgb(236,26,27)" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 6, + 6, + 8, + 8, + 6, + null, + 11, + 11, + 13, + 13, + 11, + null, + 15, + 15, + 16, + 16, + 15, + null + ], + "y": [ + -8, + -7, + -7, + -8, + -8, + null, + -8, + -7, + -7, + -8, + -8, + null, + -8, + -7, + -7, + -8, + -8, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230629946272", + "line": { + "color": "rgb(236,26,27)" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 7, + 7, + 17, + 17, + 7, + null + ], + "y": [ + -10, + -9, + -9, + -10, + -10, + null + ], + "type": "scatter" + } + ], + "layout": { + "template": { "data": { "histogram2dcontour": [ { @@ -1957,115 +2541,870 @@ } } }, - "xaxis": { - "title": { - "text": "x" - } + "xaxis": { + "title": { + "text": "x" + } + }, + "yaxis": { + "title": { + "text": "y" + } + }, + "title": { + "text": "Random Events Tomato" + } + }, + "config": { + "plotlyServerURL": "https://plot.ly" + } + }, + "text/html": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "execution_count": 39 + }, + { + "cell_type": "markdown", + "source": [ + "While the shape of a tomato as an event that can be used for probabilistic reasoning serves no particular research, it showcases that random events can take approximately any shape and not \"just\" rectangles.\n", + "Unions of complex events of any shape can also performed to get the tomato as an entire event and not a union of three different events." + ], + "metadata": { + "collapsed": false + }, + "id": "5bdcd00ab2fac7cf" + }, + { + "cell_type": "code", + "source": [ + "entire_event = complex_events[0] | complex_events[1] | complex_events[2]\n", + "fig = go.Figure(entire_event.plot(), entire_event.plotly_layout())\n", + "fig.update_layout(title=\"Random Events Tomato as one Event\")\n", + "fig.show()" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-05-31T15:13:31.307406Z", + "start_time": "2024-05-31T15:13:31.052252Z" + } + }, + "id": "ce38e8a948d2a0d5", + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "data": [ + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": true, + "x": [ + 2, + 2, + 4, + 4, + 2, + null, + 5, + 5, + 6, + 6, + 5, + null, + 7, + 7, + 16, + 16, + 7, + null + ], + "y": [ + -14, + -13, + -13, + -14, + -14, + null, + -14, + -13, + -13, + -14, + -14, + null, + -14, + -13, + -13, + -14, + -14, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 5, + 5, + 13, + 13, + 5, + null, + 5, + 5, + 13, + 13, + 5, + null + ], + "y": [ + -17, + -16, + -16, + -17, + -17, + null, + -5, + -4, + -4, + -5, + -5, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 3, + 3, + 5, + 5, + 3, + null, + 7, + 7, + 10, + 10, + 7, + null, + 11, + 11, + 15, + 15, + 11, + null + ], + "y": [ + -16, + -15, + -15, + -16, + -16, + null, + -16, + -15, + -15, + -16, + -16, + null, + -16, + -15, + -15, + -16, + -16, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 2, + 2, + 3, + 3, + 2, + null, + 2, + 2, + 3, + 3, + 2, + null, + 15, + 15, + 16, + 16, + 15, + null, + 15, + 15, + 16, + 16, + 15, + null + ], + "y": [ + -15, + -14, + -14, + -15, + -15, + null, + -6, + -5, + -5, + -6, + -6, + null, + -15, + -14, + -14, + -15, + -15, + null, + -6, + -5, + -5, + -6, + -6, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 5, + 5, + 7, + 7, + 5, + null, + 10, + 10, + 11, + 11, + 10, + null + ], + "y": [ + -16, + -14, + -14, + -16, + -16, + null, + -16, + -14, + -14, + -16, + -16, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 7, + 7, + 10, + 10, + 7, + null, + 11, + 11, + 15, + 15, + 11, + null + ], + "y": [ + -15, + -14, + -14, + -15, + -15, + null, + -15, + -14, + -14, + -15, + -15, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 3, + 3, + 4, + 4, + 3, + null, + 3, + 3, + 4, + 4, + 3, + null, + 3, + 3, + 4, + 4, + 3, + null + ], + "y": [ + -15, + -14, + -14, + -15, + -15, + null, + -13, + -9, + -9, + -13, + -13, + null, + -8, + -4, + -4, + -8, + -8, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 1, + 1, + 2, + 2, + 1, + null, + 1, + 1, + 2, + 2, + 1, + null + ], + "y": [ + -14, + -12, + -12, + -14, + -14, + null, + -11, + -6, + -6, + -11, + -11, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 6, + 6, + 7, + 7, + 6, + null + ], + "y": [ + -14, + -8, + -8, + -14, + -14, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 1, + 1, + 2, + 2, + 1, + null, + 7, + 7, + 10, + 10, + 7, + null, + 11, + 11, + 17, + 17, + 11, + null + ], + "y": [ + -12, + -11, + -11, + -12, + -12, + null, + -12, + -11, + -11, + -12, + -12, + null, + -12, + -11, + -11, + -12, + -12, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 0, + 0, + 1, + 1, + 0, + null, + 17, + 17, + 18, + 18, + 17, + null + ], + "y": [ + -12, + -8, + -8, + -12, + -12, + null, + -12, + -8, + -8, + -12, + -12, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 7, + 7, + 10, + 10, + 7, + null, + 11, + 11, + 17, + 17, + 11, + null + ], + "y": [ + -11, + -10, + -10, + -11, + -11, + null, + -11, + -10, + -10, + -11, + -11, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 7, + 7, + 17, + 17, + 7, + null + ], + "y": [ + -10, + -9, + -9, + -10, + -10, + null + ], + "type": "scatter" }, - "yaxis": { - "title": { - "text": "y" - } + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 3, + 3, + 4, + 4, + 3, + null, + 5, + 5, + 6, + 6, + 5, + null, + 7, + 7, + 17, + 17, + 7, + null + ], + "y": [ + -9, + -8, + -8, + -9, + -9, + null, + -9, + -8, + -8, + -9, + -9, + null, + -9, + -8, + -8, + -9, + -9, + null + ], + "type": "scatter" }, - "title": { - "text": "Random Events Tomato" - } - }, - "config": { - "plotlyServerURL": "https://plot.ly" - } - }, - "text/html": "
" - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image = np.array(image.resize((18, 17), Image.NEAREST))\n", - "colors = np.unique(image.reshape((image.shape[0] * image.shape[1], image.shape[2])), axis=0)[1:]\n", - "def indices_to_complex_event(indices: np.array) -> ComplexEvent:\n", - " result = ComplexEvent([])\n", - " for index in indices:\n", - " event = Event({y: portion.closedopen(-index[0] - 1, -index[0]),\n", - " x: portion.closedopen(index[1], index[1] + 1)})\n", - " result.events.append(event)\n", - " result = result.simplify()\n", - " return result.simplify()\n", - "\n", - "fig = go.Figure()\n", - "\n", - "complex_events = []\n", - "\n", - "for color in colors:\n", - " pixel_indices = np.transpose(np.nonzero(np.all(image == color, axis=-1)))\n", - " complex_event = indices_to_complex_event(pixel_indices)\n", - " complex_events.append(complex_event)\n", - " traces = complex_event.plot(f\"rgb({color[0]},{color[1]},{color[2]})\")\n", - " fig.update_layout(complex_event.plotly_layout())\n", - " fig.add_traces(traces)\n", - "\n", - "fig.update_layout(title=\"Random Events Tomato\")\n", - "fig.show()" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-03-28T11:49:24.657999Z", - "start_time": "2024-03-28T11:49:24.588202Z" - } - }, - "id": "767c932bc1a6beb", - "execution_count": 9 - }, - { - "cell_type": "markdown", - "source": [ - "While the shape of a tomato as an event that can be used for probabilistic reasoning serves no particular research, it showcases that random events can take approximately any shape and not \"just\" rectangles.\n", - "Unions of complex events of any shape can also performed to get the tomato as an entire event and not a union of three different events." - ], - "metadata": { - "collapsed": false - }, - "id": "5bdcd00ab2fac7cf" - }, - { - "cell_type": "code", - "outputs": [ - { - "data": { - "application/vnd.plotly.v1+json": { - "data": [ { "fill": "toself", - "legendgroup": "139790930873264", + "legendgroup": "140230628047792", "line": { "color": "#636EFA" }, "mode": "lines", "name": "Event", - "showlegend": true, + "showlegend": false, "x": [ - 1, - 1, + 2, + 2, + 3, + 3, + 2, + null, + 4, + 4, 17, 17, - 1, + 4, + null + ], + "y": [ + -7, + -6, + -6, + -7, + -7, + null, + -7, + -6, + -6, + -7, + -7, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 4, + 4, + 5, + 5, + 4, + null + ], + "y": [ + -15, + -8, + -8, + -15, + -15, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 4, + 4, + 5, + 5, + 4, + null, + 13, + 13, + 15, + 15, + 13, + null + ], + "y": [ + -5, + -4, + -4, + -5, + -5, + null, + -5, + -4, + -4, + -5, + -5, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 4, + 4, + 15, + 15, + 4, + null + ], + "y": [ + -6, + -5, + -5, + -6, + -6, + null + ], + "type": "scatter" + }, + { + "fill": "toself", + "legendgroup": "140230628047792", + "line": { + "color": "#636EFA" + }, + "mode": "lines", + "name": "Event", + "showlegend": false, + "x": [ + 5, + 5, + 6, + 6, + 5, + null, + 7, + 7, + 16, + 16, + 7, null ], "y": [ + -13, -12, - -6, - -6, + -12, + -13, + -13, + null, + -13, -12, -12, + -13, + -13, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790930873264", + "legendgroup": "140230628047792", "line": { "color": "#636EFA" }, @@ -2073,38 +3412,26 @@ "name": "Event", "showlegend": false, "x": [ - 2, - 2, - 16, 16, - 2, - null, - 2, - 2, 16, + 17, + 17, 16, - 2, null ], "y": [ - -15, + -14, -12, -12, - -15, - -15, - null, - -6, - -5, - -5, - -6, - -6, + -14, + -14, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790930873264", + "legendgroup": "140230628047792", "line": { "color": "#636EFA" }, @@ -2112,38 +3439,26 @@ "name": "Event", "showlegend": false, "x": [ - 5, - 5, - 13, - 13, - 5, - null, - 5, - 5, - 13, - 13, - 5, + 2, + 2, + 3, + 3, + 2, null ], "y": [ - -17, - -15, - -15, - -17, - -17, - null, - -5, - -4, - -4, - -5, - -5, + -13, + -7, + -7, + -13, + -13, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790930873264", + "legendgroup": "140230628047792", "line": { "color": "#636EFA" }, @@ -2151,26 +3466,38 @@ "name": "Event", "showlegend": false, "x": [ - 6, - 6, + 7, + 7, + 8, + 8, + 7, + null, 10, 10, - 6, + 11, + 11, + 10, null ], "y": [ + -3, -2, - -1, - -1, + -2, + -3, + -3, + null, + -3, -2, -2, + -3, + -3, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790930873264", + "legendgroup": "140230628047792", "line": { "color": "#636EFA" }, @@ -2178,62 +3505,38 @@ "name": "Event", "showlegend": false, "x": [ - 3, - 3, - 5, - 5, - 3, - null, - 3, - 3, - 5, - 5, - 3, - null, - 13, - 13, - 15, - 15, - 13, + 10, + 10, + 11, + 11, + 10, null, - 13, - 13, - 15, - 15, - 13, + 10, + 10, + 11, + 11, + 10, null ], "y": [ - -16, - -15, - -15, - -16, - -16, - null, - -5, - -4, - -4, - -5, - -5, - null, - -16, - -15, - -15, - -16, - -16, + -12, + -10, + -10, + -12, + -12, null, - -5, - -4, - -4, - -5, - -5, + -8, + -7, + -7, + -8, + -8, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790930873264", + "legendgroup": "140230628047792", "line": { "color": "#636EFA" }, @@ -2241,38 +3544,50 @@ "name": "Event", "showlegend": false, "x": [ - 1, - 1, - 2, - 2, - 1, + 4, + 4, + 5, + 5, + 4, null, - 16, - 16, + 6, + 6, + 10, + 10, + 6, + null, + 11, + 11, 17, 17, - 16, + 11, null ], "y": [ - -14, - -12, - -12, - -14, - -14, + -8, + -7, + -7, + -8, + -8, null, - -14, - -12, - -12, - -14, - -14, + -8, + -7, + -7, + -8, + -8, + null, + -8, + -7, + -7, + -8, + -8, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790930873264", + "legendgroup": "140230628047792", "line": { "color": "#636EFA" }, @@ -2280,38 +3595,38 @@ "name": "Event", "showlegend": false, "x": [ - 0, - 0, - 1, - 1, - 0, + 5, + 5, + 6, + 6, + 5, null, - 17, - 17, - 18, - 18, - 17, + 5, + 5, + 6, + 6, + 5, null ], "y": [ -12, - -8, - -8, + -9, + -9, -12, -12, null, - -12, + -8, + -7, + -7, -8, -8, - -12, - -12, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790930873264", + "legendgroup": "140230628047792", "line": { "color": "#636EFA" }, @@ -2350,7 +3665,7 @@ }, { "fill": "toself", - "legendgroup": "139790930873264", + "legendgroup": "140230628047792", "line": { "color": "#636EFA" }, @@ -2358,38 +3673,26 @@ "name": "Event", "showlegend": false, "x": [ - 7, - 7, - 8, - 8, - 7, - null, - 10, + 6, + 6, 10, - 11, - 11, 10, + 6, null ], "y": [ - -3, - -2, -2, - -3, - -3, - null, - -3, + -1, + -1, -2, -2, - -3, - -3, null ], "type": "scatter" }, { "fill": "toself", - "legendgroup": "139790930873264", + "legendgroup": "140230628047792", "line": { "color": "#636EFA" }, @@ -2416,7 +3719,7 @@ }, { "fill": "toself", - "legendgroup": "139790930873264", + "legendgroup": "140230628047792", "line": { "color": "#636EFA" }, @@ -3286,27 +4589,39 @@ "plotlyServerURL": "https://plot.ly" } }, - "text/html": "
" + "text/html": [ + "
" + ] }, "metadata": {}, "output_type": "display_data" } ], - "source": [ - "entire_event = complex_events[0] | complex_events[1] | complex_events[2]\n", - "fig = go.Figure(entire_event.plot(), entire_event.plotly_layout())\n", - "fig.update_layout(title=\"Random Events Tomato as one Event\")\n", - "fig.show()" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-03-28T11:49:24.709114Z", - "start_time": "2024-03-28T11:49:24.659193Z" - } - }, - "id": "ce38e8a948d2a0d5", - "execution_count": 10 + "execution_count": 40 }, { "cell_type": "markdown", diff --git a/examples/product_spaces.ipynb b/examples/product_spaces.ipynb index d49c010..9afb160 100644 --- a/examples/product_spaces.ipynb +++ b/examples/product_spaces.ipynb @@ -40,25 +40,55 @@ }, { "cell_type": "code", - "execution_count": 45, "id": "initial_id", "metadata": { "collapsed": true, "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.166262Z", - "start_time": "2024-04-02T10:44:50.128762Z" + "end_time": "2024-05-31T15:18:36.476482Z", + "start_time": "2024-05-31T15:18:36.314378Z" } }, "source": [ - "from random_events.variables import Symbolic, Continuous, Integer\n", - "from random_events.events import Event, ComplexEvent\n", - "import portion\n", + "from random_events.variable import Symbolic, Continuous, Integer\n", + "from random_events.product_algebra import Event, SimpleEvent\n", + "from random_events.interval import *\n", "import plotly\n", "plotly.offline.init_notebook_mode()\n", "import plotly.graph_objects as go\n", "from itertools import chain, combinations, product" ], - "outputs": [] + "outputs": [ + { + "data": { + "text/html": [ + " \n", + " " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "execution_count": 1 }, { "cell_type": "markdown", @@ -100,13 +130,31 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.247398Z", - "start_time": "2024-04-02T10:44:50.243668Z" + "end_time": "2024-05-31T15:18:36.482098Z", + "start_time": "2024-05-31T15:18:36.477214Z" } }, "id": "efd225f025a25755", - "execution_count": 46, - "outputs": [] + "outputs": [ + { + "data": { + "text/plain": [ + "[set(),\n", + " {'c'},\n", + " {'b'},\n", + " {'a'},\n", + " {'b', 'c'},\n", + " {'a', 'c'},\n", + " {'a', 'b'},\n", + " {'a', 'b', 'c'}]" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 2 }, { "cell_type": "markdown", @@ -124,15 +172,22 @@ "E in powerset_of_E" ], "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.255879Z", - "start_time": "2024-04-02T10:44:50.251974Z" - } + "collapsed": false }, "id": "4718cfb47e7aabf5", - "execution_count": 47, - "outputs": [] + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 3 }, { "cell_type": "markdown", @@ -152,15 +207,11 @@ " print(f\"Set difference {A - B} not in powerset\")" ], "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.274492Z", - "start_time": "2024-04-02T10:44:50.271606Z" - } + "collapsed": false }, "id": "dc64275c217072e", - "execution_count": 48, - "outputs": [] + "outputs": [], + "execution_count": 4 }, { "cell_type": "markdown", @@ -182,15 +233,11 @@ " print(f\"Intersection {A.intersection(B)} not in powerset\")" ], "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.313439Z", - "start_time": "2024-04-02T10:44:50.309989Z" - } + "collapsed": false }, "id": "e7dc354bb8a70a12", - "execution_count": 49, - "outputs": [] + "outputs": [], + "execution_count": 5 }, { "cell_type": "markdown", @@ -208,7 +255,6 @@ }, { "cell_type": "code", - "execution_count": 50, "source": [ "item = Symbolic(\"item\", [\"bowl\", \"cup\", \"spoon\"])\n", "color = Symbolic(\"color\", [\"blue\", \"green\", \"red\"])\n", @@ -216,14 +262,20 @@ "print(color)" ], "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.343095Z", - "start_time": "2024-04-02T10:44:50.340246Z" - } + "collapsed": false }, "id": "27ea010bc8892833", - "outputs": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Symbolic(item, ['bowl', 'cup', 'spoon'])\n", + "Symbolic(color, ['blue', 'green', 'red'])\n" + ] + } + ], + "execution_count": 6 }, { "cell_type": "markdown", @@ -272,15 +324,30 @@ "list(product_E)" ], "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.396625Z", - "start_time": "2024-04-02T10:44:50.392533Z" - } + "collapsed": false }, "id": "379cef1a50307c47", - "execution_count": 51, - "outputs": [] + "outputs": [ + { + "data": { + "text/plain": [ + "[('bowl', 'blue'),\n", + " ('bowl', 'green'),\n", + " ('bowl', 'red'),\n", + " ('cup', 'blue'),\n", + " ('cup', 'green'),\n", + " ('cup', 'red'),\n", + " ('spoon', 'blue'),\n", + " ('spoon', 'green'),\n", + " ('spoon', 'red')]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 7 }, { "cell_type": "markdown", @@ -302,13 +369,29 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.425878Z", - "start_time": "2024-04-02T10:44:50.423043Z" + "end_time": "2024-05-31T15:18:36.669838Z", + "start_time": "2024-05-31T15:18:36.511232Z" } }, "id": "a53e718226f00339", - "execution_count": 52, - "outputs": [] + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'Symbolic' object has no attribute 'variables'", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mAttributeError\u001B[0m Traceback (most recent call last)", + "Cell \u001B[0;32mIn[8], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m event \u001B[38;5;241m=\u001B[39m \u001B[43mEvent\u001B[49m\u001B[43m(\u001B[49m\u001B[43m{\u001B[49m\u001B[43mitem\u001B[49m\u001B[43m:\u001B[49m\u001B[43m \u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mbowl\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mcup\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mcolor\u001B[49m\u001B[43m:\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mblue\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m}\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 2\u001B[0m \u001B[38;5;28mlist\u001B[39m(product(\u001B[38;5;241m*\u001B[39mevent\u001B[38;5;241m.\u001B[39mvalues()))\n", + "File \u001B[0;32m~/random-events/src/random_events/product_algebra.py:267\u001B[0m, in \u001B[0;36mEvent.__init__\u001B[0;34m(self, simple_sets)\u001B[0m\n\u001B[1;32m 265\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m__init__\u001B[39m(\u001B[38;5;28mself\u001B[39m, simple_sets: Iterable[SimpleEvent]):\n\u001B[1;32m 266\u001B[0m \u001B[38;5;28msuper\u001B[39m()\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__init__\u001B[39m(simple_sets)\n\u001B[0;32m--> 267\u001B[0m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mfill_missing_variables\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n", + "File \u001B[0;32m~/random-events/src/random_events/product_algebra.py:278\u001B[0m, in \u001B[0;36mEvent.fill_missing_variables\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 274\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mfill_missing_variables\u001B[39m(\u001B[38;5;28mself\u001B[39m):\n\u001B[1;32m 275\u001B[0m \u001B[38;5;250m \u001B[39m\u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[1;32m 276\u001B[0m \u001B[38;5;124;03m Fill all simple sets with the missing variables.\u001B[39;00m\n\u001B[1;32m 277\u001B[0m \u001B[38;5;124;03m \"\"\"\u001B[39;00m\n\u001B[0;32m--> 278\u001B[0m all_variables \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mall_variables\u001B[49m\n\u001B[1;32m 279\u001B[0m \u001B[38;5;28;01mfor\u001B[39;00m simple_set \u001B[38;5;129;01min\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39msimple_sets:\n\u001B[1;32m 280\u001B[0m simple_set\u001B[38;5;241m.\u001B[39mfill_missing_variables(all_variables)\n", + "File \u001B[0;32m~/random-events/src/random_events/product_algebra.py:272\u001B[0m, in \u001B[0;36mEvent.all_variables\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 269\u001B[0m \u001B[38;5;129m@property\u001B[39m\n\u001B[1;32m 270\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mall_variables\u001B[39m(\u001B[38;5;28mself\u001B[39m) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m SortedSet[Variable]:\n\u001B[1;32m 271\u001B[0m result \u001B[38;5;241m=\u001B[39m SortedSet()\n\u001B[0;32m--> 272\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m result\u001B[38;5;241m.\u001B[39munion(\u001B[38;5;241m*\u001B[39m[SortedSet(simple_set\u001B[38;5;241m.\u001B[39mvariables) \u001B[38;5;28;01mfor\u001B[39;00m simple_set \u001B[38;5;129;01min\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39msimple_sets])\n", + "File \u001B[0;32m~/random-events/src/random_events/product_algebra.py:272\u001B[0m, in \u001B[0;36m\u001B[0;34m(.0)\u001B[0m\n\u001B[1;32m 269\u001B[0m \u001B[38;5;129m@property\u001B[39m\n\u001B[1;32m 270\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mall_variables\u001B[39m(\u001B[38;5;28mself\u001B[39m) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m SortedSet[Variable]:\n\u001B[1;32m 271\u001B[0m result \u001B[38;5;241m=\u001B[39m SortedSet()\n\u001B[0;32m--> 272\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m result\u001B[38;5;241m.\u001B[39munion(\u001B[38;5;241m*\u001B[39m[SortedSet(\u001B[43msimple_set\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mvariables\u001B[49m) \u001B[38;5;28;01mfor\u001B[39;00m simple_set \u001B[38;5;129;01min\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39msimple_sets])\n", + "\u001B[0;31mAttributeError\u001B[0m: 'Symbolic' object has no attribute 'variables'" + ] + } + ], + "execution_count": 8 }, { "cell_type": "markdown", @@ -327,15 +410,11 @@ "event2 = Event({item: \"cup\", color: \"red\"})" ], "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.488740Z", - "start_time": "2024-04-02T10:44:50.486218Z" - } + "collapsed": false }, "id": "1bb140fb470e3cf7", - "execution_count": 53, - "outputs": [] + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -354,15 +433,11 @@ "event_union" ], "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.509623Z", - "start_time": "2024-04-02T10:44:50.506634Z" - } + "collapsed": false }, "id": "b74c89bfbed07d6f", - "execution_count": 54, - "outputs": [] + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -381,15 +456,11 @@ "str(real_event_union)" ], "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.541399Z", - "start_time": "2024-04-02T10:44:50.538604Z" - } + "collapsed": false }, "id": "7fd789bf96187ca1", - "execution_count": 55, - "outputs": [] + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -427,7 +498,6 @@ }, { "cell_type": "code", - "execution_count": 56, "source": [ "x = Continuous(\"x\")\n", "y = Continuous(\"y\")\n", @@ -438,14 +508,11 @@ "fig.show()" ], "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.548967Z", - "start_time": "2024-04-02T10:44:50.542689Z" - } + "collapsed": false }, "id": "a86b223360f60725", - "outputs": [] + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -462,20 +529,16 @@ }, { "cell_type": "code", - "execution_count": 57, "source": [ "complex_event = Event({x: portion.closed(2, 3) | portion.closed(4, 5) | portion.closed(6,7), y: portion.closed(10, 15) | portion.closed(25, 27)})\n", "complex_event" ], "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.565328Z", - "start_time": "2024-04-02T10:44:50.561779Z" - } + "collapsed": false }, "id": "86d42ecd896bef10", - "outputs": [] + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -489,21 +552,17 @@ }, { "cell_type": "code", - "execution_count": 58, "source": [ "fig = go.Figure(complex_event.plot(), complex_event.plotly_layout())\n", "fig.update_layout(title= \"Complex event in 2D\")\n", "fig.show()" ], "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.618704Z", - "start_time": "2024-04-02T10:44:50.611069Z" - } + "collapsed": false }, "id": "7d81de549d20f02b", - "outputs": [] + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -517,7 +576,6 @@ }, { "cell_type": "code", - "execution_count": 59, "source": [ "# extend previous event by 3rd dimension\n", "z = Continuous(\"z\")\n", @@ -528,14 +586,11 @@ "fig.show()" ], "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.641933Z", - "start_time": "2024-04-02T10:44:50.631387Z" - } + "collapsed": false }, "id": "da2b51a986fa9d05", - "outputs": [] + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -570,15 +625,11 @@ "fig.show()" ], "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.745436Z", - "start_time": "2024-04-02T10:44:50.737858Z" - } + "collapsed": false }, "id": "97f6f80a61c8abaf", - "execution_count": 60, - "outputs": [] + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -613,15 +664,11 @@ "fig.show()" ], "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.763941Z", - "start_time": "2024-04-02T10:44:50.746465Z" - } + "collapsed": false }, "id": "9e47b2f884e4c9dd", - "execution_count": 61, - "outputs": [] + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -641,15 +688,11 @@ "fig.show()" ], "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.774002Z", - "start_time": "2024-04-02T10:44:50.765035Z" - } + "collapsed": false }, "id": "a4ef759878e21dd5", - "execution_count": 62, - "outputs": [] + "outputs": [], + "execution_count": null }, { "metadata": {}, @@ -681,16 +724,8 @@ " (A \\times B)^c &= (A^c \\times B) \\cup (A \\times B^c) \\cup (A^c \\times B^c) \\\\\n", " &= (A^c \\times B) \\cup (A^c \\times B^c) \\cup (A \\times B^c) \\\\\n", " &= ( A^c \\times (B \\cup B^c) ) \\cup (A \\times B^c) \\\\\n", - " &= (A^c \\times \\mathbb{B}) \\cup (A \\times B^C) \\qquad \\square\n", + " &= (A^c \\times \\mathbb{B}) \\cup (A \\times B^C) \\square\n", "\\end{align*}\n", - "\n" - ], - "id": "511cdcad45f76bab" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ "\n", "### Induction Step\n", "\n", @@ -699,17 +734,17 @@ "\\end{align*}\n", "Proof:\n", "\\begin{align*}\n", - " (A \\times B \\times C)^c &= (A \\times B^c \\times C) \\cup (A \\times B \\times C^c) \\cup (A \\times B^c \\times C^c)\\\\\n", - " & \\cup \\, (A^c \\times B \\times C)\\cup(A^c \\times B^c \\times C) \\cup (A^c \\times B \\times C^c) \\cup (A^c \\times B^c \\times C^c) \\\\ \n", - " &= (A \\times \\underbrace{((B^c \\times C) \\cup (B \\times C^c) \\cup (B^c \\times C^c))}_{\\text{Induction Assumption}} \\\\\n", - " &\\cup \\, (A^c \\times \\underbrace{((B \\times C)\\cup(B^c \\times C) \\cup (B \\times C^c) \\cup (B^c \\times C^c))}_{\\mathbb{B} \\times \\mathbb{C}}) \\\\\n", - " &= (A \\times (B^c \\times \\mathbb{C}) \\cup (B \\times C^C)) \\cup (A^c \\times \\mathbb{B} \\times \\mathbb{C}) \\\\\n", - " &= (A^c \\times \\mathbb{B} \\times \\mathbb{C}) \\cup (A \\times B^C \\times \\mathbb{C} ) \\cup (A \\times B \\times C^c) \\qquad \\square\n", - "\\end{align*}\n", - "\n", - "Furthermore, take notice that the complement $(A \\times B \\times C)^c$ as expressed in this proof is a disjoint union." + " (A \\times B \\times C)^c &= (A^c \\times B \\times C) \\cup (A \\times B^c \\times C) \\cup (A \\times B \\times C^c) \\cup \n", + " (A^c \\times B^c \\times C) \\cup (A^c \\times B \\times C^c) \\cup (A \\times B^c \\times C^c) \\cup \n", + " (A^c \\times B^c \\times C^c) \\\\\n", + " &= (C \\times \\underbrace{(A^c \\times B) \\cup (A \\times B^c) \\cup (A^c \\times B^c))}_{\\text{Induction Assumption}} \\cup\n", + " (C^c \\times \\underbrace{(A^c \\times B) \\cup (A \\times B^c) \\cup (A^c \\times B^c))}_{\\text{Induction Assumption}} \\cup (A \\times B \\times C^c) \\\\\n", + " &= (C \\times (A^c \\times \\mathbb{B}) \\cup (A \\times B^C)) \\cup \n", + " (C^c \\times (A^c \\times \\mathbb{B}) \\cup (A \\times B^C)) \\cup (A \\times B \\times C^c)\\\\\n", + " &= \n", + "\\end{align*}\n" ], - "id": "4ca5ba06adf3eb6a" + "id": "511cdcad45f76bab" }, { "cell_type": "markdown", @@ -740,15 +775,11 @@ "fig.show()" ], "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.810916Z", - "start_time": "2024-04-02T10:44:50.798397Z" - } + "collapsed": false }, "id": "b8916038b2521a38", - "execution_count": 63, - "outputs": [] + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -768,15 +799,11 @@ "fig.show()" ], "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-04-02T10:44:50.844515Z", - "start_time": "2024-04-02T10:44:50.834676Z" - } + "collapsed": false }, "id": "510b80164a41cfc", - "execution_count": 64, - "outputs": [] + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", diff --git a/examples/self_assessment.ipynb b/examples/self_assessment.ipynb index 807be39..02e410f 100644 --- a/examples/self_assessment.ipynb +++ b/examples/self_assessment.ipynb @@ -14,32 +14,54 @@ }, { "cell_type": "code", - "execution_count": 1, "id": "initial_id", "metadata": { - "ExecuteTime": { - "end_time": "2024-04-02T10:02:21.588488Z", - "start_time": "2024-04-02T10:02:21.581395Z" - }, "editable": true, "slideshow": { "slide_type": "" }, "tags": [ "remove-input" - ] + ], + "ExecuteTime": { + "end_time": "2024-05-31T15:18:01.350347Z", + "start_time": "2024-05-31T15:18:01.343336Z" + } }, + "source": [ + "from jupyterquiz import display_quiz\n", + "\n", + "q1 = {\n", + " \"question\": \"Which shapes can be represented using the product sigma algebra?\",\n", + " \"type\": \"many_choice\",\n", + " \"answers\": [{\"answer\": \"Triangles\", \"correct\": False},\n", + " {\"answer\": \"Squares\", \"correct\": True},\n", + " {\"answer\": \"Circles\", \"correct\": False},\n", + " {\"answer\": \"Rectangles\", \"correct\": True},\n", + " {\"answer\": \"Cubes\", \"correct\": True},\n", + " {\"answer\": \"Lines\", \"correct\": True},\n", + " {\"answer\": \"Trapezoids\", \"correct\": False},\n", + " {\"answer\": \"Parallelograms\", \"correct\": False},\n", + " {\"answer\": \"Pyramids\", \"correct\": False},\n", + " {\"answer\": \"Hyper-Rectangles\", \"correct\": True},\n", + " ]\n", + "}\n", + "display_quiz([q1])" + ], "outputs": [ { "data": { + "text/plain": [ + "" + ], "text/html": [ - "
" - ], - "text/plain": [ - "" ] }, "metadata": {}, @@ -220,801 +258,16 @@ }, { "data": { - "application/javascript": [ - "var questionsfOkJVCInIPRm=[{\"question\": \"Which shapes can be represented using the sigma algebra?\", \"type\": \"many_choice\", \"answers\": [{\"answer\": \"Triangles\", \"correct\": false}, {\"answer\": \"Squares\", \"correct\": true}, {\"answer\": \"Circles\", \"correct\": false}, {\"answer\": \"Rectangles\", \"correct\": true}, {\"answer\": \"Cubes\", \"correct\": true}, {\"answer\": \"Lines\", \"correct\": true}, {\"answer\": \"Trapezoids\", \"correct\": false}, {\"answer\": \"Parallelograms\", \"correct\": false}, {\"answer\": \"Pyramids\", \"correct\": false}, {\"answer\": \"Hyper-Rectangles\", \"correct\": true}]}];\n", - " // Make a random ID\n", - "function makeid(length) {\n", - " var result = [];\n", - " var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';\n", - " var charactersLength = characters.length;\n", - " for (var i = 0; i < length; i++) {\n", - " result.push(characters.charAt(Math.floor(Math.random() * charactersLength)));\n", - " }\n", - " return result.join('');\n", - "}\n", - "\n", - "// Choose a random subset of an array. Can also be used to shuffle the array\n", - "function getRandomSubarray(arr, size) {\n", - " var shuffled = arr.slice(0), i = arr.length, temp, index;\n", - " while (i--) {\n", - " index = Math.floor((i + 1) * Math.random());\n", - " temp = shuffled[index];\n", - " shuffled[index] = shuffled[i];\n", - " shuffled[i] = temp;\n", - " }\n", - " return shuffled.slice(0, size);\n", - "}\n", - "\n", - "function printResponses(responsesContainer) {\n", - " var responses=JSON.parse(responsesContainer.dataset.responses);\n", - " var stringResponses='IMPORTANT!To preserve this answer sequence for submission, when you have finalized your answers:
  1. Copy the text in this cell below \"Answer String\"
  2. Double click on the cell directly below the Answer String, labeled \"Replace Me\"
  3. Select the whole \"Replace Me\" text
  4. Paste in your answer string and press shift-Enter.
  5. Save the notebook using the save icon or File->Save Notebook menu item



  6. Answer String:
    ';\n", - " console.log(responses);\n", - " responses.forEach((response, index) => {\n", - " if (response) {\n", - " console.log(index + ': ' + response);\n", - " stringResponses+= index + ': ' + response +\"
    \";\n", - " }\n", - " });\n", - " responsesContainer.innerHTML=stringResponses;\n", - "}\n", - "function check_mc() {\n", - " var id = this.id.split('-')[0];\n", - " //var response = this.id.split('-')[1];\n", - " //console.log(response);\n", - " //console.log(\"In check_mc(), id=\"+id);\n", - " //console.log(event.srcElement.id) \n", - " //console.log(event.srcElement.dataset.correct) \n", - " //console.log(event.srcElement.dataset.feedback)\n", - "\n", - " var label = event.srcElement;\n", - " //console.log(label, label.nodeName);\n", - " var depth = 0;\n", - " while ((label.nodeName != \"LABEL\") && (depth < 20)) {\n", - " label = label.parentElement;\n", - " console.log(depth, label);\n", - " depth++;\n", - " }\n", - "\n", - "\n", - "\n", - " var answers = label.parentElement.children;\n", - "\n", - " //console.log(answers);\n", - "\n", - "\n", - " // Split behavior based on multiple choice vs many choice:\n", - " var fb = document.getElementById(\"fb\" + id);\n", - "\n", - "\n", - "\n", - "\n", - " if (fb.dataset.numcorrect == 1) {\n", - " // What follows is for the saved responses stuff\n", - " var outerContainer = fb.parentElement.parentElement;\n", - " var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n", - " if (responsesContainer) {\n", - " //console.log(responsesContainer);\n", - " var response = label.firstChild.innerText;\n", - " if (label.querySelector(\".QuizCode\")){\n", - " response+= label.querySelector(\".QuizCode\").firstChild.innerText;\n", - " }\n", - " console.log(response);\n", - " //console.log(document.getElementById(\"quizWrap\"+id));\n", - " var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n", - " console.log(\"Question \" + qnum);\n", - " //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n", - " var responses=JSON.parse(responsesContainer.dataset.responses);\n", - " console.log(responses);\n", - " responses[qnum]= response;\n", - " responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n", - " printResponses(responsesContainer);\n", - " }\n", - " // End code to preserve responses\n", - " \n", - " for (var i = 0; i < answers.length; i++) {\n", - " var child = answers[i];\n", - " //console.log(child);\n", - " child.className = \"MCButton\";\n", - " }\n", - "\n", - "\n", - "\n", - " if (label.dataset.correct == \"true\") {\n", - " // console.log(\"Correct action\");\n", - " if (\"feedback\" in label.dataset) {\n", - " fb.textContent = jaxify(label.dataset.feedback);\n", - " } else {\n", - " fb.textContent = \"Correct!\";\n", - " }\n", - " label.classList.add(\"correctButton\");\n", - "\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"correct\");\n", - "\n", - " } else {\n", - " if (\"feedback\" in label.dataset) {\n", - " fb.textContent = jaxify(label.dataset.feedback);\n", - " } else {\n", - " fb.textContent = \"Incorrect -- try again.\";\n", - " }\n", - " //console.log(\"Error action\");\n", - " label.classList.add(\"incorrectButton\");\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"incorrect\");\n", - " }\n", - " }\n", - " else {\n", - " var reset = false;\n", - " var feedback;\n", - " if (label.dataset.correct == \"true\") {\n", - " if (\"feedback\" in label.dataset) {\n", - " feedback = jaxify(label.dataset.feedback);\n", - " } else {\n", - " feedback = \"Correct!\";\n", - " }\n", - " if (label.dataset.answered <= 0) {\n", - " if (fb.dataset.answeredcorrect < 0) {\n", - " fb.dataset.answeredcorrect = 1;\n", - " reset = true;\n", - " } else {\n", - " fb.dataset.answeredcorrect++;\n", - " }\n", - " if (reset) {\n", - " for (var i = 0; i < answers.length; i++) {\n", - " var child = answers[i];\n", - " child.className = \"MCButton\";\n", - " child.dataset.answered = 0;\n", - " }\n", - " }\n", - " label.classList.add(\"correctButton\");\n", - " label.dataset.answered = 1;\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"correct\");\n", - "\n", - " }\n", - " } else {\n", - " if (\"feedback\" in label.dataset) {\n", - " feedback = jaxify(label.dataset.feedback);\n", - " } else {\n", - " feedback = \"Incorrect -- try again.\";\n", - " }\n", - " if (fb.dataset.answeredcorrect > 0) {\n", - " fb.dataset.answeredcorrect = -1;\n", - " reset = true;\n", - " } else {\n", - " fb.dataset.answeredcorrect--;\n", - " }\n", - "\n", - " if (reset) {\n", - " for (var i = 0; i < answers.length; i++) {\n", - " var child = answers[i];\n", - " child.className = \"MCButton\";\n", - " child.dataset.answered = 0;\n", - " }\n", - " }\n", - " label.classList.add(\"incorrectButton\");\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"incorrect\");\n", - " }\n", - " // What follows is for the saved responses stuff\n", - " var outerContainer = fb.parentElement.parentElement;\n", - " var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n", - " if (responsesContainer) {\n", - " //console.log(responsesContainer);\n", - " var response = label.firstChild.innerText;\n", - " if (label.querySelector(\".QuizCode\")){\n", - " response+= label.querySelector(\".QuizCode\").firstChild.innerText;\n", - " }\n", - " console.log(response);\n", - " //console.log(document.getElementById(\"quizWrap\"+id));\n", - " var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n", - " console.log(\"Question \" + qnum);\n", - " //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n", - " var responses=JSON.parse(responsesContainer.dataset.responses);\n", - " if (label.dataset.correct == \"true\") {\n", - " if (typeof(responses[qnum]) == \"object\"){\n", - " if (!responses[qnum].includes(response))\n", - " responses[qnum].push(response);\n", - " } else{\n", - " responses[qnum]= [ response ];\n", - " }\n", - " } else {\n", - " responses[qnum]= response;\n", - " }\n", - " console.log(responses);\n", - " responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n", - " printResponses(responsesContainer);\n", - " }\n", - " // End save responses stuff\n", - "\n", - "\n", - "\n", - " var numcorrect = fb.dataset.numcorrect;\n", - " var answeredcorrect = fb.dataset.answeredcorrect;\n", - " if (answeredcorrect >= 0) {\n", - " fb.textContent = feedback + \" [\" + answeredcorrect + \"/\" + numcorrect + \"]\";\n", - " } else {\n", - " fb.textContent = feedback + \" [\" + 0 + \"/\" + numcorrect + \"]\";\n", - " }\n", - "\n", - "\n", - " }\n", - "\n", - " if (typeof MathJax != 'undefined') {\n", - " var version = MathJax.version;\n", - " console.log('MathJax version', version);\n", - " if (version[0] == \"2\") {\n", - " MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n", - " } else if (version[0] == \"3\") {\n", - " MathJax.typeset([fb]);\n", - " }\n", - " } else {\n", - " console.log('MathJax not detected');\n", - " }\n", - "\n", - "}\n", - "\n", - "function make_mc(qa, shuffle_answers, outerqDiv, qDiv, aDiv, id) {\n", - " var shuffled;\n", - " if (shuffle_answers == \"True\") {\n", - " //console.log(shuffle_answers+\" read as true\");\n", - " shuffled = getRandomSubarray(qa.answers, qa.answers.length);\n", - " } else {\n", - " //console.log(shuffle_answers+\" read as false\");\n", - " shuffled = qa.answers;\n", - " }\n", - "\n", - "\n", - " var num_correct = 0;\n", - "\n", - "\n", - "\n", - " shuffled.forEach((item, index, ans_array) => {\n", - " //console.log(answer);\n", - "\n", - " // Make input element\n", - " var inp = document.createElement(\"input\");\n", - " inp.type = \"radio\";\n", - " inp.id = \"quizo\" + id + index;\n", - " inp.style = \"display:none;\";\n", - " aDiv.append(inp);\n", - "\n", - " //Make label for input element\n", - " var lab = document.createElement(\"label\");\n", - " lab.className = \"MCButton\";\n", - " lab.id = id + '-' + index;\n", - " lab.onclick = check_mc;\n", - " var aSpan = document.createElement('span');\n", - " aSpan.classsName = \"\";\n", - " //qDiv.id=\"quizQn\"+id+index;\n", - " if (\"answer\" in item) {\n", - " aSpan.innerHTML = jaxify(item.answer);\n", - " //aSpan.innerHTML=item.answer;\n", - " }\n", - " lab.append(aSpan);\n", - "\n", - " // Create div for code inside question\n", - " var codeSpan;\n", - " if (\"code\" in item) {\n", - " codeSpan = document.createElement('span');\n", - " codeSpan.id = \"code\" + id + index;\n", - " codeSpan.className = \"QuizCode\";\n", - " var codePre = document.createElement('pre');\n", - " codeSpan.append(codePre);\n", - " var codeCode = document.createElement('code');\n", - " codePre.append(codeCode);\n", - " codeCode.innerHTML = item.code;\n", - " lab.append(codeSpan);\n", - " //console.log(codeSpan);\n", - " }\n", - "\n", - " //lab.textContent=item.answer;\n", - "\n", - " // Set the data attributes for the answer\n", - " lab.setAttribute('data-correct', item.correct);\n", - " if (item.correct) {\n", - " num_correct++;\n", - " }\n", - " if (\"feedback\" in item) {\n", - " lab.setAttribute('data-feedback', item.feedback);\n", - " }\n", - " lab.setAttribute('data-answered', 0);\n", - "\n", - " aDiv.append(lab);\n", - "\n", - " });\n", - "\n", - " if (num_correct > 1) {\n", - " outerqDiv.className = \"ManyChoiceQn\";\n", - " } else {\n", - " outerqDiv.className = \"MultipleChoiceQn\";\n", - " }\n", - "\n", - " return num_correct;\n", - "\n", - "}\n", - "function check_numeric(ths, event) {\n", - "\n", - " if (event.keyCode === 13) {\n", - " ths.blur();\n", - "\n", - " var id = ths.id.split('-')[0];\n", - "\n", - " var submission = ths.value;\n", - " if (submission.indexOf('/') != -1) {\n", - " var sub_parts = submission.split('/');\n", - " //console.log(sub_parts);\n", - " submission = sub_parts[0] / sub_parts[1];\n", - " }\n", - " //console.log(\"Reader entered\", submission);\n", - "\n", - " if (\"precision\" in ths.dataset) {\n", - " var precision = ths.dataset.precision;\n", - " // console.log(\"1:\", submission)\n", - " submission = Math.round((1 * submission + Number.EPSILON) * 10 ** precision) / 10 ** precision;\n", - " // console.log(\"Rounded to \", submission, \" precision=\", precision );\n", - " }\n", - "\n", - "\n", - " //console.log(\"In check_numeric(), id=\"+id);\n", - " //console.log(event.srcElement.id) \n", - " //console.log(event.srcElement.dataset.feedback)\n", - "\n", - " var fb = document.getElementById(\"fb\" + id);\n", - " fb.style.display = \"none\";\n", - " fb.textContent = \"Incorrect -- try again.\";\n", - "\n", - " var answers = JSON.parse(ths.dataset.answers);\n", - " //console.log(answers);\n", - "\n", - " var defaultFB = \"\";\n", - " var correct;\n", - " var done = false;\n", - " answers.every(answer => {\n", - " //console.log(answer.type);\n", - "\n", - " correct = false;\n", - " // if (answer.type==\"value\"){\n", - " if ('value' in answer) {\n", - " if (submission == answer.value) {\n", - " if (\"feedback\" in answer) {\n", - " fb.textContent = jaxify(answer.feedback);\n", - " } else {\n", - " fb.textContent = jaxify(\"Correct\");\n", - " }\n", - " correct = answer.correct;\n", - " //console.log(answer.correct);\n", - " done = true;\n", - " }\n", - " // } else if (answer.type==\"range\") {\n", - " } else if ('range' in answer) {\n", - " //console.log(answer.range);\n", - " if ((submission >= answer.range[0]) && (submission < answer.range[1])) {\n", - " fb.textContent = jaxify(answer.feedback);\n", - " correct = answer.correct;\n", - " //console.log(answer.correct);\n", - " done = true;\n", - " }\n", - " } else if (answer.type == \"default\") {\n", - " defaultFB = answer.feedback;\n", - " }\n", - " if (done) {\n", - " return false; // Break out of loop if this has been marked correct\n", - " } else {\n", - " return true; // Keep looking for case that includes this as a correct answer\n", - " }\n", - " });\n", - "\n", - " if ((!done) && (defaultFB != \"\")) {\n", - " fb.innerHTML = jaxify(defaultFB);\n", - " //console.log(\"Default feedback\", defaultFB);\n", - " }\n", - "\n", - " fb.style.display = \"block\";\n", - " if (correct) {\n", - " ths.className = \"Input-text\";\n", - " ths.classList.add(\"correctButton\");\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"correct\");\n", - " } else {\n", - " ths.className = \"Input-text\";\n", - " ths.classList.add(\"incorrectButton\");\n", - " fb.className = \"Feedback\";\n", - " fb.classList.add(\"incorrect\");\n", - " }\n", - "\n", - " // What follows is for the saved responses stuff\n", - " var outerContainer = fb.parentElement.parentElement;\n", - " var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n", - " if (responsesContainer) {\n", - " console.log(submission);\n", - " var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n", - " //console.log(\"Question \" + qnum);\n", - " //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n", - " var responses=JSON.parse(responsesContainer.dataset.responses);\n", - " console.log(responses);\n", - " if (submission == ths.value){\n", - " responses[qnum]= submission;\n", - " } else {\n", - " responses[qnum]= ths.value + \"(\" + submission +\")\";\n", - " }\n", - " responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n", - " printResponses(responsesContainer);\n", - " }\n", - " // End code to preserve responses\n", - "\n", - " if (typeof MathJax != 'undefined') {\n", - " var version = MathJax.version;\n", - " console.log('MathJax version', version);\n", - " if (version[0] == \"2\") {\n", - " MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n", - " } else if (version[0] == \"3\") {\n", - " MathJax.typeset([fb]);\n", - " }\n", - " } else {\n", - " console.log('MathJax not detected');\n", - " }\n", - " return false;\n", - " }\n", - "\n", - "}\n", - "\n", - "function isValid(el, charC) {\n", - " //console.log(\"Input char: \", charC);\n", - " if (charC == 46) {\n", - " if (el.value.indexOf('.') === -1) {\n", - " return true;\n", - " } else if (el.value.indexOf('/') != -1) {\n", - " var parts = el.value.split('/');\n", - " if (parts[1].indexOf('.') === -1) {\n", - " return true;\n", - " }\n", - " }\n", - " else {\n", - " return false;\n", - " }\n", - " } else if (charC == 47) {\n", - " if (el.value.indexOf('/') === -1) {\n", - " if ((el.value != \"\") && (el.value != \".\")) {\n", - " return true;\n", - " } else {\n", - " return false;\n", - " }\n", - " } else {\n", - " return false;\n", - " }\n", - " } else if (charC == 45) {\n", - " var edex = el.value.indexOf('e');\n", - " if (edex == -1) {\n", - " edex = el.value.indexOf('E');\n", - " }\n", - "\n", - " if (el.value == \"\") {\n", - " return true;\n", - " } else if (edex == (el.value.length - 1)) { // If just after e or E\n", - " return true;\n", - " } else {\n", - " return false;\n", - " }\n", - " } else if (charC == 101) { // \"e\"\n", - " if ((el.value.indexOf('e') === -1) && (el.value.indexOf('E') === -1) && (el.value.indexOf('/') == -1)) {\n", - " // Prev symbol must be digit or decimal point:\n", - " if (el.value.slice(-1).search(/\\d/) >= 0) {\n", - " return true;\n", - " } else if (el.value.slice(-1).search(/\\./) >= 0) {\n", - " return true;\n", - " } else {\n", - " return false;\n", - " }\n", - " } else {\n", - " return false;\n", - " }\n", - " } else {\n", - " if (charC > 31 && (charC < 48 || charC > 57))\n", - " return false;\n", - " }\n", - " return true;\n", - "}\n", - "\n", - "function numeric_keypress(evnt) {\n", - " var charC = (evnt.which) ? evnt.which : evnt.keyCode;\n", - "\n", - " if (charC == 13) {\n", - " check_numeric(this, evnt);\n", - " } else {\n", - " return isValid(this, charC);\n", - " }\n", - "}\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "function make_numeric(qa, outerqDiv, qDiv, aDiv, id) {\n", - "\n", - "\n", - "\n", - " //console.log(answer);\n", - "\n", - "\n", - " outerqDiv.className = \"NumericQn\";\n", - " aDiv.style.display = 'block';\n", - "\n", - " var lab = document.createElement(\"label\");\n", - " lab.className = \"InpLabel\";\n", - " lab.textContent = \"Type numeric answer here:\";\n", - " aDiv.append(lab);\n", - "\n", - " var inp = document.createElement(\"input\");\n", - " inp.type = \"text\";\n", - " //inp.id=\"input-\"+id;\n", - " inp.id = id + \"-0\";\n", - " inp.className = \"Input-text\";\n", - " inp.setAttribute('data-answers', JSON.stringify(qa.answers));\n", - " if (\"precision\" in qa) {\n", - " inp.setAttribute('data-precision', qa.precision);\n", - " }\n", - " aDiv.append(inp);\n", - " //console.log(inp);\n", - "\n", - " //inp.addEventListener(\"keypress\", check_numeric);\n", - " //inp.addEventListener(\"keypress\", numeric_keypress);\n", - " /*\n", - " inp.addEventListener(\"keypress\", function(event) {\n", - " return numeric_keypress(this, event);\n", - " }\n", - " );\n", - " */\n", - " //inp.onkeypress=\"return numeric_keypress(this, event)\";\n", - " inp.onkeypress = numeric_keypress;\n", - " inp.onpaste = event => false;\n", - "\n", - " inp.addEventListener(\"focus\", function (event) {\n", - " this.value = \"\";\n", - " return false;\n", - " }\n", - " );\n", - "\n", - "\n", - "}\n", - "function jaxify(string) {\n", - " var mystring = string;\n", - "\n", - " var count = 0;\n", - " var loc = mystring.search(/([^\\\\]|^)(\\$)/);\n", - "\n", - " var count2 = 0;\n", - " var loc2 = mystring.search(/([^\\\\]|^)(\\$\\$)/);\n", - "\n", - " //console.log(loc);\n", - "\n", - " while ((loc >= 0) || (loc2 >= 0)) {\n", - "\n", - " /* Have to replace all the double $$ first with current implementation */\n", - " if (loc2 >= 0) {\n", - " if (count2 % 2 == 0) {\n", - " mystring = mystring.replace(/([^\\\\]|^)(\\$\\$)/, \"$1\\\\[\");\n", - " } else {\n", - " mystring = mystring.replace(/([^\\\\]|^)(\\$\\$)/, \"$1\\\\]\");\n", - " }\n", - " count2++;\n", - " } else {\n", - " if (count % 2 == 0) {\n", - " mystring = mystring.replace(/([^\\\\]|^)(\\$)/, \"$1\\\\(\");\n", - " } else {\n", - " mystring = mystring.replace(/([^\\\\]|^)(\\$)/, \"$1\\\\)\");\n", - " }\n", - " count++;\n", - " }\n", - " loc = mystring.search(/([^\\\\]|^)(\\$)/);\n", - " loc2 = mystring.search(/([^\\\\]|^)(\\$\\$)/);\n", - " //console.log(mystring,\", loc:\",loc,\", loc2:\",loc2);\n", - " }\n", - "\n", - " //console.log(mystring);\n", - " return mystring;\n", - "}\n", - "\n", - "\n", - "function show_questions(json, mydiv) {\n", - " console.log('show_questions');\n", - " //var mydiv=document.getElementById(myid);\n", - " var shuffle_questions = mydiv.dataset.shufflequestions;\n", - " var num_questions = mydiv.dataset.numquestions;\n", - " var shuffle_answers = mydiv.dataset.shuffleanswers;\n", - " var max_width = mydiv.dataset.maxwidth;\n", - "\n", - " if (num_questions > json.length) {\n", - " num_questions = json.length;\n", - " }\n", - "\n", - " var questions;\n", - " if ((num_questions < json.length) || (shuffle_questions == \"True\")) {\n", - " //console.log(num_questions+\",\"+json.length);\n", - " questions = getRandomSubarray(json, num_questions);\n", - " } else {\n", - " questions = json;\n", - " }\n", - "\n", - " //console.log(\"SQ: \"+shuffle_questions+\", NQ: \" + num_questions + \", SA: \", shuffle_answers);\n", - "\n", - " // Iterate over questions\n", - " questions.forEach((qa, index, array) => {\n", - " //console.log(qa.question); \n", - "\n", - " var id = makeid(8);\n", - " //console.log(id);\n", - "\n", - "\n", - " // Create Div to contain question and answers\n", - " var iDiv = document.createElement('div');\n", - " //iDiv.id = 'quizWrap' + id + index;\n", - " iDiv.id = 'quizWrap' + id;\n", - " iDiv.className = 'Quiz';\n", - " iDiv.setAttribute('data-qnum', index);\n", - " iDiv.style.maxWidth =max_width+\"px\";\n", - " mydiv.appendChild(iDiv);\n", - " // iDiv.innerHTML=qa.question;\n", - " \n", - " var outerqDiv = document.createElement('div');\n", - " outerqDiv.id = \"OuterquizQn\" + id + index;\n", - " // Create div to contain question part\n", - " var qDiv = document.createElement('div');\n", - " qDiv.id = \"quizQn\" + id + index;\n", - " \n", - " if (qa.question) {\n", - " iDiv.append(outerqDiv);\n", - "\n", - " //qDiv.textContent=qa.question;\n", - " qDiv.innerHTML = jaxify(qa.question);\n", - " outerqDiv.append(qDiv);\n", - " }\n", - "\n", - " // Create div for code inside question\n", - " var codeDiv;\n", - " if (\"code\" in qa) {\n", - " codeDiv = document.createElement('div');\n", - " codeDiv.id = \"code\" + id + index;\n", - " codeDiv.className = \"QuizCode\";\n", - " var codePre = document.createElement('pre');\n", - " codeDiv.append(codePre);\n", - " var codeCode = document.createElement('code');\n", - " codePre.append(codeCode);\n", - " codeCode.innerHTML = qa.code;\n", - " outerqDiv.append(codeDiv);\n", - " //console.log(codeDiv);\n", - " }\n", - "\n", - "\n", - " // Create div to contain answer part\n", - " var aDiv = document.createElement('div');\n", - " aDiv.id = \"quizAns\" + id + index;\n", - " aDiv.className = 'Answer';\n", - " iDiv.append(aDiv);\n", - "\n", - " //console.log(qa.type);\n", - "\n", - " var num_correct;\n", - " if ((qa.type == \"multiple_choice\") || (qa.type == \"many_choice\") ) {\n", - " num_correct = make_mc(qa, shuffle_answers, outerqDiv, qDiv, aDiv, id);\n", - " if (\"answer_cols\" in qa) {\n", - " //aDiv.style.gridTemplateColumns = 'auto '.repeat(qa.answer_cols);\n", - " aDiv.style.gridTemplateColumns = 'repeat(' + qa.answer_cols + ', 1fr)';\n", - " }\n", - " } else if (qa.type == \"numeric\") {\n", - " //console.log(\"numeric\");\n", - " make_numeric(qa, outerqDiv, qDiv, aDiv, id);\n", - " }\n", - "\n", - "\n", - " //Make div for feedback\n", - " var fb = document.createElement(\"div\");\n", - " fb.id = \"fb\" + id;\n", - " //fb.style=\"font-size: 20px;text-align:center;\";\n", - " fb.className = \"Feedback\";\n", - " fb.setAttribute(\"data-answeredcorrect\", 0);\n", - " fb.setAttribute(\"data-numcorrect\", num_correct);\n", - " iDiv.append(fb);\n", - "\n", - "\n", - " });\n", - " var preserveResponses = mydiv.dataset.preserveresponses;\n", - " console.log(preserveResponses);\n", - " console.log(preserveResponses == \"true\");\n", - " if (preserveResponses == \"true\") {\n", - " console.log(preserveResponses);\n", - " // Create Div to contain record of answers\n", - " var iDiv = document.createElement('div');\n", - " iDiv.id = 'responses' + mydiv.id;\n", - " iDiv.className = 'JCResponses';\n", - " // Create a place to store responses as an empty array\n", - " iDiv.setAttribute('data-responses', '[]');\n", - "\n", - " // Dummy Text\n", - " iDiv.innerHTML=\"Select your answers and then follow the directions that will appear here.\"\n", - " //iDiv.className = 'Quiz';\n", - " mydiv.appendChild(iDiv);\n", - " }\n", - "//console.log(\"At end of show_questions\");\n", - " if (typeof MathJax != 'undefined') {\n", - " console.log(\"MathJax version\", MathJax.version);\n", - " var version = MathJax.version;\n", - " setTimeout(function(){\n", - " var version = MathJax.version;\n", - " console.log('After sleep, MathJax version', version);\n", - " if (version[0] == \"2\") {\n", - " MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n", - " } else if (version[0] == \"3\") {\n", - " MathJax.typeset([mydiv]);\n", - " }\n", - " }, 500);\n", - "if (typeof version == 'undefined') {\n", - " } else\n", - " {\n", - " if (version[0] == \"2\") {\n", - " MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n", - " } else if (version[0] == \"3\") {\n", - " MathJax.typeset([mydiv]);\n", - " } else {\n", - " console.log(\"MathJax not found\");\n", - " }\n", - " }\n", - " }\n", - " return false;\n", - "}\n", - "/* This is to handle asynchrony issues in loading Jupyter notebooks\n", - " where the quiz has been previously run. The Javascript was generally\n", - " being run before the div was added to the DOM. I tried to do this\n", - " more elegantly using Mutation Observer, but I didn't get it to work.\n", - "\n", - " Someone more knowledgeable could make this better ;-) */\n", - "\n", - " function try_show() {\n", - " if(document.getElementById(\"fOkJVCInIPRm\")) {\n", - " show_questions(questionsfOkJVCInIPRm, fOkJVCInIPRm); \n", - " } else {\n", - " setTimeout(try_show, 200);\n", - " }\n", - " };\n", - " \n", - " {\n", - " // console.log(element);\n", - "\n", - " //console.log(\"fOkJVCInIPRm\");\n", - " // console.log(document.getElementById(\"fOkJVCInIPRm\"));\n", - "\n", - " try_show();\n", - " }\n", - " " - ], "text/plain": [ "" - ] + ], + "application/javascript": "var questionsQEIDIzaSzDPr=[{\"question\": \"Which shapes can be represented using the product sigma algebra?\", \"type\": \"many_choice\", \"answers\": [{\"answer\": \"Triangles\", \"correct\": false}, {\"answer\": \"Squares\", \"correct\": true}, {\"answer\": \"Circles\", \"correct\": false}, {\"answer\": \"Rectangles\", \"correct\": true}, {\"answer\": \"Cubes\", \"correct\": true}, {\"answer\": \"Lines\", \"correct\": true}, {\"answer\": \"Trapezoids\", \"correct\": false}, {\"answer\": \"Parallelograms\", \"correct\": false}, {\"answer\": \"Pyramids\", \"correct\": false}, {\"answer\": \"Hyper-Rectangles\", \"correct\": true}]}];\n // Make a random ID\nfunction makeid(length) {\n var result = [];\n var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';\n var charactersLength = characters.length;\n for (var i = 0; i < length; i++) {\n result.push(characters.charAt(Math.floor(Math.random() * charactersLength)));\n }\n return result.join('');\n}\n\n// Choose a random subset of an array. Can also be used to shuffle the array\nfunction getRandomSubarray(arr, size) {\n var shuffled = arr.slice(0), i = arr.length, temp, index;\n while (i--) {\n index = Math.floor((i + 1) * Math.random());\n temp = shuffled[index];\n shuffled[index] = shuffled[i];\n shuffled[i] = temp;\n }\n return shuffled.slice(0, size);\n}\n\nfunction printResponses(responsesContainer) {\n var responses=JSON.parse(responsesContainer.dataset.responses);\n var stringResponses='IMPORTANT!To preserve this answer sequence for submission, when you have finalized your answers:
    1. Copy the text in this cell below \"Answer String\"
    2. Double click on the cell directly below the Answer String, labeled \"Replace Me\"
    3. Select the whole \"Replace Me\" text
    4. Paste in your answer string and press shift-Enter.
    5. Save the notebook using the save icon or File->Save Notebook menu item



    6. Answer String:
      ';\n console.log(responses);\n responses.forEach((response, index) => {\n if (response) {\n console.log(index + ': ' + response);\n stringResponses+= index + ': ' + response +\"
      \";\n }\n });\n responsesContainer.innerHTML=stringResponses;\n}\nfunction check_mc() {\n var id = this.id.split('-')[0];\n //var response = this.id.split('-')[1];\n //console.log(response);\n //console.log(\"In check_mc(), id=\"+id);\n //console.log(event.srcElement.id) \n //console.log(event.srcElement.dataset.correct) \n //console.log(event.srcElement.dataset.feedback)\n\n var label = event.srcElement;\n //console.log(label, label.nodeName);\n var depth = 0;\n while ((label.nodeName != \"LABEL\") && (depth < 20)) {\n label = label.parentElement;\n console.log(depth, label);\n depth++;\n }\n\n\n\n var answers = label.parentElement.children;\n\n //console.log(answers);\n\n\n // Split behavior based on multiple choice vs many choice:\n var fb = document.getElementById(\"fb\" + id);\n\n\n\n\n if (fb.dataset.numcorrect == 1) {\n // What follows is for the saved responses stuff\n var outerContainer = fb.parentElement.parentElement;\n var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n if (responsesContainer) {\n //console.log(responsesContainer);\n var response = label.firstChild.innerText;\n if (label.querySelector(\".QuizCode\")){\n response+= label.querySelector(\".QuizCode\").firstChild.innerText;\n }\n console.log(response);\n //console.log(document.getElementById(\"quizWrap\"+id));\n var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n console.log(\"Question \" + qnum);\n //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n var responses=JSON.parse(responsesContainer.dataset.responses);\n console.log(responses);\n responses[qnum]= response;\n responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n printResponses(responsesContainer);\n }\n // End code to preserve responses\n \n for (var i = 0; i < answers.length; i++) {\n var child = answers[i];\n //console.log(child);\n child.className = \"MCButton\";\n }\n\n\n\n if (label.dataset.correct == \"true\") {\n // console.log(\"Correct action\");\n if (\"feedback\" in label.dataset) {\n fb.textContent = jaxify(label.dataset.feedback);\n } else {\n fb.textContent = \"Correct!\";\n }\n label.classList.add(\"correctButton\");\n\n fb.className = \"Feedback\";\n fb.classList.add(\"correct\");\n\n } else {\n if (\"feedback\" in label.dataset) {\n fb.textContent = jaxify(label.dataset.feedback);\n } else {\n fb.textContent = \"Incorrect -- try again.\";\n }\n //console.log(\"Error action\");\n label.classList.add(\"incorrectButton\");\n fb.className = \"Feedback\";\n fb.classList.add(\"incorrect\");\n }\n }\n else {\n var reset = false;\n var feedback;\n if (label.dataset.correct == \"true\") {\n if (\"feedback\" in label.dataset) {\n feedback = jaxify(label.dataset.feedback);\n } else {\n feedback = \"Correct!\";\n }\n if (label.dataset.answered <= 0) {\n if (fb.dataset.answeredcorrect < 0) {\n fb.dataset.answeredcorrect = 1;\n reset = true;\n } else {\n fb.dataset.answeredcorrect++;\n }\n if (reset) {\n for (var i = 0; i < answers.length; i++) {\n var child = answers[i];\n child.className = \"MCButton\";\n child.dataset.answered = 0;\n }\n }\n label.classList.add(\"correctButton\");\n label.dataset.answered = 1;\n fb.className = \"Feedback\";\n fb.classList.add(\"correct\");\n\n }\n } else {\n if (\"feedback\" in label.dataset) {\n feedback = jaxify(label.dataset.feedback);\n } else {\n feedback = \"Incorrect -- try again.\";\n }\n if (fb.dataset.answeredcorrect > 0) {\n fb.dataset.answeredcorrect = -1;\n reset = true;\n } else {\n fb.dataset.answeredcorrect--;\n }\n\n if (reset) {\n for (var i = 0; i < answers.length; i++) {\n var child = answers[i];\n child.className = \"MCButton\";\n child.dataset.answered = 0;\n }\n }\n label.classList.add(\"incorrectButton\");\n fb.className = \"Feedback\";\n fb.classList.add(\"incorrect\");\n }\n // What follows is for the saved responses stuff\n var outerContainer = fb.parentElement.parentElement;\n var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n if (responsesContainer) {\n //console.log(responsesContainer);\n var response = label.firstChild.innerText;\n if (label.querySelector(\".QuizCode\")){\n response+= label.querySelector(\".QuizCode\").firstChild.innerText;\n }\n console.log(response);\n //console.log(document.getElementById(\"quizWrap\"+id));\n var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n console.log(\"Question \" + qnum);\n //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n var responses=JSON.parse(responsesContainer.dataset.responses);\n if (label.dataset.correct == \"true\") {\n if (typeof(responses[qnum]) == \"object\"){\n if (!responses[qnum].includes(response))\n responses[qnum].push(response);\n } else{\n responses[qnum]= [ response ];\n }\n } else {\n responses[qnum]= response;\n }\n console.log(responses);\n responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n printResponses(responsesContainer);\n }\n // End save responses stuff\n\n\n\n var numcorrect = fb.dataset.numcorrect;\n var answeredcorrect = fb.dataset.answeredcorrect;\n if (answeredcorrect >= 0) {\n fb.textContent = feedback + \" [\" + answeredcorrect + \"/\" + numcorrect + \"]\";\n } else {\n fb.textContent = feedback + \" [\" + 0 + \"/\" + numcorrect + \"]\";\n }\n\n\n }\n\n if (typeof MathJax != 'undefined') {\n var version = MathJax.version;\n console.log('MathJax version', version);\n if (version[0] == \"2\") {\n MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n } else if (version[0] == \"3\") {\n MathJax.typeset([fb]);\n }\n } else {\n console.log('MathJax not detected');\n }\n\n}\n\nfunction make_mc(qa, shuffle_answers, outerqDiv, qDiv, aDiv, id) {\n var shuffled;\n if (shuffle_answers == \"True\") {\n //console.log(shuffle_answers+\" read as true\");\n shuffled = getRandomSubarray(qa.answers, qa.answers.length);\n } else {\n //console.log(shuffle_answers+\" read as false\");\n shuffled = qa.answers;\n }\n\n\n var num_correct = 0;\n\n\n\n shuffled.forEach((item, index, ans_array) => {\n //console.log(answer);\n\n // Make input element\n var inp = document.createElement(\"input\");\n inp.type = \"radio\";\n inp.id = \"quizo\" + id + index;\n inp.style = \"display:none;\";\n aDiv.append(inp);\n\n //Make label for input element\n var lab = document.createElement(\"label\");\n lab.className = \"MCButton\";\n lab.id = id + '-' + index;\n lab.onclick = check_mc;\n var aSpan = document.createElement('span');\n aSpan.classsName = \"\";\n //qDiv.id=\"quizQn\"+id+index;\n if (\"answer\" in item) {\n aSpan.innerHTML = jaxify(item.answer);\n //aSpan.innerHTML=item.answer;\n }\n lab.append(aSpan);\n\n // Create div for code inside question\n var codeSpan;\n if (\"code\" in item) {\n codeSpan = document.createElement('span');\n codeSpan.id = \"code\" + id + index;\n codeSpan.className = \"QuizCode\";\n var codePre = document.createElement('pre');\n codeSpan.append(codePre);\n var codeCode = document.createElement('code');\n codePre.append(codeCode);\n codeCode.innerHTML = item.code;\n lab.append(codeSpan);\n //console.log(codeSpan);\n }\n\n //lab.textContent=item.answer;\n\n // Set the data attributes for the answer\n lab.setAttribute('data-correct', item.correct);\n if (item.correct) {\n num_correct++;\n }\n if (\"feedback\" in item) {\n lab.setAttribute('data-feedback', item.feedback);\n }\n lab.setAttribute('data-answered', 0);\n\n aDiv.append(lab);\n\n });\n\n if (num_correct > 1) {\n outerqDiv.className = \"ManyChoiceQn\";\n } else {\n outerqDiv.className = \"MultipleChoiceQn\";\n }\n\n return num_correct;\n\n}\nfunction check_numeric(ths, event) {\n\n if (event.keyCode === 13) {\n ths.blur();\n\n var id = ths.id.split('-')[0];\n\n var submission = ths.value;\n if (submission.indexOf('/') != -1) {\n var sub_parts = submission.split('/');\n //console.log(sub_parts);\n submission = sub_parts[0] / sub_parts[1];\n }\n //console.log(\"Reader entered\", submission);\n\n if (\"precision\" in ths.dataset) {\n var precision = ths.dataset.precision;\n submission = Number(Number(submission).toPrecision(precision));\n }\n\n\n //console.log(\"In check_numeric(), id=\"+id);\n //console.log(event.srcElement.id) \n //console.log(event.srcElement.dataset.feedback)\n\n var fb = document.getElementById(\"fb\" + id);\n fb.style.display = \"none\";\n fb.textContent = \"Incorrect -- try again.\";\n\n var answers = JSON.parse(ths.dataset.answers);\n //console.log(answers);\n\n var defaultFB = \"\";\n var correct;\n var done = false;\n answers.every(answer => {\n //console.log(answer.type);\n\n correct = false;\n // if (answer.type==\"value\"){\n if ('value' in answer) {\n if (submission == answer.value) {\n if (\"feedback\" in answer) {\n fb.textContent = jaxify(answer.feedback);\n } else {\n fb.textContent = jaxify(\"Correct\");\n }\n correct = answer.correct;\n //console.log(answer.correct);\n done = true;\n }\n // } else if (answer.type==\"range\") {\n } else if ('range' in answer) {\n console.log(answer.range);\n console.log(submission, submission >=answer.range[0], submission < answer.range[1])\n if ((submission >= answer.range[0]) && (submission < answer.range[1])) {\n fb.textContent = jaxify(answer.feedback);\n correct = answer.correct;\n console.log(answer.correct);\n done = true;\n }\n } else if (answer.type == \"default\") {\n defaultFB = answer.feedback;\n }\n if (done) {\n return false; // Break out of loop if this has been marked correct\n } else {\n return true; // Keep looking for case that includes this as a correct answer\n }\n });\n console.log(\"done:\", done);\n\n if ((!done) && (defaultFB != \"\")) {\n fb.innerHTML = jaxify(defaultFB);\n //console.log(\"Default feedback\", defaultFB);\n }\n\n fb.style.display = \"block\";\n if (correct) {\n ths.className = \"Input-text\";\n ths.classList.add(\"correctButton\");\n fb.className = \"Feedback\";\n fb.classList.add(\"correct\");\n } else {\n ths.className = \"Input-text\";\n ths.classList.add(\"incorrectButton\");\n fb.className = \"Feedback\";\n fb.classList.add(\"incorrect\");\n }\n\n // What follows is for the saved responses stuff\n var outerContainer = fb.parentElement.parentElement;\n var responsesContainer = document.getElementById(\"responses\" + outerContainer.id);\n if (responsesContainer) {\n console.log(submission);\n var qnum = document.getElementById(\"quizWrap\"+id).dataset.qnum;\n //console.log(\"Question \" + qnum);\n //console.log(id, \", got numcorrect=\",fb.dataset.numcorrect);\n var responses=JSON.parse(responsesContainer.dataset.responses);\n console.log(responses);\n if (submission == ths.value){\n responses[qnum]= submission;\n } else {\n responses[qnum]= ths.value + \"(\" + submission +\")\";\n }\n responsesContainer.setAttribute('data-responses', JSON.stringify(responses));\n printResponses(responsesContainer);\n }\n // End code to preserve responses\n\n if (typeof MathJax != 'undefined') {\n var version = MathJax.version;\n console.log('MathJax version', version);\n if (version[0] == \"2\") {\n MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n } else if (version[0] == \"3\") {\n MathJax.typeset([fb]);\n }\n } else {\n console.log('MathJax not detected');\n }\n return false;\n }\n\n}\n\nfunction isValid(el, charC) {\n //console.log(\"Input char: \", charC);\n if (charC == 46) {\n if (el.value.indexOf('.') === -1) {\n return true;\n } else if (el.value.indexOf('/') != -1) {\n var parts = el.value.split('/');\n if (parts[1].indexOf('.') === -1) {\n return true;\n }\n }\n else {\n return false;\n }\n } else if (charC == 47) {\n if (el.value.indexOf('/') === -1) {\n if ((el.value != \"\") && (el.value != \".\")) {\n return true;\n } else {\n return false;\n }\n } else {\n return false;\n }\n } else if (charC == 45) {\n var edex = el.value.indexOf('e');\n if (edex == -1) {\n edex = el.value.indexOf('E');\n }\n\n if (el.value == \"\") {\n return true;\n } else if (edex == (el.value.length - 1)) { // If just after e or E\n return true;\n } else {\n return false;\n }\n } else if (charC == 101) { // \"e\"\n if ((el.value.indexOf('e') === -1) && (el.value.indexOf('E') === -1) && (el.value.indexOf('/') == -1)) {\n // Prev symbol must be digit or decimal point:\n if (el.value.slice(-1).search(/\\d/) >= 0) {\n return true;\n } else if (el.value.slice(-1).search(/\\./) >= 0) {\n return true;\n } else {\n return false;\n }\n } else {\n return false;\n }\n } else {\n if (charC > 31 && (charC < 48 || charC > 57))\n return false;\n }\n return true;\n}\n\nfunction numeric_keypress(evnt) {\n var charC = (evnt.which) ? evnt.which : evnt.keyCode;\n\n if (charC == 13) {\n check_numeric(this, evnt);\n } else {\n return isValid(this, charC);\n }\n}\n\n\n\n\n\nfunction make_numeric(qa, outerqDiv, qDiv, aDiv, id) {\n\n\n\n //console.log(answer);\n\n\n outerqDiv.className = \"NumericQn\";\n aDiv.style.display = 'block';\n\n var lab = document.createElement(\"label\");\n lab.className = \"InpLabel\";\n lab.textContent = \"Type numeric answer here:\";\n aDiv.append(lab);\n\n var inp = document.createElement(\"input\");\n inp.type = \"text\";\n //inp.id=\"input-\"+id;\n inp.id = id + \"-0\";\n inp.className = \"Input-text\";\n inp.setAttribute('data-answers', JSON.stringify(qa.answers));\n if (\"precision\" in qa) {\n inp.setAttribute('data-precision', qa.precision);\n }\n aDiv.append(inp);\n //console.log(inp);\n\n //inp.addEventListener(\"keypress\", check_numeric);\n //inp.addEventListener(\"keypress\", numeric_keypress);\n /*\n inp.addEventListener(\"keypress\", function(event) {\n return numeric_keypress(this, event);\n }\n );\n */\n //inp.onkeypress=\"return numeric_keypress(this, event)\";\n inp.onkeypress = numeric_keypress;\n inp.onpaste = event => false;\n\n inp.addEventListener(\"focus\", function (event) {\n this.value = \"\";\n return false;\n }\n );\n\n\n}\nfunction jaxify(string) {\n var mystring = string;\n\n var count = 0;\n var loc = mystring.search(/([^\\\\]|^)(\\$)/);\n\n var count2 = 0;\n var loc2 = mystring.search(/([^\\\\]|^)(\\$\\$)/);\n\n //console.log(loc);\n\n while ((loc >= 0) || (loc2 >= 0)) {\n\n /* Have to replace all the double $$ first with current implementation */\n if (loc2 >= 0) {\n if (count2 % 2 == 0) {\n mystring = mystring.replace(/([^\\\\]|^)(\\$\\$)/, \"$1\\\\[\");\n } else {\n mystring = mystring.replace(/([^\\\\]|^)(\\$\\$)/, \"$1\\\\]\");\n }\n count2++;\n } else {\n if (count % 2 == 0) {\n mystring = mystring.replace(/([^\\\\]|^)(\\$)/, \"$1\\\\(\");\n } else {\n mystring = mystring.replace(/([^\\\\]|^)(\\$)/, \"$1\\\\)\");\n }\n count++;\n }\n loc = mystring.search(/([^\\\\]|^)(\\$)/);\n loc2 = mystring.search(/([^\\\\]|^)(\\$\\$)/);\n //console.log(mystring,\", loc:\",loc,\", loc2:\",loc2);\n }\n\n //console.log(mystring);\n return mystring;\n}\n\n\nfunction show_questions(json, mydiv) {\n console.log('show_questions');\n //var mydiv=document.getElementById(myid);\n var shuffle_questions = mydiv.dataset.shufflequestions;\n var num_questions = mydiv.dataset.numquestions;\n var shuffle_answers = mydiv.dataset.shuffleanswers;\n var max_width = mydiv.dataset.maxwidth;\n\n if (num_questions > json.length) {\n num_questions = json.length;\n }\n\n var questions;\n if ((num_questions < json.length) || (shuffle_questions == \"True\")) {\n //console.log(num_questions+\",\"+json.length);\n questions = getRandomSubarray(json, num_questions);\n } else {\n questions = json;\n }\n\n //console.log(\"SQ: \"+shuffle_questions+\", NQ: \" + num_questions + \", SA: \", shuffle_answers);\n\n // Iterate over questions\n questions.forEach((qa, index, array) => {\n //console.log(qa.question); \n\n var id = makeid(8);\n //console.log(id);\n\n\n // Create Div to contain question and answers\n var iDiv = document.createElement('div');\n //iDiv.id = 'quizWrap' + id + index;\n iDiv.id = 'quizWrap' + id;\n iDiv.className = 'Quiz';\n iDiv.setAttribute('data-qnum', index);\n iDiv.style.maxWidth =max_width+\"px\";\n mydiv.appendChild(iDiv);\n // iDiv.innerHTML=qa.question;\n \n var outerqDiv = document.createElement('div');\n outerqDiv.id = \"OuterquizQn\" + id + index;\n // Create div to contain question part\n var qDiv = document.createElement('div');\n qDiv.id = \"quizQn\" + id + index;\n \n if (qa.question) {\n iDiv.append(outerqDiv);\n\n //qDiv.textContent=qa.question;\n qDiv.innerHTML = jaxify(qa.question);\n outerqDiv.append(qDiv);\n }\n\n // Create div for code inside question\n var codeDiv;\n if (\"code\" in qa) {\n codeDiv = document.createElement('div');\n codeDiv.id = \"code\" + id + index;\n codeDiv.className = \"QuizCode\";\n var codePre = document.createElement('pre');\n codeDiv.append(codePre);\n var codeCode = document.createElement('code');\n codePre.append(codeCode);\n codeCode.innerHTML = qa.code;\n outerqDiv.append(codeDiv);\n //console.log(codeDiv);\n }\n\n\n // Create div to contain answer part\n var aDiv = document.createElement('div');\n aDiv.id = \"quizAns\" + id + index;\n aDiv.className = 'Answer';\n iDiv.append(aDiv);\n\n //console.log(qa.type);\n\n var num_correct;\n if ((qa.type == \"multiple_choice\") || (qa.type == \"many_choice\") ) {\n num_correct = make_mc(qa, shuffle_answers, outerqDiv, qDiv, aDiv, id);\n if (\"answer_cols\" in qa) {\n //aDiv.style.gridTemplateColumns = 'auto '.repeat(qa.answer_cols);\n aDiv.style.gridTemplateColumns = 'repeat(' + qa.answer_cols + ', 1fr)';\n }\n } else if (qa.type == \"numeric\") {\n //console.log(\"numeric\");\n make_numeric(qa, outerqDiv, qDiv, aDiv, id);\n }\n\n\n //Make div for feedback\n var fb = document.createElement(\"div\");\n fb.id = \"fb\" + id;\n //fb.style=\"font-size: 20px;text-align:center;\";\n fb.className = \"Feedback\";\n fb.setAttribute(\"data-answeredcorrect\", 0);\n fb.setAttribute(\"data-numcorrect\", num_correct);\n iDiv.append(fb);\n\n\n });\n var preserveResponses = mydiv.dataset.preserveresponses;\n console.log(preserveResponses);\n console.log(preserveResponses == \"true\");\n if (preserveResponses == \"true\") {\n console.log(preserveResponses);\n // Create Div to contain record of answers\n var iDiv = document.createElement('div');\n iDiv.id = 'responses' + mydiv.id;\n iDiv.className = 'JCResponses';\n // Create a place to store responses as an empty array\n iDiv.setAttribute('data-responses', '[]');\n\n // Dummy Text\n iDiv.innerHTML=\"Select your answers and then follow the directions that will appear here.\"\n //iDiv.className = 'Quiz';\n mydiv.appendChild(iDiv);\n }\n//console.log(\"At end of show_questions\");\n if (typeof MathJax != 'undefined') {\n console.log(\"MathJax version\", MathJax.version);\n var version = MathJax.version;\n setTimeout(function(){\n var version = MathJax.version;\n console.log('After sleep, MathJax version', version);\n if (version[0] == \"2\") {\n MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n } else if (version[0] == \"3\") {\n if (MathJax.hasOwnProperty('typeset') ) {\n MathJax.typeset([mydiv]);\n } else {\n console.log('WARNING: Trying to force load MathJax 3');\n window.MathJax = {\n tex: {\n inlineMath: [['$', '$'], ['\\\\(', '\\\\)']]\n },\n svg: {\n fontCache: 'global'\n }\n };\n\n (function () {\n var script = document.createElement('script');\n script.src = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js';\n script.async = true;\n document.head.appendChild(script);\n })();\n }\n }\n }, 500);\nif (typeof version == 'undefined') {\n } else\n {\n if (version[0] == \"2\") {\n MathJax.Hub.Queue([\"Typeset\", MathJax.Hub]);\n } else if (version[0] == \"3\") {\n if (MathJax.hasOwnProperty('typeset') ) {\n MathJax.typeset([mydiv]);\n } else {\n console.log('WARNING: Trying to force load MathJax 3');\n window.MathJax = {\n tex: {\n inlineMath: [['$', '$'], ['\\\\(', '\\\\)']]\n },\n svg: {\n fontCache: 'global'\n }\n };\n\n (function () {\n var script = document.createElement('script');\n script.src = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js';\n script.async = true;\n document.head.appendChild(script);\n })();\n }\n } else {\n console.log(\"MathJax not found\");\n }\n }\n }\n return false;\n}\n/* This is to handle asynchrony issues in loading Jupyter notebooks\n where the quiz has been previously run. The Javascript was generally\n being run before the div was added to the DOM. I tried to do this\n more elegantly using Mutation Observer, but I didn't get it to work.\n\n Someone more knowledgeable could make this better ;-) */\n\n function try_show() {\n if(document.getElementById(\"QEIDIzaSzDPr\")) {\n show_questions(questionsQEIDIzaSzDPr, QEIDIzaSzDPr); \n } else {\n setTimeout(try_show, 200);\n }\n };\n \n {\n // console.log(element);\n\n //console.log(\"QEIDIzaSzDPr\");\n // console.log(document.getElementById(\"QEIDIzaSzDPr\"));\n\n try_show();\n }\n " }, "metadata": {}, "output_type": "display_data" } ], - "source": [ - "from jupyterquiz import display_quiz\n", - "\n", - "q1 = {\n", - " \"question\": \"Which shapes can be represented using the product sigma algebra?\",\n", - " \"type\": \"many_choice\",\n", - " \"answers\": [{\"answer\": \"Triangles\", \"correct\": False},\n", - " {\"answer\": \"Squares\", \"correct\": True},\n", - " {\"answer\": \"Circles\", \"correct\": False},\n", - " {\"answer\": \"Rectangles\", \"correct\": True},\n", - " {\"answer\": \"Cubes\", \"correct\": True},\n", - " {\"answer\": \"Lines\", \"correct\": True},\n", - " {\"answer\": \"Trapezoids\", \"correct\": False},\n", - " {\"answer\": \"Parallelograms\", \"correct\": False},\n", - " {\"answer\": \"Pyramids\", \"correct\": False},\n", - " {\"answer\": \"Hyper-Rectangles\", \"correct\": True},\n", - " ]\n", - "}\n", - "display_quiz([q1])" - ] + "execution_count": 2 }, { "cell_type": "markdown", diff --git a/src/random_events/interval.py b/src/random_events/interval.py index 63479bd..0c9326c 100644 --- a/src/random_events/interval.py +++ b/src/random_events/interval.py @@ -148,6 +148,11 @@ def to_json(self) -> Dict[str, Any]: def _from_json(cls, data: Dict[str, Any]) -> Self: return cls(data['lower'], data['upper'], Bound[data['left']], Bound[data['right']]) + def center(self) -> float: + """ + :return: The center point of the interval + """ + return ((self.lower + self.upper) / 2) + self.lower class Interval(sigma_algebra.AbstractCompositeSet): @@ -188,3 +193,60 @@ def new_empty_set(self) -> Self: def complement_if_empty(self) -> Self: return Interval([SimpleInterval(float('-inf'), float('inf'), Bound.OPEN, Bound.OPEN)]) + + +def open(left: float, right: float) -> Interval: + """ + Creates an open interval. + :param left: The left bound of the interval. + :param right: The right bound of the interval. + :return: The open interval. + """ + return Interval([SimpleInterval(left, right, Bound.OPEN, Bound.OPEN)]) + + +def closed(left: float, right: float) -> Interval: + """ + Creates a closed interval. + :param left: The left bound of the interval. + :param right: The right bound of the interval. + :return: The closed interval. + """ + return Interval([SimpleInterval(left, right, Bound.CLOSED, Bound.CLOSED)]) + + +def open_closed(left: float, right: float) -> Interval: + """ + Creates an open-closed interval. + :param left: The left bound of the interval. + :param right: The right bound of the interval. + :return: The open-closed interval. + """ + return Interval([SimpleInterval(left, right, Bound.OPEN, Bound.CLOSED)]) + + +def closed_open(left: float, right: float) -> Interval: + """ + Creates a closed-open interval. + :param left: The left bound of the interval. + :param right: The right bound of the interval. + :return: The closed-open interval. + """ + return Interval([SimpleInterval(left, right, Bound.CLOSED, Bound.OPEN)]) + + +def singleton(value: float) -> Interval: + """ + Creates a singleton interval. + :param value: The value of the interval. + :return: The singleton interval. + """ + return Interval([SimpleInterval(value, value, Bound.CLOSED, Bound.CLOSED)]) + + +def reals() -> Interval: + """ + Creates the set of real numbers. + :return: The set of real numbers. + """ + return Interval([SimpleInterval(float('-inf'), float('inf'), Bound.OPEN, Bound.OPEN)]) diff --git a/src/random_events/product_algebra.py b/src/random_events/product_algebra.py index fd77c75..1795af3 100644 --- a/src/random_events/product_algebra.py +++ b/src/random_events/product_algebra.py @@ -1,8 +1,10 @@ +import numpy as np from sortedcontainers import SortedDict, SortedKeysView, SortedValuesView -from typing_extensions import Union, Any +from typing_extensions import List +import plotly.graph_objects as go -from .variable import * from .sigma_algebra import * +from .variable import * from .variable import Variable @@ -139,6 +141,115 @@ def __lt__(self, other: Self): def non_empty_to_string(self) -> str: return "{" + ", ".join(f"{variable.name} = {assignment}" for variable, assignment in self.items()) + "}" + def to_json(self) -> Dict[str, Any]: + return {**super().to_json(), + "assignments": [(variable.to_json(), assignment.to_json()) for variable, assignment in self.items()]} + + @classmethod + def _from_json(cls, data: Dict[str, Any]) -> Self: + return cls( + {Variable.from_json(variable): AbstractCompositeSet.from_json(assignment) for variable, assignment in + data["assignments"]}) + + def plot(self) -> Union[List[go.Scatter], List[go.Mesh3d]]: + """ + Plot the event. + """ + assert all(isinstance(variable, Continuous) for variable in self.keys()), \ + "Plotting is only supported for events that consist of only continuous variables." + if len(self.keys()) == 2: + return self.plot_2d() + elif len(self.keys()) == 3: + return self.plot_3d() + else: + raise NotImplementedError("Plotting is only supported for two and three dimensional events") + + def plot_2d(self) -> List[go.Scatter]: + """ + Plot the event in 2D. + """ + + # form cartesian product of all intervals + intervals = [value.simple_sets for value in self.values()] + interval_combinations = list(itertools.product(*intervals)) + + xs = [] + ys = [] + + # for every atomic interval + for interval_combination in interval_combinations: + + # plot a rectangle + points = np.asarray(list(itertools.product(*[[axis.lower, axis.upper] for axis in interval_combination]))) + y_points = points[:, 1] + y_points[len(y_points) // 2:] = y_points[len(y_points) // 2:][::-1] + xs.extend(points[:, 0].tolist() + [points[0, 0], None]) + ys.extend(y_points.tolist()+ [y_points[0], None]) + + return [go.Scatter(x=xs, y=ys, mode="lines", name="Event", fill="toself")] + + def plot_3d(self) -> List[go.Mesh3d]: + """ + Plot the event in 3D. + """ + + # form cartesian product of all intervals + intervals = [value.simple_sets for _, value in sorted(self.items())] + simple_events = list(itertools.product(*intervals)) + traces = [] + + # shortcut for the dimensions + x, y, z = 0, 1, 2 + + # for every atomic interval + for simple_event in simple_events: + + # Create a 3D mesh trace for the rectangle + traces.append(go.Mesh3d( + # 8 vertices of a cube + x=[simple_event[x].lower, simple_event[x].lower, simple_event[x].upper, simple_event[x].upper, + simple_event[x].lower, simple_event[x].lower, simple_event[x].upper, simple_event[x].upper], + y=[simple_event[y].lower, simple_event[y].upper, simple_event[y].upper, simple_event[y].lower, + simple_event[y].lower, simple_event[y].upper, simple_event[y].upper, simple_event[y].lower], + z=[simple_event[z].lower, simple_event[z].lower, simple_event[z].lower, simple_event[z].lower, + simple_event[z].upper, simple_event[z].upper, simple_event[z].upper, simple_event[z].upper], + # i, j and k give the vertices of triangles + i=[7, 0, 0, 0, 4, 4, 6, 6, 4, 0, 3, 2], + j=[3, 4, 1, 2, 5, 6, 5, 2, 0, 1, 6, 3], + k=[0, 7, 2, 3, 6, 7, 1, 1, 5, 5, 7, 6], + flatshading=True + )) + return traces + + def plotly_layout(self) -> Dict: + """ + Create a layout for the plotly plot. + """ + if len(self.variables) == 2: + result = {"xaxis_title": self.variables[0].name, + "yaxis_title": self.variables[1].name} + elif len(self.variables) == 3: + result = dict(scene=dict( + xaxis_title=self.variables[0].name, + yaxis_title=self.variables[1].name, + zaxis_title=self.variables[2].name) + ) + else: + raise NotImplementedError("Plotting is only supported for two and three dimensional events") + + return result + + def fill_missing_variables(self, variables: SortedSet[Variable]): + """ + Fill this with the variables that are not in self but in `variables`. + The variables are mapped to their domain. + + :param variables: The variables to fill the event with + """ + for variable in variables: + if variable not in self: + self[variable] = variable.domain + class Event(AbstractCompositeSet): """ @@ -151,6 +262,23 @@ class Event(AbstractCompositeSet): simple_sets: SortedSet[SimpleEvent] + def __init__(self, simple_sets: Iterable[SimpleEvent]): + super().__init__(simple_sets) + self.fill_missing_variables() + + @property + def all_variables(self) -> SortedSet[Variable]: + result = SortedSet() + return result.union(*[SortedSet(simple_set.variables) for simple_set in self.simple_sets]) + + def fill_missing_variables(self): + """ + Fill all simple sets with the missing variables. + """ + all_variables = self.all_variables + for simple_set in self.simple_sets: + simple_set.fill_missing_variables(all_variables) + def simplify(self) -> Self: simplified, changed = self.simplify_once() while changed: @@ -208,7 +336,42 @@ def simplify_once(self) -> Tuple[Self, bool]: return self, False def new_empty_set(self) -> Self: - return Event() + return Event([]) def complement_if_empty(self) -> Self: raise NotImplementedError("Complement of an empty Event is not yet supported.") + + def plot(self, color="#636EFA") -> Union[List[go.Scatter], List[go.Mesh3d]]: + """ + Plot the complex event. + + :param color: The color to use for this event + """ + traces = [] + show_legend = True + for index, event in enumerate(self.simple_sets): + event_traces = event.plot() + for event_trace in event_traces: + if len(event.keys()) == 2: + event_trace.update(name="Event", legendgroup=id(self), showlegend=show_legend, + line=dict(color=color)) + if len(event.keys()) == 3: + event_trace.update(name="Event", legendgroup=id(self), showlegend=show_legend, color=color) + show_legend = False + traces.append(event_trace) + return traces + + def plotly_layout(self) -> Dict: + """ + Create a layout for the plotly plot. + """ + return self.simple_sets[0].plotly_layout() + + def add_simple_set(self, simple_set: AbstractSimpleSet): + """ + Add a simple set to this event. + + :param simple_set: The simple set to add + """ + super().add_simple_set(simple_set) + self.fill_missing_variables() diff --git a/src/random_events/sigma_algebra.py b/src/random_events/sigma_algebra.py index 855098c..7d56fbf 100644 --- a/src/random_events/sigma_algebra.py +++ b/src/random_events/sigma_algebra.py @@ -2,8 +2,8 @@ from abc import abstractmethod from typing import Tuple, Dict, Any -from typing_extensions import Self, Set, Iterable, Optional from sortedcontainers import SortedSet +from typing_extensions import Self, Iterable, Optional from .utils import SubclassJSONSerializer @@ -84,7 +84,6 @@ def difference_with(self, other: Self) -> SortedSet[Self]: # if it intersects with this set intersection = element.intersection_with(self) if not intersection.is_empty(): - # add the intersection to the result result.add(intersection) @@ -173,8 +172,8 @@ def intersection_with_simple_sets(self, other: SortedSet[AbstractSimpleSet]) -> :return: The intersection of this set with the set of simple sets """ result = self.new_empty_set() - [result.simple_sets.update(self.intersection_with_simple_set(other_simple_set).simple_sets) - for other_simple_set in other] + [result.simple_sets.update(self.intersection_with_simple_set(other_simple_set).simple_sets) for other_simple_set + in other] return result def intersection_with(self, other: Self) -> Self: @@ -322,8 +321,8 @@ def split_into_disjoint_and_non_disjoint(self) -> Tuple[Self, Self]: This method requires: - the intersection of two simple sets as a simple set - - the difference of a simple set (A) and another simple set (B) that is completely contained in A (B ⊆ A). - The result of that difference has to be a composite set with only one simple set in it. + - the difference_of_a_with_every_b of a simple set (A) and another simple set (B) that is completely contained in A (B ⊆ A). + The result of that difference_of_a_with_every_b has to be a composite set with only one simple set in it. :return: A tuple of the disjoint and non-disjoint set. """ @@ -334,43 +333,45 @@ def split_into_disjoint_and_non_disjoint(self) -> Tuple[Self, Self]: # for every simple set (a) for simple_set_a in self.simple_sets: + simple_set_a: AbstractSimpleSet # initialize the difference of a with every b - difference = simple_set_a + difference_of_a_with_every_b: Optional[AbstractSimpleSet] = simple_set_a # for every other simple set (b) for simple_set_b in self.simple_sets: + simple_set_b: AbstractSimpleSet # skip symmetric iterations if simple_set_a == simple_set_b: continue # get the intersection of a and b - intersection = simple_set_a.intersection_with(simple_set_b) + intersection_a_b: AbstractSimpleSet = simple_set_a.intersection_with(simple_set_b) # if the intersection is not empty add it to the non-disjoint set - non_disjoint.add_simple_set(intersection) + non_disjoint.add_simple_set(intersection_a_b) # get the difference of the simple set with the intersection. - difference_with_intersection = difference.difference_with(intersection) + difference_with_intersection = difference_of_a_with_every_b.difference_with(intersection_a_b) - # if the difference is empty + # if the difference of a with every b is empty if len(difference_with_intersection) == 0: # skip the rest of the loop and mark the set for discarding - difference = None + difference_of_a_with_every_b = None continue # the now should contain only 1 element - assert len(difference_with_intersection) == 1 - difference = difference_with_intersection[0] + # assert len(difference_with_intersection) == 1 + difference_of_a_with_every_b = difference_of_a_with_every_b.difference_with(intersection_a_b)[0] - # if the difference has become None - if difference is None: + # if the difference_of_a_with_every_b has become None + if difference_of_a_with_every_b is None: # skip the rest of the loop continue # append the simple_set_a without every other simple set to the disjoint set - disjoint.simple_sets.add(difference) + disjoint.simple_sets.add(difference_of_a_with_every_b) return disjoint, non_disjoint @@ -410,11 +411,25 @@ def __hash__(self): return hash(tuple(self.simple_sets)) def __lt__(self, other: Self): - if self.is_empty(): - return True - if other.is_empty(): - return False - return self.simple_sets[0] < other.simple_sets[0] + """ + Compare this set with another set. + + The sets are compared by comparing the simple sets in order. + If the pair of simple sets are equal, the next pair is compared. + If all pairs are equal, the set with the least amount of simple sets is considered smaller. + + ..note:: This does not define a total order in the mathematical sense. In the mathematical sense, this defines + a partial order. + + :param other: The other set + :return: Rather this set is smaller than the other set + """ + for a, b in zip(self.simple_sets, other.simple_sets): + if a == b: + continue + else: + return a < b + return len(self.simple_sets) < len(other.simple_sets) def to_json(self) -> Dict[str, Any]: return {**super().to_json(), "simple_sets": [simple_set.to_json() for simple_set in self.simple_sets]} diff --git a/test/test_interval.py b/test/test_interval.py index 237c737..5de6f25 100644 --- a/test/test_interval.py +++ b/test/test_interval.py @@ -82,6 +82,12 @@ def test_to_json(self): self.assertIsInstance(c, Interval) self.assertEqual(b, c) + def test_alessandros_order_complaint(self): + a = open(2, 4) | open(5, 6) + b = open(3, 4) | open(4.5, 5.5) + self.assertTrue(a < b) + self.assertFalse(b < a) + if __name__ == '__main__': unittest.main() diff --git a/test/test_product_algebra.py b/test/test_product_algebra.py index 8df55f6..2a94fea 100644 --- a/test/test_product_algebra.py +++ b/test/test_product_algebra.py @@ -1,11 +1,13 @@ import unittest from sortedcontainers import SortedSet +import plotly.graph_objects as go -from random_events.variable import Continuous, Symbolic -from random_events.interval import Interval, SimpleInterval +from random_events.interval import * from random_events.product_algebra import SimpleEvent, Event from random_events.set import SetElement, Set +from random_events.sigma_algebra import AbstractSimpleSet +from random_events.variable import Continuous, Symbolic class TestEnum(SetElement): @@ -15,9 +17,10 @@ class TestEnum(SetElement): C = 4 -class SimpleEventTestCase(unittest.TestCase): +class EventTestCase(unittest.TestCase): x = Continuous("x") y = Continuous("y") + z = Continuous("z") a = Symbolic("a", TestEnum) b = Symbolic("b", TestEnum) @@ -69,6 +72,42 @@ def test_simplify(self): self.y: Interval([SimpleInterval(0, 1)])})]) self.assertEqual(simplified, result) + def test_to_json(self): + event = SimpleEvent({self.a: Set([TestEnum.A, TestEnum.B]), self.x: Interval([SimpleInterval(0, 1)]), + self.y: Interval([SimpleInterval(0, 1)])}) + event_ = AbstractSimpleSet.from_json(event.to_json()) + self.assertEqual(event_, event) + + def test_plot_2d(self): + event_1 = SimpleEvent({self.x: Interval([SimpleInterval(0, 1)]), + self.y: Interval([SimpleInterval(0, 1)])}) + event_2 = SimpleEvent({self.x: Interval([SimpleInterval(1, 2)]), + self.y: Interval([SimpleInterval(1, 2)])}) + event = Event([event_1, event_2]) + fig = go.Figure(event.plot(), event.plotly_layout()) + self.assertIsNotNone(fig) + # fig.show() + + def test_plot_3d(self): + event_1 = SimpleEvent({self.x: Interval([SimpleInterval(0, 1)]), + self.y: Interval([SimpleInterval(0, 1)]), + self.z: Interval([SimpleInterval(0, 1)])}) + event_2 = SimpleEvent({self.x: Interval([SimpleInterval(1, 2)]), + self.y: Interval([SimpleInterval(1, 2)]), + self.z: Interval([SimpleInterval(1, 2)])}) + event = Event([event_1, event_2]) + fig = go.Figure(event.plot(), event.plotly_layout()) + self.assertIsNotNone(fig) + # fig.show() + + def test_union(self): + event = Event([SimpleEvent({self.a: Set([TestEnum.A]), self.x: open(-float("inf"), 2)})]) + second_event = Event([SimpleEvent({self.a: Set([TestEnum.A, TestEnum.B]), self.x: open(1, 4)})]) + union = event | second_event + result = Event([SimpleEvent({self.a: Set([TestEnum.A]), self.x: open(-float("inf"), 2)}), + SimpleEvent({self.a: Set([TestEnum.B]), self.x: open(1, 4)})]) + self.assertEqual(union, result) + if __name__ == '__main__': unittest.main()