diff --git a/Dates/.gitignore b/Dates/.gitignore
new file mode 100644
index 0000000..b184dd6
--- /dev/null
+++ b/Dates/.gitignore
@@ -0,0 +1 @@
+*.apkg
diff --git a/Dates/1900s.ods b/Dates/1900s.ods
new file mode 100644
index 0000000..01d0de9
Binary files /dev/null and b/Dates/1900s.ods differ
diff --git a/Dates/Date Flashcards.ipynb b/Dates/Date Flashcards.ipynb
new file mode 100644
index 0000000..6ab87c9
--- /dev/null
+++ b/Dates/Date Flashcards.ipynb
@@ -0,0 +1,250 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Generate date flashcards for Anki\n",
+ "https://github.com/kerrickstaley/genanki"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from datetime import date"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "522800796"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import random\n",
+ "\n",
+ "def get_id():\n",
+ " return random.randrange(1<<32)\n",
+ "get_id()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import genanki\n",
+ "\n",
+ "front_back = genanki.Model(\n",
+ " get_id(),\n",
+ " 'Front Back Model',\n",
+ " fields=[\n",
+ " {'name': 'Date'},\n",
+ " {'name': 'Day'},\n",
+ " ],\n",
+ " templates=[\n",
+ " {\n",
+ " 'name': 'Date Card',\n",
+ " 'qfmt': '{{Date}}',\n",
+ " 'afmt': '{{Day}}',\n",
+ " },\n",
+ " ]\n",
+ ")\n",
+ "\n",
+ "def make_deck(cards, name):\n",
+ " # Cards is a list of fields\n",
+ " deck = genanki.Deck(get_id(), name)\n",
+ " \n",
+ " for card in cards:\n",
+ " note = genanki.Note(\n",
+ " model=front_back,\n",
+ " fields=card\n",
+ " )\n",
+ " deck.add_note(note)\n",
+ " \n",
+ " return deck\n",
+ "\n",
+ "def write_decks(decks, name='dates'):\n",
+ " genanki.Package(decks).write_to_file(f'{name}.apkg')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "2"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "date(2019, 8, 28).weekday()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import calendar\n",
+ "\n",
+ "def make_august_weekday_deck(days_string):\n",
+ " wkday_map = {\n",
+ " 'M': 0,\n",
+ " 'T': 1,\n",
+ " 'W': 2,\n",
+ " 'R': 3, \n",
+ " 'F': 4, \n",
+ " 'S': 5,\n",
+ " 'U': 6\n",
+ " }\n",
+ " \n",
+ " days = sorted([wkday_map[day] for day in days_string])\n",
+ " \n",
+ " names = [calendar.day_abbr[i] for i in days]\n",
+ " name = 'August, 2019 (' + ', '.join(names) + ')'\n",
+ " \n",
+ " cards = []\n",
+ " for i in range(31):\n",
+ " day = date(2019, 8, i+1)\n",
+ " if day.weekday() not in days:\n",
+ " continue\n",
+ " date_string = day.strftime('%B %d, %Y')\n",
+ " day_string = day.strftime('%A')\n",
+ " cards.append([date_string, day_string])\n",
+ " \n",
+ " return make_deck(cards, name)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def make_august_decks():\n",
+ " \n",
+ " schedule = 'MRSWUTF'\n",
+ " \n",
+ " decks = []\n",
+ " \n",
+ " for i in range(1, len(schedule)):\n",
+ " decks.append(make_august_weekday_deck(schedule[0:i+1]))\n",
+ " \n",
+ " write_decks(decks, 'August')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "make_august_decks()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from calendar import monthrange\n",
+ "def make_month_deck(month, year=2019):\n",
+ " \n",
+ " name = date(year, month, 1).strftime('%B, %Y')\n",
+ " \n",
+ " cards = []\n",
+ " for i in range(monthrange(2019, month)[1]):\n",
+ " day = date(2019, month, i+1)\n",
+ " date_string = day.strftime('%B %d, %Y')\n",
+ " day_string = day.strftime('%A')\n",
+ " cards.append([date_string, day_string])\n",
+ " \n",
+ " return make_deck(cards, name)\n",
+ "\n",
+ "def make_months_deck(months, year=2019):\n",
+ " \n",
+ " name = ', '.join([date(year, month, 1).strftime('%B') for month in months]) + date(year, 1, 1).strftime(' - %Y')\n",
+ " \n",
+ " cards = []\n",
+ " for month in months:\n",
+ " for i in range(monthrange(2019, month)[1]):\n",
+ " day = date(2019, month, i+1)\n",
+ " date_string = day.strftime('%B %d, %Y')\n",
+ " day_string = day.strftime('%A')\n",
+ " cards.append([date_string, day_string])\n",
+ " \n",
+ " return make_deck(cards, name)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "write_decks([make_month_deck(9)], 'September')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "write_decks([make_months_deck([8, 9])], 'Aug,Sept')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/Dates/Double Day Flashcards.ipynb b/Dates/Double Day Flashcards.ipynb
new file mode 100644
index 0000000..ed7cfe0
--- /dev/null
+++ b/Dates/Double Day Flashcards.ipynb
@@ -0,0 +1,304 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Generate date flashcards for Anki\n",
+ "https://github.com/kerrickstaley/genanki"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "from datetime import date"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "2263097491"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import random\n",
+ "\n",
+ "def get_id():\n",
+ " return random.randrange(1<<32)\n",
+ "get_id()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 35,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import genanki\n",
+ "\n",
+ "# Show any date from month with day\n",
+ "# Show other date from month with blank day\n",
+ "\n",
+ "dday = genanki.Model(\n",
+ " get_id(),\n",
+ " 'Double Day',\n",
+ " fields=[\n",
+ " {'name': 'Date1'},\n",
+ " {'name': 'Day1'},\n",
+ " {'name': 'Date2'},\n",
+ " {'name': 'Day2'},\n",
+ " ],\n",
+ " templates=[\n",
+ " {\n",
+ " 'name': 'Double Day Card',\n",
+ " 'qfmt': \"\"\"\n",
+ "
\n",
+ "
\n",
+ "\n",
+ "
\n",
+ "
{{Date1}}
\n",
+ "
{{Day1}}
\n",
+ " \n",
+ "
\n",
+ "
\n",
+ "\n",
+ "
\n",
+ "
{{Date2}}
\n",
+ "
\n",
+ "
\n",
+ "\n",
+ "
\n",
+ "
\"\"\",\n",
+ " 'afmt': \"\"\"\n",
+ "\n",
+ "
\n",
+ "\n",
+ "
\n",
+ "
{{Date1}}
\n",
+ "
{{Day1}}
\n",
+ " \n",
+ "
\n",
+ "
\n",
+ "\n",
+ "
\n",
+ "
{{Date2}}
\n",
+ "
{{Day2}}
\n",
+ "
\n",
+ "\n",
+ "
\n",
+ "
\"\"\"\n",
+ " },\n",
+ " ]\n",
+ ")\n",
+ "\n",
+ "def make_deck(cards, name):\n",
+ " # Cards is a list of fields\n",
+ " deck = genanki.Deck(get_id(), name)\n",
+ " \n",
+ " for card in cards:\n",
+ " note = genanki.Note(\n",
+ " model=dday,\n",
+ " fields=card\n",
+ " )\n",
+ " deck.add_note(note)\n",
+ " \n",
+ " return deck\n",
+ "\n",
+ "def write_decks(decks, name='dates'):\n",
+ " genanki.Package(decks).write_to_file(f'{name}.apkg')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 36,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def write_deck(deck):\n",
+ " genanki.Package([deck]).write_to_file(f'doubledates.apkg')\n",
+ "\n",
+ "write_deck(make_double_deck())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "2"
+ ]
+ },
+ "execution_count": 31,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "date(2019, 8, 28).weekday()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "import random\n",
+ "from datetime import datetime, timedelta\n",
+ "from calendar import monthrange, month_name\n",
+ "\n",
+ "def make_double_deck(n=11000):\n",
+ " year = 2019\n",
+ " \n",
+ " cards = []\n",
+ " \n",
+ " for i in range(n):\n",
+ " month = random.choice(range(12)) + 1\n",
+ " max_day = monthrange(year, month)[1]\n",
+ " day = random.choice(range(max_day)) + 1\n",
+ " \n",
+ " reference_day = day\n",
+ " while day == reference_day:\n",
+ " reference_day = random.choice(range(max_day)) + 1\n",
+ " \n",
+ " month_str = month_name[month]\n",
+ " reference_day_str = date(year, month, reference_day).strftime('%A')\n",
+ " day_str = date(year, month, day).strftime('%A')\n",
+ " cards.append((\n",
+ " f\"{month_str} {reference_day}, {year}\",\n",
+ " f\"{reference_day_str}\",\n",
+ " f\"{month_str} {day}, {year}\",\n",
+ " f\"{day_str}\",\n",
+ " \n",
+ " ))\n",
+ " \n",
+ " return make_deck(cards, \"Doubles\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Thursday'"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "date(2019, 9, 26).strftime(\"%A\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "write_decks([make_month_deck(9)], 'September')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "write_decks([make_double_deck([i + 1 for i in range (12)])])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "1\n",
+ "4\n",
+ "4\n",
+ "0\n",
+ "2\n",
+ "5\n",
+ "0\n",
+ "3\n",
+ "6\n",
+ "1\n",
+ "4\n",
+ "6\n"
+ ]
+ }
+ ],
+ "source": [
+ "from datetime import date\n",
+ "for i in range(12):\n",
+ " a = date(2019, i + 1, 1)\n",
+ " print(a.weekday())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/Dates/Exploration.ipynb b/Dates/Exploration.ipynb
new file mode 100644
index 0000000..24084a8
--- /dev/null
+++ b/Dates/Exploration.ipynb
@@ -0,0 +1,334 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from datetime import datetime\n",
+ "from calendar import day_abbr"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 44,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "6"
+ ]
+ },
+ "execution_count": 44,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "datetime(2099, 1, 4).weekday()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 47,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[0, 28, 56, 84]"
+ ]
+ },
+ "execution_count": 47,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "[i * 28 for i in range(4)]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 56,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "73\n",
+ "15\n",
+ "76\n",
+ "71\n",
+ "26\n",
+ "5\n",
+ "41\n",
+ "17\n",
+ "13\n",
+ "75\n",
+ "92\n",
+ "91\n",
+ "9\n",
+ "52\n",
+ "57\n",
+ "67\n",
+ "32\n",
+ "47\n",
+ "82\n",
+ "89\n"
+ ]
+ }
+ ],
+ "source": [
+ "import random\n",
+ "for i in range(20):\n",
+ " print(random.randint(0, 99))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 59,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "1\n",
+ "5\n",
+ "5\n",
+ "5\n",
+ "5\n",
+ "0\n",
+ "3\n",
+ "1\n",
+ "3\n",
+ "3\n",
+ "4\n",
+ "2\n",
+ "5\n",
+ "3\n",
+ "2\n",
+ "0\n",
+ "6\n",
+ "3\n",
+ "5\n",
+ "0\n"
+ ]
+ }
+ ],
+ "source": [
+ "x = [\n",
+ " 73,\n",
+ " 15,\n",
+ " 76,\n",
+ " 71,\n",
+ " 26,\n",
+ " 5,\n",
+ " 41,\n",
+ " 17,\n",
+ " 13,\n",
+ " 75,\n",
+ " 92,\n",
+ " 91,\n",
+ " 9,\n",
+ " 52,\n",
+ " 57,\n",
+ " 67,\n",
+ " 32,\n",
+ " 47,\n",
+ " 82,\n",
+ " 89\n",
+ "]\n",
+ "for y in x:\n",
+ " print(datetime(2000 + y, 7, 11).weekday())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "2000: Sat Tue Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n",
+ "2001: Mon Thu Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "2002: Tue Fri Fri Mon Wed Sat Mon Thu Sun Tue Fri Sun \n",
+ "2003: Wed Sat Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "2004: Thu Sun Mon Thu Sat Tue Thu Sun Wed Fri Mon Wed \n",
+ "2005: Sat Tue Tue Fri Sun Wed Fri Mon Thu Sat Tue Thu \n",
+ "2006: Sun Wed Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n",
+ "2007: Mon Thu Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "2008: Tue Fri Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "2009: Thu Sun Sun Wed Fri Mon Wed Sat Tue Thu Sun Tue \n",
+ "2010: Fri Mon Mon Thu Sat Tue Thu Sun Wed Fri Mon Wed \n",
+ "2011: Sat Tue Tue Fri Sun Wed Fri Mon Thu Sat Tue Thu \n",
+ "2012: Sun Wed Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "2013: Tue Fri Fri Mon Wed Sat Mon Thu Sun Tue Fri Sun \n",
+ "2014: Wed Sat Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "2015: Thu Sun Sun Wed Fri Mon Wed Sat Tue Thu Sun Tue \n",
+ "2016: Fri Mon Tue Fri Sun Wed Fri Mon Thu Sat Tue Thu \n",
+ "2017: Sun Wed Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n",
+ "2018: Mon Thu Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "2019: Tue Fri Fri Mon Wed Sat Mon Thu Sun Tue Fri Sun \n",
+ "2020: Wed Sat Sun Wed Fri Mon Wed Sat Tue Thu Sun Tue \n",
+ "2021: Fri Mon Mon Thu Sat Tue Thu Sun Wed Fri Mon Wed \n",
+ "2022: Sat Tue Tue Fri Sun Wed Fri Mon Thu Sat Tue Thu \n",
+ "2023: Sun Wed Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n",
+ "2024: Mon Thu Fri Mon Wed Sat Mon Thu Sun Tue Fri Sun \n",
+ "2025: Wed Sat Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "2026: Thu Sun Sun Wed Fri Mon Wed Sat Tue Thu Sun Tue \n",
+ "2027: Fri Mon Mon Thu Sat Tue Thu Sun Wed Fri Mon Wed \n",
+ "2028: Sat Tue Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n",
+ "2029: Mon Thu Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "2030: Tue Fri Fri Mon Wed Sat Mon Thu Sun Tue Fri Sun \n",
+ "2031: Wed Sat Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "2032: Thu Sun Mon Thu Sat Tue Thu Sun Wed Fri Mon Wed \n",
+ "2033: Sat Tue Tue Fri Sun Wed Fri Mon Thu Sat Tue Thu \n",
+ "2034: Sun Wed Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n",
+ "2035: Mon Thu Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "2036: Tue Fri Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "2037: Thu Sun Sun Wed Fri Mon Wed Sat Tue Thu Sun Tue \n",
+ "2038: Fri Mon Mon Thu Sat Tue Thu Sun Wed Fri Mon Wed \n",
+ "2039: Sat Tue Tue Fri Sun Wed Fri Mon Thu Sat Tue Thu \n",
+ "2040: Sun Wed Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "2041: Tue Fri Fri Mon Wed Sat Mon Thu Sun Tue Fri Sun \n",
+ "2042: Wed Sat Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "2043: Thu Sun Sun Wed Fri Mon Wed Sat Tue Thu Sun Tue \n",
+ "2044: Fri Mon Tue Fri Sun Wed Fri Mon Thu Sat Tue Thu \n",
+ "2045: Sun Wed Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n",
+ "2046: Mon Thu Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "2047: Tue Fri Fri Mon Wed Sat Mon Thu Sun Tue Fri Sun \n",
+ "2048: Wed Sat Sun Wed Fri Mon Wed Sat Tue Thu Sun Tue \n",
+ "2049: Fri Mon Mon Thu Sat Tue Thu Sun Wed Fri Mon Wed \n",
+ "2050: Sat Tue Tue Fri Sun Wed Fri Mon Thu Sat Tue Thu \n",
+ "2051: Sun Wed Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n",
+ "2052: Mon Thu Fri Mon Wed Sat Mon Thu Sun Tue Fri Sun \n",
+ "2053: Wed Sat Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "2054: Thu Sun Sun Wed Fri Mon Wed Sat Tue Thu Sun Tue \n",
+ "2055: Fri Mon Mon Thu Sat Tue Thu Sun Wed Fri Mon Wed \n",
+ "2056: Sat Tue Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n",
+ "2057: Mon Thu Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "2058: Tue Fri Fri Mon Wed Sat Mon Thu Sun Tue Fri Sun \n",
+ "2059: Wed Sat Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "2060: Thu Sun Mon Thu Sat Tue Thu Sun Wed Fri Mon Wed \n",
+ "2061: Sat Tue Tue Fri Sun Wed Fri Mon Thu Sat Tue Thu \n",
+ "2062: Sun Wed Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n",
+ "2063: Mon Thu Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "2064: Tue Fri Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "2065: Thu Sun Sun Wed Fri Mon Wed Sat Tue Thu Sun Tue \n",
+ "2066: Fri Mon Mon Thu Sat Tue Thu Sun Wed Fri Mon Wed \n",
+ "2067: Sat Tue Tue Fri Sun Wed Fri Mon Thu Sat Tue Thu \n",
+ "2068: Sun Wed Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "2069: Tue Fri Fri Mon Wed Sat Mon Thu Sun Tue Fri Sun \n",
+ "2070: Wed Sat Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "2071: Thu Sun Sun Wed Fri Mon Wed Sat Tue Thu Sun Tue \n",
+ "2072: Fri Mon Tue Fri Sun Wed Fri Mon Thu Sat Tue Thu \n",
+ "2073: Sun Wed Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n",
+ "2074: Mon Thu Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "2075: Tue Fri Fri Mon Wed Sat Mon Thu Sun Tue Fri Sun \n",
+ "2076: Wed Sat Sun Wed Fri Mon Wed Sat Tue Thu Sun Tue \n",
+ "2077: Fri Mon Mon Thu Sat Tue Thu Sun Wed Fri Mon Wed \n",
+ "2078: Sat Tue Tue Fri Sun Wed Fri Mon Thu Sat Tue Thu \n",
+ "2079: Sun Wed Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n",
+ "2080: Mon Thu Fri Mon Wed Sat Mon Thu Sun Tue Fri Sun \n",
+ "2081: Wed Sat Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "2082: Thu Sun Sun Wed Fri Mon Wed Sat Tue Thu Sun Tue \n",
+ "2083: Fri Mon Mon Thu Sat Tue Thu Sun Wed Fri Mon Wed \n",
+ "2084: Sat Tue Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n",
+ "2085: Mon Thu Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "2086: Tue Fri Fri Mon Wed Sat Mon Thu Sun Tue Fri Sun \n",
+ "2087: Wed Sat Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "2088: Thu Sun Mon Thu Sat Tue Thu Sun Wed Fri Mon Wed \n",
+ "2089: Sat Tue Tue Fri Sun Wed Fri Mon Thu Sat Tue Thu \n",
+ "2090: Sun Wed Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n",
+ "2091: Mon Thu Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "2092: Tue Fri Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "2093: Thu Sun Sun Wed Fri Mon Wed Sat Tue Thu Sun Tue \n",
+ "2094: Fri Mon Mon Thu Sat Tue Thu Sun Wed Fri Mon Wed \n",
+ "2095: Sat Tue Tue Fri Sun Wed Fri Mon Thu Sat Tue Thu \n",
+ "2096: Sun Wed Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "2097: Tue Fri Fri Mon Wed Sat Mon Thu Sun Tue Fri Sun \n",
+ "2098: Wed Sat Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "2099: Thu Sun Sun Wed Fri Mon Wed Sat Tue Thu Sun Tue \n"
+ ]
+ }
+ ],
+ "source": [
+ "for year in range(2000, 2100):\n",
+ " line = f\"{year}: \"\n",
+ " for month in range(1, 13):\n",
+ " line += day_abbr[datetime(year, month, 1).weekday()] + ' '\n",
+ " print(line)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 39,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Wed Sat Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "Mon Thu Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "Sat Tue Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n",
+ "Fri Mon Mon Thu Sat Tue Thu Sun Wed Fri Mon Wed \n",
+ "Wed Sat Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "Mon Thu Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "Sat Tue Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n",
+ "Fri Mon Mon Thu Sat Tue Thu Sun Wed Fri Mon Wed \n",
+ "Wed Sat Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "Mon Thu Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "Sat Tue Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n",
+ "Fri Mon Mon Thu Sat Tue Thu Sun Wed Fri Mon Wed \n",
+ "Wed Sat Sat Tue Thu Sun Tue Fri Mon Wed Sat Mon \n",
+ "Mon Thu Thu Sun Tue Fri Sun Wed Sat Mon Thu Sat \n",
+ "Sat Tue Wed Sat Mon Thu Sat Tue Fri Sun Wed Fri \n"
+ ]
+ }
+ ],
+ "source": [
+ "for year in range(1000, 2401, 100):\n",
+ " line = \"\"\n",
+ " for month in range(1, 13):\n",
+ " line += day_abbr[datetime(year, month, 1).weekday()] + ' '\n",
+ " print(line)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/Dates/Exploration.ods b/Dates/Exploration.ods
new file mode 100644
index 0000000..577c072
Binary files /dev/null and b/Dates/Exploration.ods differ
diff --git a/Dates/Machine Learning.ipynb b/Dates/Machine Learning.ipynb
new file mode 100644
index 0000000..b4d02a1
--- /dev/null
+++ b/Dates/Machine Learning.ipynb
@@ -0,0 +1,708 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import time\n",
+ "from datetime import datetime, date, timedelta\n",
+ "import random"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def rand_date(start=date(1400, 1, 1), end=date(2400, 1, 1)):\n",
+ " diff = end - start\n",
+ " return start + random.random() * diff"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def convert_to_vector(xdate):\n",
+ " yr1 = xdate.year // 1000\n",
+ " yr2 = (xdate.year // 100) % 10\n",
+ " yr3 = (xdate.year // 10) % 10\n",
+ " yr4 = (xdate.year) % 10\n",
+ " \n",
+ " month = xdate.month\n",
+ " \n",
+ " day1 = xdate.day // 10\n",
+ " day2 = xdate.day % 10\n",
+ " \n",
+ " weekday = xdate.weekday()\n",
+ " \n",
+ " to_encode = [\n",
+ " (yr1, 10),\n",
+ " (yr2, 10),\n",
+ " (yr3, 10),\n",
+ " (yr4, 10),\n",
+ " (month, 12),\n",
+ " (day1, 10),\n",
+ " (day2, 10)\n",
+ " ]\n",
+ " \n",
+ " xs = []\n",
+ " for val, num_vals in to_encode:\n",
+ " one_hot = np.zeros(num_vals)\n",
+ " one_hot[val-1] = 1\n",
+ " xs.append(one_hot)\n",
+ " \n",
+ " x = np.concatenate(xs)\n",
+ " \n",
+ " y = np.zeros(7)\n",
+ " y[weekday] = 1\n",
+ " return x, y"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Encoding: One-hot, separate integers\n",
+ "\n",
+ "Training: Month, year, other years, other decades\n",
+ "\n",
+ "Raw\n",
+ "\n",
+ "Start small, build up\n",
+ "\n",
+ "One month, same month plus another, keep adding months until a year, then add new years\n",
+ "One month, add a month, add a year, add several month, add several years, add decades\n",
+ "Start without leap years, then include leap years\n",
+ "\n",
+ "Whole idea is to go simple and complex\n",
+ "Introduce new concepts before past concepts are solidified\n",
+ "Don't want to confuse things - easily possible\n",
+ "\n",
+ "Simplest would be a single month in non leap-year\n",
+ "When introducing leap years, do half leap years and half non-leap years\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Using TensorFlow backend.\n"
+ ]
+ }
+ ],
+ "source": [
+ "from keras.models import Sequential\n",
+ "from keras.layers import Dense\n",
+ "from keras.callbacks import Callback\n",
+ "from keras import backend as K"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "model = Sequential()\n",
+ "model.add(Dense(100, input_shape=(10*6 + 12,), activation='tanh'))\n",
+ "model.add(Dense(100, activation='tanh'))\n",
+ "model.add(Dense(100, activation='tanh'))\n",
+ "model.add(Dense(7, activation='softmax'))\n",
+ "\n",
+ "model.compile('adam', 'categorical_crossentropy', metrics=['accuracy'])\n",
+ "\n",
+ "def reset_model():\n",
+ " global model\n",
+ " session = K.get_session()\n",
+ " for layer in model.layers: \n",
+ " if hasattr(layer, 'kernel_initializer'):\n",
+ " layer.kernel.initializer.run(session=session)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def generate_random(batch_size):\n",
+ " dates = []\n",
+ " xs = []\n",
+ " ys = []\n",
+ " for i in range(batch_size):\n",
+ " rdate = rand_date()\n",
+ " x, y = convert_to_vector(rdate)\n",
+ " dates.append(rdate)\n",
+ " xs.append(x)\n",
+ " ys.append(y)\n",
+ "\n",
+ " xs = np.array(xs)\n",
+ " ys = np.array(ys)\n",
+ " return xs, ys\n",
+ "\n",
+ "\n",
+ "def get_range_gen(start_date, end_date):\n",
+ " def generate_range(batch_size):\n",
+ " dates = []\n",
+ " xs = []\n",
+ " ys = []\n",
+ " for i in range(batch_size):\n",
+ " rdate = rand_date(start_date, end_date)\n",
+ " x, y = convert_to_vector(rdate)\n",
+ " dates.append(rdate)\n",
+ " xs.append(x)\n",
+ " ys.append(y)\n",
+ "\n",
+ " xs = np.array(xs)\n",
+ " ys = np.array(ys)\n",
+ " return xs, ys\n",
+ " return generate_range\n",
+ "\n",
+ "\n",
+ "def get_month_gen(year, month):\n",
+ " start = date(year, month, 1)\n",
+ " if month == 12:\n",
+ " end = date(year + 1, 1, 1)\n",
+ " else:\n",
+ " end = date(year, month + 1, 1)\n",
+ " return get_range_generator(start, end)\n",
+ "\n",
+ "\n",
+ "def combine_gens(generators, p=None):\n",
+ " if p is None:\n",
+ " p = [1/len(generators)] * len(generators)\n",
+ " \n",
+ " def generate(batch_size):\n",
+ " generator = np.random.choice(generators, p=p)\n",
+ " return generator(batch_size)\n",
+ " \n",
+ " return generate\n",
+ "\n",
+ "\n",
+ "def get_months_gen(year, months, p=None):\n",
+ " gens = []\n",
+ " for month in months:\n",
+ " gens.append(get_month_generator(year, month))\n",
+ " return combine_generators(gens, p)\n",
+ "\n",
+ "\n",
+ "def get_year_gen(year):\n",
+ " return get_range_generator(date(year, 1, 1), date(year+1, 1, 1))\n",
+ "\n",
+ "\n",
+ "def get_years_gen(start_year, end_year):\n",
+ " return get_range_generator(date(start_year, 1, 1), date(end_year + 1, 1, 1))\n",
+ "\n",
+ "\n",
+ "def get_years_gen_p(years, p=None):\n",
+ " gens = []\n",
+ " for year in years:\n",
+ " gens.append(get_year_generator(year))\n",
+ " return combine_generators(years, p)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from collections import deque"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def train_until_acc(model, data_gen, desired_acc, output=True, limit=1000000):\n",
+ " running_acc = 0\n",
+ " num_samples = 0\n",
+ " batch_size = 32\n",
+ " accs = deque(maxlen=10)\n",
+ " accs.append(desired_acc-0.01) # so we don't get the divide by zero error\n",
+ " \n",
+ " batch_num = 0\n",
+ " while sum(accs)/len(accs) < desired_acc:\n",
+ " xs, ys = data_gen(batch_size)\n",
+ " loss, acc = model.train_on_batch(xs, ys)\n",
+ " accs.append(acc)\n",
+ " num_samples += batch_size\n",
+ " batch_num += 1\n",
+ " if batch_num % 100 == 0:\n",
+ " print(\"Minibatch\", batch_num, sum(accs)/len(accs))\n",
+ " if num_samples > limit: # 1 mil by default\n",
+ " break\n",
+ " return num_samples\n",
+ "\n",
+ "\n",
+ "def run_schedule(schedule):\n",
+ " reset_model()\n",
+ " \n",
+ " total_samples = 0\n",
+ " for name, data_gen, accuracy in schedule:\n",
+ " num_samples = train_until_acc(model, data_gen, accuracy)\n",
+ " total_samples += num_samples\n",
+ " print('Trained {} in {} samples'.format(name, num_samples))\n",
+ " print('Training complete after {} samples'.format(total_samples))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from scipy.special import softmax\n",
+ "\n",
+ "def get_schedule_generator(x):\n",
+ " class P:\n",
+ " def __init__(self, x):\n",
+ " self.x = x\n",
+ " def __getitem__(self, key):\n",
+ " x.add_constraints()\n",
+ " return softmax(x[key])\n",
+ " \n",
+ " x = X(x)\n",
+ " p = P(x)\n",
+ " \n",
+ " schedule = [\n",
+ " ('Aug', get_month_generator(2019, 8), 0.99)\n",
+ " ]\n",
+ " class StagedValue:\n",
+ " def __init__(self, num):\n",
+ " self.num = num\n",
+ " class Stager:\n",
+ " def __init__(self):\n",
+ " self.total = 0\n",
+ " self.constraints = []\n",
+ " def __getitem__(self, key):\n",
+ " self.total += key\n",
+ " new_constraints = None # TODO Implement new constraints\n",
+ " self.constraints.append(new_constraints)\n",
+ " return StagedValue(key)\n",
+ " \n",
+ " # TODO How do I get this for multiple situations\n",
+ " schedule = [ # Have a schedule generator. Maybe iterate through after staging to activate\n",
+ " ('Aug', get_month_generator(2019, 8), 0.99),\n",
+ " ('Sep', get_months_generator(2019, [8, 9], p=p[2]), 0.99),\n",
+ " ('All', get_month_generator(2019, [8, 9]), 0.99)\n",
+ " ]\n",
+ " \n",
+ " # need to create function that accepts the right number of parameters and stuff\n",
+ " # use sparse matrix to represent constraints\n",
+ " class X:\n",
+ " def __init__(self, x):\n",
+ " self.x = x\n",
+ " self.current = 0\n",
+ " def __getitem__(self, key):\n",
+ " values = self.x[self.current: self.current+key]\n",
+ " self.current += key\n",
+ " return values\n",
+ " def __len__(self):\n",
+ " return self.current\n",
+ " \n",
+ " def get_schedule(x):\n",
+ " x = X(x)\n",
+ " processed_schedule = []\n",
+ " for name, func, params, probability in schedule:\n",
+ " # process into actual schedule\n",
+ " new_params = []\n",
+ " for param in params:\n",
+ " if type(param) is StagedValue:\n",
+ " new_params.append(x[param.num])\n",
+ " else:\n",
+ " new_params.append(param)\n",
+ " schedule_item = (name, func(*params), probability)\n",
+ " processed_schedule.append(schedule_item)\n",
+ " return processed_schedule\n",
+ " \n",
+ " return get_schedule, constraints, x0\n",
+ " \n",
+ " \n",
+ " \n",
+ " schedule = [ # Have a schedule generator. Maybe iterate through after staging to activate\n",
+ " ('Aug', get_month_generator(2019, 8), 0.99),\n",
+ " ('Sep', get_months_generator(2019, [8, 9], p=p[2]), x[1]),\n",
+ " ('Oct', get_month_generator(2019, [8, 9, 10], p=p[3]), x[1]),\n",
+ " ('Oct', get_month_generator(2019, [8, 9, 10]), 0.99)\n",
+ " ]\n",
+ " \n",
+ " schedule = [\n",
+ " ('2019-1', get_months_gen(2019, range(1, 13), p=x[12]), x[1]),\n",
+ " ('2019-2', get_months_gen(2019, range(1, 13), p=x[12]), x[1]),\n",
+ " ('2019-3', get_months_gen(2019, range(1, 13), p=x[12]), x[1]),\n",
+ " ('2019-4', get_months_gen(2019, range(1, 13), p=x[12]), x[1]),\n",
+ " ('2019-5', get_months_gen(2019, range(1, 13), p=x[12]), x[1]),\n",
+ " ('2019-6', get_months_gen(2019, range(1, 13), p=x[12]), x[1]),\n",
+ " ('2019-7', get_months_gen(2019, range(1, 13), p=x[12]), x[1]),\n",
+ " ('2019-8', get_months_gen(2019, range(1, 13), p=x[12]), x[1]),\n",
+ " ('2019-9', get_months_gen(2019, range(1, 13), p=x[12]), x[1]),\n",
+ " ('2019-10', get_months_gen(2019, range(1, 13), p=x[12]), x[1]),\n",
+ " ('2019-11', get_months_gen(2019, range(1, 13), p=x[12]), x[1]),\n",
+ " ('2019-12', get_months_gen(2019, range(1, 13), p=x[12]), x[1]),\n",
+ " ('2019', get_year_generator(2019), 0.99),\n",
+ "# ('2020', get_years_gen(2019, 2020), x[1]),\n",
+ "# ('2020s', get_years_gen(2019, 2029), x[1]),\n",
+ "# ('2000-2100', get_years_gen(2000, 2100), x[1]),\n",
+ "# ('1900-2100', get_years_gen(1900, 2100), x[1]),\n",
+ "# ('1-2100', get_years_gen(1, 2100), x[1]),\n",
+ " ]\n",
+ " \n",
+ " \n",
+ " return schedule, len(x)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Optimize the last two, so the new one and the most recent before that. That way, there's a lag time, but most of it is set. We can also save the progresss of the model to make the running occur faster"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'get_years_gen' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 13\u001b[0m \u001b[1;33m(\u001b[0m\u001b[1;34m'Jun'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mget_months_gen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m2019\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;36m6\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0.85\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 14\u001b[0m \u001b[1;33m(\u001b[0m\u001b[1;34m'2019'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mget_year_generator\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m2019\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0.85\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 15\u001b[1;33m \u001b[1;33m(\u001b[0m\u001b[1;34m'2020'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mget_years_gen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m2019\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2020\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0.85\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 16\u001b[0m \u001b[1;33m(\u001b[0m\u001b[1;34m'2020s'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mget_years_gen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m2019\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2029\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0.85\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 17\u001b[0m \u001b[1;33m(\u001b[0m\u001b[1;34m'2000-2100'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mget_years_gen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m2000\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2100\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0.85\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;31mNameError\u001b[0m: name 'get_years_gen' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "schedule = [\n",
+ " ('Jul', get_months_gen(2019, [7]), 0.99),\n",
+ " ('Aug', get_months_gen(2019, [8]), 0.85),\n",
+ " ('Sep', get_months_gen(2019, [9]), 0.85),\n",
+ " ('Oct', get_months_gen(2019, [10]), 0.85),\n",
+ " ('Nov', get_months_gen(2019, [11]), 0.85),\n",
+ " ('Dec', get_months_gen(2019, [12]), 0.85),\n",
+ " ('Jan', get_months_gen(2019, [1]), 0.85),\n",
+ " ('Feb', get_months_gen(2019, [2]), 0.85),\n",
+ " ('Mar', get_months_gen(2019, [3]), 0.85),\n",
+ " ('Apr', get_months_gen(2019, [4]), 0.85),\n",
+ " ('May', get_months_gen(2019, [5]), 0.85),\n",
+ " ('Jun', get_months_gen(2019, [6]), 0.85),\n",
+ " ('2019', get_year_generator(2019), 0.85),\n",
+ " ('2020', get_years_gen(2019, 2020), 0.85),\n",
+ " ('2020s', get_years_gen(2019, 2029), 0.85),\n",
+ " ('2000-2100', get_years_gen(2000, 2100), 0.85),\n",
+ " ('1900-2100', get_years_gen(1900, 2100), 0.85),\n",
+ " ('1-2100', get_years_gen(1, 2100), 0.85),\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "scrolled": false
+ },
+ "outputs": [],
+ "source": [
+ "run_schedule(schedule)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {
+ "scrolled": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Minibatch 100 0.5375\n",
+ "Trained July in 6208 samples\n",
+ "Trained Aug in 3072 samples\n",
+ "Trained Sep in 32 samples\n",
+ "Minibatch 100 0.571875\n",
+ "Trained Oct in 6016 samples\n",
+ "Trained Nov in 32 samples\n",
+ "Trained Dec in 64 samples\n",
+ "Trained Jan in 32 samples\n",
+ "Minibatch 100 0.79375\n",
+ "Trained Feb in 3328 samples\n",
+ "Trained Mar in 64 samples\n",
+ "Trained Apr in 32 samples\n",
+ "Trained May in 32 samples\n",
+ "Trained Jun in 1568 samples\n",
+ "Trained Jul-Dec in 32 samples\n",
+ "Trained 2019 in 3008 samples\n",
+ "Minibatch 100 0.75\n",
+ "Trained 2020 in 5312 samples\n",
+ "Minibatch 100 0.584375\n",
+ "Minibatch 200 0.778125\n",
+ "Minibatch 300 0.79375\n",
+ "Trained 2020s in 9856 samples\n",
+ "Minibatch 100 0.509375\n",
+ "Minibatch 200 0.6625\n",
+ "Minibatch 300 0.6875\n",
+ "Minibatch 400 0.75625\n",
+ "Minibatch 500 0.796875\n",
+ "Minibatch 600 0.7875\n",
+ "Trained 2000-2100 in 19904 samples\n",
+ "Trained 1900-2100 in 2944 samples\n",
+ "Minibatch 100 0.45625\n",
+ "Minibatch 200 0.5125\n",
+ "Minibatch 300 0.6125\n",
+ "Minibatch 400 0.65\n",
+ "Minibatch 500 0.65625\n",
+ "Minibatch 600 0.68125\n",
+ "Minibatch 700 0.696875\n",
+ "Minibatch 800 0.721875\n",
+ "Minibatch 900 0.734375\n",
+ "Minibatch 1000 0.746875\n",
+ "Minibatch 1100 0.778125\n",
+ "Minibatch 1200 0.80625\n",
+ "Minibatch 1300 0.825\n",
+ "Trained 1-2100 in 42400 samples\n",
+ "Minibatch 100 0.815625\n",
+ "Minibatch 200 0.85625\n",
+ "Minibatch 300 0.85625\n",
+ "Minibatch 400 0.884375\n",
+ "Minibatch 500 0.853125\n",
+ "Minibatch 600 0.85\n",
+ "Minibatch 700 0.890625\n",
+ "Minibatch 800 0.9\n",
+ "Minibatch 900 0.90625\n",
+ "Minibatch 1000 0.90625\n",
+ "Minibatch 1100 0.884375\n",
+ "Minibatch 1200 0.925\n",
+ "Minibatch 1300 0.940625\n",
+ "Minibatch 1400 0.925\n",
+ "Minibatch 1500 0.946875\n",
+ "Minibatch 1600 0.9375\n",
+ "Minibatch 1700 0.94375\n",
+ "Minibatch 1800 0.965625\n",
+ "Minibatch 1900 0.95\n",
+ "Minibatch 2000 0.953125\n",
+ "Minibatch 2100 0.928125\n",
+ "Minibatch 2200 0.940625\n",
+ "Minibatch 2300 0.959375\n",
+ "Minibatch 2400 0.9625\n",
+ "Minibatch 2500 0.959375\n",
+ "Minibatch 2600 0.96875\n",
+ "Minibatch 2700 0.971875\n",
+ "Minibatch 2800 0.96875\n",
+ "Minibatch 2900 0.971875\n",
+ "Minibatch 3000 0.971875\n",
+ "Minibatch 3100 0.9625\n",
+ "Minibatch 3200 0.984375\n",
+ "Minibatch 3300 0.946875\n",
+ "Minibatch 3400 0.95\n",
+ "Minibatch 3500 0.978125\n",
+ "Minibatch 3600 0.975\n",
+ "Minibatch 3700 0.98125\n",
+ "Minibatch 3800 0.975\n",
+ "Minibatch 3900 0.98125\n",
+ "Minibatch 4000 0.98125\n",
+ "Minibatch 4100 0.990625\n",
+ "Minibatch 4200 0.990625\n",
+ "Minibatch 4300 0.978125\n",
+ "Trained 1-2100 in 138720 samples\n",
+ "Training complete after 242656 samples\n"
+ ]
+ }
+ ],
+ "source": [
+ "from itertools import chain\n",
+ "\n",
+ "reset_model()\n",
+ "\n",
+ "schedule = [\n",
+ " ('July', get_month_generator(2019, 7), 0.85),\n",
+ " ('Aug', get_months_gen(2019, range(7, 9)), 0.85),\n",
+ " ('Sep', get_months_gen(2019, range(7, 10)), 0.85),\n",
+ " ('Oct', get_months_gen(2019, range(7, 11)), 0.85),\n",
+ " ('Nov', get_months_gen(2019, range(7, 12)), 0.85),\n",
+ " ('Dec', get_months_gen(2019, range(7, 13)), 0.85),\n",
+ " ('Jan', get_months_gen(2019, chain(range(1, 2), range(7, 13))), 0.85),\n",
+ " ('Feb', get_months_gen(2019, chain(range(1, 3), range(7, 13))), 0.85),\n",
+ " ('Mar', get_months_gen(2019, chain(range(1, 4), range(7, 13))), 0.85),\n",
+ " ('Apr', get_months_gen(2019, chain(range(1, 5), range(7, 13))), 0.85),\n",
+ " ('May', get_months_gen(2019, chain(range(1, 6), range(7, 13))), 0.85),\n",
+ " ('Jun', get_months_gen(2019, chain(range(1, 7), range(7, 13))), 0.85),\n",
+ " ('Jul-Dec', get_months_gen(2019, chain(range(1, 8), range(7, 13))), 0.85),\n",
+ " ('2019', get_year_generator(2019), 0.85),\n",
+ " ('2020', get_years_gen(2019, 2020), 0.85),\n",
+ " ('2020s', get_years_gen(2019, 2029), 0.85),\n",
+ " ('2000-2100', get_years_gen(2000, 2100), 0.85),\n",
+ " ('1900-2100', get_years_gen(1900, 2100), 0.85),\n",
+ " ('1-2100', get_years_gen(1, 2100), 0.85),\n",
+ " ('1-2100', get_years_gen(1, 2100), 0.999),\n",
+ "]\n",
+ "\n",
+ "bad_schedule = [\n",
+ " ('1-2100', get_years_gen(1, 2100), 0.85)\n",
+ "]\n",
+ "\n",
+ "schedule_2 = list(map(lambda item: (item[0], item[1], 0.5), schedule))\n",
+ "schedule_2[-1] = schedule[-1]\n",
+ "\n",
+ "schedule_3 = list(map(lambda item: (item[0], item[1], 0.2), schedule))\n",
+ "schedule_3[-1] = schedule[-1]\n",
+ "\n",
+ "run_schedule(schedule)\n",
+ "\n",
+ "# print('\\n\\n\\n')\n",
+ "# reset_model()\n",
+ "# run_schedule(model, schedule_2)\n",
+ "# print('\\n\\n\\n')\n",
+ "# reset_model()\n",
+ "# run_schedule(model, schedule_3)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([0., 0., 0., 0., 0., 0., 1.])"
+ ]
+ },
+ "execution_count": 29,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "convert_to_vector(date(2019,7,28))[1]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "array([[3.21856205e-04, 4.16064868e-04, 3.76252714e-03, 1.97594166e-02,\n",
+ " 8.88420641e-01, 7.28261918e-02, 1.44934375e-02]], dtype=float32)"
+ ]
+ },
+ "execution_count": 30,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model.predict(convert_to_vector(date(2035,5,18))[0].reshape((1, -1)))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "So far, it seems that a model with 0.85 threshold trains with 160k samples and a model with 0.5 threshold trains with 120k samples.\n",
+ "\n",
+ "I tested a model with no grading. It got 100k batches (3,200k samples) without having improved its' accuracy at all."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Can we train some type of model that takes in training histories and outputs the ideal training history?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 117,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Epoch 1/1\n",
+ "100000/100000 [==============================] - 19s 190us/step - loss: 0.4153 - acc: 0.8324\n"
+ ]
+ }
+ ],
+ "source": [
+ "stuff = model.fit(xs, ys)\n",
+ "\n",
+ "stuff\n",
+ "print(stuff.history['acc'])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Next steps:\n",
+ "\n",
+ "- Overfit on a single sample of say 1000, then as soon as its' prediction is better than chance, move along to another set. \n",
+ " - Compare to pure random\n",
+ "- Overfit on a sample of just a few, and then start throwing in new ones? - This was the whole strategy from before\n",
+ " - This would work, but we want our sample to be better than just chance, how do we determine the sample?\n",
+ "\n",
+ "1. Just do in order with random distributions up until a certain threshold\n",
+ " - Test different thresholds for progression, 50% accuracy, 90%, etc\n",
+ "2. Change distribution to reflect the learning that needs to happen\n",
+ " - If you get a certain month right 90% of the time, only show it 10% of the time or something like that - determine this distrubtion\n",
+ "3. Learn the distribution using some kind of statistics or model\n",
+ "4. Create an ml model that perfects this situation\n",
+ "\n",
+ "Also, should be considering taking a month where we know the date and asking for another date. So if we know that today is the 18th and a Thursday, we can infer that tomorrow is the 19th and a Friday."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.7.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/Dates/Personal Trainer.ipynb b/Dates/Personal Trainer.ipynb
new file mode 100644
index 0000000..43535ef
--- /dev/null
+++ b/Dates/Personal Trainer.ipynb
@@ -0,0 +1,117 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from datetime import date\n",
+ "from calendar import day_abbr, monthrange\n",
+ "\n",
+ "\n",
+ "def month_wkdy(month, days_string='MTWRFSU', year=2019):\n",
+ " wkday_map = {\n",
+ " 'M': 0,\n",
+ " 'T': 1,\n",
+ " 'W': 2,\n",
+ " 'R': 3, \n",
+ " 'F': 4, \n",
+ " 'S': 5,\n",
+ " 'U': 6\n",
+ " }\n",
+ " \n",
+ " days = sorted([wkday_map[day] for day in days_string])\n",
+ " \n",
+ " names = [day_abbr[i] for i in days]\n",
+ " \n",
+ " name = date(year, month, 1).strftime('%B, %Y (' + ', '.join(names) + ')')\n",
+ " \n",
+ " cards = []\n",
+ " for i in range(monthrange(2019, month)[1]):\n",
+ " day = date(2019, month, i+1)\n",
+ " if day.weekday() not in days:\n",
+ " continue\n",
+ " date_string = day.strftime('%B %d, %Y')\n",
+ " day_string = day.strftime('%A')\n",
+ " cards.append([date_string, day_string])\n",
+ " \n",
+ " return cards\n",
+ "\n",
+ "def aug_wkdy(days_string):\n",
+ " return month_wkdy(8, days_string)\n",
+ "\n",
+ "def sept_wkdy(days_string):\n",
+ " return month_wkdy(9, days_string)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import random\n",
+ "\n",
+ "def train(cards):\n",
+ " while True:\n",
+ " date, day = random.choice(cards)\n",
+ " if input(date):\n",
+ " break\n",
+ " if input(day):\n",
+ " break\n",
+ " print()\n",
+ "\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "September 05, 2019\n",
+ "Thursday\n",
+ "\n",
+ "September 05, 2019\n"
+ ]
+ }
+ ],
+ "source": [
+ "train(sept_wkdy('MR'))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.7.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/Dates/Presidents.ipynb b/Dates/Presidents.ipynb
new file mode 100644
index 0000000..a624371
--- /dev/null
+++ b/Dates/Presidents.ipynb
@@ -0,0 +1,229 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Generate date flashcards for Anki\n",
+ "https://github.com/kerrickstaley/genanki"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "1270607229"
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import random\n",
+ "\n",
+ "def get_id():\n",
+ " return random.randrange(1<<32)\n",
+ "get_id()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import genanki\n",
+ "\n",
+ "front_back = genanki.Model(\n",
+ " get_id(),\n",
+ " 'Front Back Model',\n",
+ " fields=[\n",
+ " {'name': 'Front'},\n",
+ " {'name': 'Back'},\n",
+ " ],\n",
+ " templates=[\n",
+ " {\n",
+ " 'name': 'Card',\n",
+ " 'qfmt': '{{Front}}',\n",
+ " 'afmt': '{{Back}}',\n",
+ " },\n",
+ " ]\n",
+ ")\n",
+ "\n",
+ "def make_deck(cards, name):\n",
+ " # Cards is a list of fields\n",
+ " deck = genanki.Deck(get_id(), name)\n",
+ " \n",
+ " for card in cards:\n",
+ " note = genanki.Note(\n",
+ " model=front_back,\n",
+ " fields=card\n",
+ " )\n",
+ " deck.add_note(note)\n",
+ " \n",
+ " return deck\n",
+ "\n",
+ "def write_decks(decks, name):\n",
+ " genanki.Package(decks).write_to_file(f'{name}.apkg')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "presidents = [ \n",
+ " \"George Washington\",\n",
+ " \"John Adams\",\n",
+ " \"Thomas Jefferson\",\n",
+ " \"James Madison\",\n",
+ " \"James Monroe\",\n",
+ " \"John Quincy Adams\",\n",
+ " \"Andrew Jackson\",\n",
+ " \"Martin Van Buren\",\n",
+ " \"William Henry Harrison\",\n",
+ " \"John Tyler\",\n",
+ " \"James K. Polk\",\n",
+ " \"Zachary Taylor\",\n",
+ " \"Millard Fillmore\",\n",
+ " \"Franklin Pierce\",\n",
+ " \"James Buchanan\",\n",
+ " \"Abraham Lincoln\",\n",
+ " \"Andrew Johnson\",\n",
+ " \"Ulysses S. Grant\",\n",
+ " \"Rutherford B. Hayes\",\n",
+ " \"James A. Garfield\",\n",
+ " \"Chester A. Arthur\",\n",
+ " \"Grover Cleaveland (First term)\",\n",
+ " \"Benjamin Harrison\",\n",
+ " \"Grover Cleaveland (Second term)\",\n",
+ " \"William McKinley\",\n",
+ " \"Theodore Roosevelt\",\n",
+ " \"William Howard Taft\",\n",
+ " \"Woodrow Wilson\",\n",
+ " \"Warren G. Harding\",\n",
+ " \"Calvin Coolidge\",\n",
+ " \"Herbert Hoover\",\n",
+ " \"Franklin D. Roosevelt\",\n",
+ " \"Harry S. Truman\",\n",
+ " \"Dwight D. Eisenhower\",\n",
+ " \"John F. Kennedy\",\n",
+ " \"Lyndon B. Johnson\",\n",
+ " \"Richard Nixon\",\n",
+ " \"Gerald Ford\",\n",
+ " \"Jimmy Carter\",\n",
+ " \"Ronald Reagan\",\n",
+ " \"George H. W. Bush\",\n",
+ " \"Bill Clinton\",\n",
+ " \"George W. Bush\",\n",
+ " \"Barack Obama\",\n",
+ " \"Donald Trump\",\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def ordinal(n):\n",
+ " s = str(n)\n",
+ " if 10 < n < 20:\n",
+ " s += 'th'\n",
+ " elif n % 10 == 1:\n",
+ " s += 'st'\n",
+ " elif n % 10 == 2:\n",
+ " s += 'nd'\n",
+ " elif n % 10 == 3:\n",
+ " s += 'rd'\n",
+ " else:\n",
+ " s += 'th'\n",
+ " return s\n",
+ "\n",
+ "def ordgen():\n",
+ " i = 1\n",
+ " while True:\n",
+ " yield ordinal(i)\n",
+ " i += 1\n",
+ "name_first = []\n",
+ "num_first = []\n",
+ "for name, num in zip(presidents, ordgen()):\n",
+ " card = [name, num]\n",
+ " card2 = [num, name]\n",
+ " name_first.append(card)\n",
+ " num_first.append(card2)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "name_first"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import random\n",
+ "from IPython.display import clear_output\n",
+ "while True:\n",
+ " clear_output()\n",
+ " x, y = random.choice(name_first)\n",
+ " if input(x) != '':\n",
+ " break\n",
+ " if input(y) != '':\n",
+ " break"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "write_decks([make_deck(name_first, 'Name first'), make_deck(num_first, 'Number first')], 'presidents')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.7.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}