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