Created
July 21, 2017 12:26
-
-
Save mauriciosl/c597bfb102778edbbb59a603a9775649 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "cells": [ | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# Approval Engine with PyDatalog\n", | |
| "\n", | |
| "### The problem\n", | |
| "\n", | |
| "Create an algoritm that can tell you who's the best person to approve a document based on his approval limit, cost center and organization hierarchy.\n", | |
| "In this example, we have an organization with 2 cost centers, 3 members for each cost center and a CFO who's the indirect manager of the whole organization.\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 1, | |
| "metadata": { | |
| "collapsed": true | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "from pyDatalog import pyDatalog\n", | |
| "pyDatalog.create_terms(\"\"\"X,Y,Z,W,Amount,Person,Manager,CC,Limit,Someone,\n", | |
| " manager,indirect_manager,\n", | |
| " approval,can_approve,first_approval,\n", | |
| " costcenter,cost_center_approval,first_ccap\"\"\")" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 2, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "approval['Alice'] = 1000\n", | |
| "approval['Bob'] = 5000\n", | |
| "approval['Charlie'] = 10000\n", | |
| "\n", | |
| "approval['Anne'] = 1000\n", | |
| "approval['Bill'] = 5000\n", | |
| "approval['Chris'] = 10000\n", | |
| "\n", | |
| "approval['Daisy'] = float('inf') # Python 3 has infinity numbers ;)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 3, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Person \n", | |
| "-------\n", | |
| "Bob \n", | |
| "Bill \n", | |
| "Daisy \n", | |
| "Charlie\n", | |
| "Chris \n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "print((approval[Person] >= 2000))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 4, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "can_approve(Person,Amount) <= approval[1]>=(*,Pers" | |
| ] | |
| }, | |
| "execution_count": 4, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "can_approve(Person, Amount) <= (approval[Person] >= Amount)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 5, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Person \n", | |
| "-------\n", | |
| "Bob \n", | |
| "Bill \n", | |
| "Daisy \n", | |
| "Charlie\n", | |
| "Chris \n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "print(can_approve(Person, 2000))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 6, | |
| "metadata": { | |
| "collapsed": true | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "+(manager['Alice'] == 'Charlie')\n", | |
| "+(manager['Bob'] == 'Charlie')\n", | |
| "+(manager['Charlie'] == 'Daisy')\n", | |
| "+(manager['Anne'] == 'Chris')\n", | |
| "+(manager['Bill'] == 'Chris')\n", | |
| "+(manager['Chris'] == 'Daisy')" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 7, | |
| "metadata": { | |
| "scrolled": false | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Person\n", | |
| "------\n", | |
| "Bob \n", | |
| "Alice \n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "print(manager[Person] == 'Charlie')" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 8, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "indirect_manager(Person,Manager) <= manager[1]==(*" | |
| ] | |
| }, | |
| "execution_count": 8, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "indirect_manager(Person, Manager) <= (manager[Person] == Manager)\n", | |
| "indirect_manager(Person, Manager) <= (manager[Person] == Someone) & indirect_manager(Someone, Manager)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 9, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Manager\n", | |
| "-------\n", | |
| "Charlie\n", | |
| "Daisy \n", | |
| "Person \n", | |
| "-------\n", | |
| "Alice \n", | |
| "Bob \n", | |
| "Anne \n", | |
| "Bill \n", | |
| "Chris \n", | |
| "Charlie\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "print(indirect_manager('Alice', Manager))\n", | |
| "print(indirect_manager(Person, 'Daisy'))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 10, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "+(costcenter['Alice'] == 'A')\n", | |
| "+(costcenter['Bob'] == 'A')\n", | |
| "+(costcenter['Charlie'] == 'A')\n", | |
| "+(costcenter['Anne'] == 'B')\n", | |
| "+(costcenter['Bill'] == 'B')\n", | |
| "+(costcenter['Chris'] == 'B')" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 11, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Person \n", | |
| "-------\n", | |
| "Charlie\n", | |
| "Alice \n", | |
| "Bob \n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "print(costcenter[Person] == 'A')" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 12, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "first_approval[1]==!1(*,Amount,Person,Limit) <= ap" | |
| ] | |
| }, | |
| "execution_count": 12, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "\n", | |
| "(first_approval[Amount] == min_(Person, key=Limit)) <= ((approval[Person]==Limit) & can_approve(Person, Amount))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 13, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Person\n", | |
| "------\n", | |
| "Alice \n", | |
| "Person\n", | |
| "------\n", | |
| "Bob \n", | |
| "Person \n", | |
| "-------\n", | |
| "Charlie\n", | |
| "Person\n", | |
| "------\n", | |
| "Daisy \n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "print((first_approval[500]==Person))\n", | |
| "print((first_approval[2000]==Person))\n", | |
| "print((first_approval[6000]==Person))\n", | |
| "print((first_approval[15000]==Person))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 14, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "cost_center_approval(CC,Amount,Person) <= costcent" | |
| ] | |
| }, | |
| "execution_count": 14, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "cost_center_approval(CC, Amount, Person) <= ((costcenter[Person] == CC) & can_approve(Person, Amount))\n", | |
| "cost_center_approval(CC, Amount, Person) <= ((costcenter[Someone] == CC) &\n", | |
| " indirect_manager(Someone, Person) &\n", | |
| " can_approve(Person, Amount))\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 15, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "X \n", | |
| "-------\n", | |
| "Daisy \n", | |
| "Charlie\n", | |
| "Bob \n", | |
| "Alice \n", | |
| "X \n", | |
| "-------\n", | |
| "Daisy \n", | |
| "Charlie\n", | |
| "Bob \n", | |
| "X \n", | |
| "-------\n", | |
| "Daisy \n", | |
| "Charlie\n", | |
| "X \n", | |
| "-----\n", | |
| "Daisy\n", | |
| "X \n", | |
| "-----\n", | |
| "Daisy\n", | |
| "Chris\n", | |
| "Bill \n", | |
| "Anne \n", | |
| "X \n", | |
| "-----\n", | |
| "Daisy\n", | |
| "Chris\n", | |
| "Bill \n", | |
| "X \n", | |
| "-----\n", | |
| "Daisy\n", | |
| "Chris\n", | |
| "X \n", | |
| "-----\n", | |
| "Daisy\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "print(cost_center_approval('A', 500, X))\n", | |
| "print(cost_center_approval('A', 2000, X))\n", | |
| "print(cost_center_approval('A', 7000, X))\n", | |
| "print(cost_center_approval('A', 11000, X))\n", | |
| "\n", | |
| "print(cost_center_approval('B', 500, X))\n", | |
| "print(cost_center_approval('B', 2000, X))\n", | |
| "print(cost_center_approval('B', 7000, X))\n", | |
| "print(cost_center_approval('B', 11000, X))\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 16, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "first_ccap[2]==!2(*,CC,Amount,Person,Limit) <= cos" | |
| ] | |
| }, | |
| "execution_count": 16, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "(first_ccap[CC, Amount] == min_(Person, key=Limit)) <= (cost_center_approval(CC, Amount, Person) &\n", | |
| " (approval[Person]==Limit))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 17, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "X \n", | |
| "-----\n", | |
| "Alice\n", | |
| "X \n", | |
| "---\n", | |
| "Bob\n", | |
| "X \n", | |
| "-------\n", | |
| "Charlie\n", | |
| "X \n", | |
| "-----\n", | |
| "Daisy\n", | |
| "X \n", | |
| "----\n", | |
| "Anne\n", | |
| "X \n", | |
| "----\n", | |
| "Bill\n", | |
| "X \n", | |
| "-----\n", | |
| "Chris\n", | |
| "X \n", | |
| "-----\n", | |
| "Daisy\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "print(first_ccap['A', 500] == X)\n", | |
| "print(first_ccap['A', 2000] == X)\n", | |
| "print(first_ccap['A', 7000] == X)\n", | |
| "print(first_ccap['A', 11000] == X)\n", | |
| "\n", | |
| "print(first_ccap['B', 500] == X)\n", | |
| "print(first_ccap['B', 2000] == X)\n", | |
| "print(first_ccap['B', 7000] == X)\n", | |
| "print(first_ccap['B', 11000] == X)" | |
| ] | |
| }, | |
| { | |
| "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 | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment