Skip to content

Instantly share code, notes, and snippets.

@mauriciosl
Created July 21, 2017 12:26
Show Gist options
  • Save mauriciosl/c597bfb102778edbbb59a603a9775649 to your computer and use it in GitHub Desktop.
Save mauriciosl/c597bfb102778edbbb59a603a9775649 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"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