TP-recherche-operationnelle/notebook.ipynb

420 lines
13 KiB
Plaintext
Raw Normal View History

2021-11-26 13:51:01 +00:00
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# TP 2-3 : Branch-and-bound applied to a knapsack problem"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Initialisation (à faire une seule fois)"
]
},
{
"cell_type": "code",
2021-11-27 10:20:11 +00:00
"execution_count": 1,
2021-11-26 13:51:01 +00:00
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m registry at `~/.julia/registries/General`\n",
2021-11-26 13:51:01 +00:00
"\u001b[32m\u001b[1m Resolving\u001b[22m\u001b[39m package versions...\n",
"\u001b[32m\u001b[1m No Changes\u001b[22m\u001b[39m to `~/.julia/environments/v1.6/Project.toml`\n",
"\u001b[32m\u001b[1m No Changes\u001b[22m\u001b[39m to `~/.julia/environments/v1.6/Manifest.toml`\n",
2021-11-26 16:57:38 +00:00
"\u001b[32m\u001b[1mPrecompiling\u001b[22m\u001b[39m project...\n",
"\u001b[32m ✓ \u001b[39mTestOptinum\n",
" 1 dependency successfully precompiled in 6 seconds (158 already precompiled)\n",
2021-11-26 13:51:01 +00:00
"\u001b[32m\u001b[1m Resolving\u001b[22m\u001b[39m package versions...\n",
"\u001b[32m\u001b[1m No Changes\u001b[22m\u001b[39m to `~/.julia/environments/v1.6/Project.toml`\n",
2021-11-26 16:57:38 +00:00
"\u001b[32m\u001b[1m No Changes\u001b[22m\u001b[39m to `~/.julia/environments/v1.6/Manifest.toml`\n",
"\u001b[32m\u001b[1mPrecompiling\u001b[22m\u001b[39m project...\n",
"\u001b[32m ✓ \u001b[39mTestOptinum\n",
2021-11-27 10:20:11 +00:00
" 1 dependency successfully precompiled in 3 seconds (158 already precompiled)\n"
2021-11-26 13:51:01 +00:00
]
}
],
"source": [
"import Pkg; \n",
"Pkg.add(\"GraphRecipes\"); Pkg.add(\"Plots\"); \n",
"using GraphRecipes, Plots #only used to visualize the search tree at the end of the branch-and-bound"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Récupération des données"
]
},
{
"cell_type": "code",
2021-11-27 10:20:11 +00:00
"execution_count": 1,
2021-11-26 13:51:01 +00:00
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
2021-11-26 16:57:38 +00:00
"readKnapInstance (generic function with 1 method)"
2021-11-26 13:51:01 +00:00
]
},
2021-11-27 10:20:11 +00:00
"execution_count": 1,
2021-11-26 13:51:01 +00:00
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function readKnapInstance(filename)\n",
2021-11-26 13:51:01 +00:00
" price=[]\n",
" weight=[]\n",
" capacity = -1\n",
2021-11-26 13:51:01 +00:00
" open(filename) do f\n",
" for i in 1:3\n",
" tok = split(readline(f))\n",
" if (tok[1] == \"ListPrices=\")\n",
" for i in 2:(length(tok)-1)\n",
" push!(price,parse(Int64, tok[i]))\n",
" end\n",
" elseif (tok[1] == \"ListWeights=\")\n",
2021-11-26 13:51:01 +00:00
" for i in 2:(length(tok)-1)\n",
" push!(weight,parse(Int64, tok[i]))\n",
" end\n",
" elseif (tok[1] == \"Capacity=\")\n",
" capacity = parse(Int64, tok[2])\n",
2021-11-26 13:51:01 +00:00
" else\n",
" println(\"Unknown read :\", tok)\n",
" end \n",
" end\n",
" end\n",
" \n",
2021-11-26 13:51:01 +00:00
" return price, weight, capacity\n",
"end\n",
"\n",
"# readKnapInstance(\"data/test.opb\")\n",
"# readKnapInstance(\"data/almost_strongly_correlated/knapPI_5_50_1000_1_-2096.opb\")"
2021-11-26 13:51:01 +00:00
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Procédure d'application des tests de sondabilités TA, TO et TR pour le cas de la relaxation linéaire"
]
},
{
"cell_type": "code",
2021-11-27 10:20:11 +00:00
"execution_count": 2,
2021-11-26 13:51:01 +00:00
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"TestsSondabilite_relaxlin (generic function with 1 method)"
]
},
2021-11-27 10:20:11 +00:00
"execution_count": 2,
2021-11-26 13:51:01 +00:00
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
2021-11-27 10:20:11 +00:00
"function TestsSondabilite_relaxlin(x, price, weight, capacity, BestProfit, Bestsol, affich)\n",
2021-11-26 13:51:01 +00:00
" TA, TO, TR = false, false, false\n",
" if (!Constraints(x, weight, capacity)) # Test de faisabilite\n",
" TA = true\n",
2021-11-27 10:20:11 +00:00
" if affich\n",
" println(\"TA\")\n",
" end\n",
" elseif (Objective(x, price) <= BestProfit) # Test d'optimalite\n",
" TO = true\n",
2021-11-27 10:20:11 +00:00
" if affich\n",
" println(\"TO\")\n",
" end\n",
" elseif (AllDef(x)) # Test de resolution\n",
" TR = true\n",
2021-11-27 10:20:11 +00:00
" if affich\n",
" println(\"TR : solution \", \" de profit \", Objective(x, price))\n",
" end\n",
2021-11-27 10:44:55 +00:00
" if (Objective(x, price) >= BestProfit) # Le profit de la solution trouvée est meilleur que les autres\n",
2021-11-27 10:20:11 +00:00
" if affich\n",
" println(\"\\t-> Cette solution a un meilleur profit.\")\n",
" end\n",
2021-11-27 10:44:55 +00:00
" # On remplace la solution et le profit par les nouvelles valeurs\n",
" Bestsol = x\n",
" BestProfit = Objective(x, price)\n",
2021-11-27 10:20:11 +00:00
" else\n",
" if affich\n",
" println(\"\\t-> Cette solution est moins bonne.\")\n",
" end\n",
2021-11-26 13:51:01 +00:00
" end\n",
" else\n",
2021-11-27 10:20:11 +00:00
" if affich \n",
" println(\"non sondable\")\n",
" end\n",
" end\n",
" if affich\n",
" println(\"\\n\")\n",
2021-11-26 13:51:01 +00:00
" end\n",
" TA, TO, TR, Bestsol, BestProfit\n",
"end"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Procédure de séparation et stratégie d'exploration permettant de se placer au prochain noeud à traiter"
]
},
{
"cell_type": "code",
2021-11-27 10:20:11 +00:00
"execution_count": 3,
2021-11-26 13:51:01 +00:00
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"ExplorerAutreNoeud_relaxlin (generic function with 1 method)"
]
},
2021-11-27 10:20:11 +00:00
"execution_count": 3,
2021-11-26 13:51:01 +00:00
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\n",
2021-11-26 16:57:38 +00:00
"function SeparerNoeud_relaxlin(price, listvars, listvals)\n",
2021-11-27 10:44:55 +00:00
" # Le noeud est non-sondable. Appliquer le critère de séparation pour le séparer en sous-noeuds \n",
2021-11-26 16:57:38 +00:00
"\n",
" # Cas du noeud le plus à gauche\n",
2021-11-27 10:44:55 +00:00
"\n",
" # On sépare le noeud actuel en 2 sous-noeuds\n",
2021-11-27 10:20:11 +00:00
" predX = pop!(listvars)\n",
" nextX0 = copy(predX)\n",
" nextX1 = copy(predX)\n",
2021-11-27 10:44:55 +00:00
"\n",
" # On initialise leurs valeurs à zéro\n",
2021-11-26 16:57:38 +00:00
" val0 = 0\n",
" val1 = 0\n",
2021-11-27 10:44:55 +00:00
"\n",
" # On fixe la nouvelle variable des deux sous-noeuds\n",
" n = length(predX)\n",
2021-11-26 16:57:38 +00:00
" for i in 1:n\n",
" if predX[i] == -1\n",
2021-11-27 10:44:55 +00:00
" # L'un a zéro\n",
2021-11-26 16:57:38 +00:00
" nextX0[i] = 0\n",
2021-11-27 10:44:55 +00:00
" # L'autre a un\n",
2021-11-26 16:57:38 +00:00
" nextX1[i] = 1\n",
2021-11-26 13:51:01 +00:00
"\n",
2021-11-27 10:44:55 +00:00
" # On calcule leurs valeurs\n",
2021-11-26 16:57:38 +00:00
" val0 = Objective(nextX0, price)\n",
" val1 = Objective(nextX1, price)\n",
" break\n",
" end\n",
" end\n",
2021-11-27 10:44:55 +00:00
" # On ajoute les sous-noeuds a la pile des noeuds a explorer\n",
2021-11-26 16:57:38 +00:00
" push!(listvars, nextX1)\n",
2021-11-27 10:20:11 +00:00
" push!(listvars, nextX0)\n",
2021-11-27 10:44:55 +00:00
"\n",
" # On ajoute aussi leurs valeurs\n",
2021-11-26 16:57:38 +00:00
" push!(listvals, val1)\n",
2021-11-27 10:20:11 +00:00
" push!(listvals, val0)\n",
2021-11-27 10:44:55 +00:00
"\n",
2021-11-26 13:51:01 +00:00
" listvars, listvals\n",
"end\n",
"\n",
"\n",
2021-11-26 16:57:38 +00:00
"function ExplorerAutreNoeud_relaxlin(listvars, listvals)\n",
2021-11-27 10:44:55 +00:00
" # Le noeud est sondable, on l'enlève de la pile des noeuds à sonder\n",
2021-11-26 13:51:01 +00:00
" \n",
2021-11-26 16:57:38 +00:00
" stop = false\n",
" if (length(listvars) > 1)\n",
2021-11-27 10:44:55 +00:00
" # On passe au noeud suivant\n",
2021-11-26 16:57:38 +00:00
" var = pop!(listvars)\n",
" val = pop!(listvals)\n",
2021-11-26 13:51:01 +00:00
" else\n",
2021-11-27 10:44:55 +00:00
" # Il n'y a pas d'autre noeud\n",
2021-11-26 13:51:01 +00:00
" println(\"\\nFINISHED\")\n",
2021-11-26 16:57:38 +00:00
" stop = true\n",
2021-11-26 13:51:01 +00:00
" end\n",
2021-11-27 10:44:55 +00:00
"\n",
2021-11-26 16:57:38 +00:00
" listvars, listvals, stop \n",
2021-11-26 13:51:01 +00:00
"end"
]
},
{
"cell_type": "code",
2021-11-27 10:20:11 +00:00
"execution_count": 4,
2021-11-26 13:51:01 +00:00
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
2021-11-27 10:20:11 +00:00
"AllDef (generic function with 1 method)"
2021-11-26 13:51:01 +00:00
]
},
2021-11-27 10:20:11 +00:00
"execution_count": 4,
2021-11-26 13:51:01 +00:00
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
2021-11-27 10:44:55 +00:00
"# Fonction objectif que l'on souhaite maximiser/minimiser (évalué dans le meilleur des cas)\n",
"Objective(x, price) = \n",
" sum(\n",
" if x[i] < 0\n",
2021-11-27 10:20:11 +00:00
" price[i]\n",
" else\n",
" price[i]*x[i] \n",
" end\n",
" for i in 1:length(x)\n",
" )\n",
2021-11-26 13:51:01 +00:00
"\n",
2021-11-27 10:44:55 +00:00
"# Fonction permettant de vérfier toutes les contraintes du modèle (dans le meilleur des cas)\n",
"Constraints(x, weight, capacity) =\n",
" sum(\n",
" if x[i] < 0\n",
" 0\n",
" else \n",
" weight[i]*x[i]\n",
2021-11-26 13:51:01 +00:00
" end\n",
" for i in 1:length(x)\n",
" ) <= capacity\n",
2021-11-26 13:51:01 +00:00
"\n",
2021-11-27 10:44:55 +00:00
"# Fonction qui nous dis si toutes les variables de x sont fixées\n",
2021-11-27 10:20:11 +00:00
"function AllDef(x)\n",
" for i in 1:length(x)\n",
" if x[i] < 0\n",
" return false\n",
" end\n",
2021-11-26 13:51:01 +00:00
" end\n",
2021-11-27 10:20:11 +00:00
" return true\n",
"end"
2021-11-26 13:51:01 +00:00
]
2021-11-26 16:57:38 +00:00
},
{
"cell_type": "code",
2021-11-27 10:44:55 +00:00
"execution_count": 5,
2021-11-26 16:57:38 +00:00
"metadata": {},
"outputs": [
{
2021-11-27 10:44:55 +00:00
"name": "stdout",
"output_type": "stream",
"text": [
"Capacity : 994 | Number of objects : 50\n",
"\n",
"----------\n",
"Node n°1001 : \n",
"\n",
"Previous Solution memorized with bestprofit 994\n",
"\n",
"non sondable\n",
"\n",
"\n",
"\n",
"FINISHED\n",
"\n",
"******\n",
"\n",
"Optimal value = 994\n",
"\n",
"Optimal x=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
2021-11-26 16:57:38 +00:00
]
}
],
"source": [
"function SolveKnapInstance(filename)\n",
"\n",
" price, weight, capacity = readKnapInstance(filename)\n",
"\n",
2021-11-27 10:20:11 +00:00
" println(\"Capacity : \", capacity, \" | Number of objects : \", length(price), \"\\n\")\n",
"\n",
2021-11-27 10:44:55 +00:00
" # Liste des variable pour naviguer de noeuds en noeuds\n",
2021-11-26 16:57:38 +00:00
" listvars=[]\n",
" listvals=[]\n",
"\n",
2021-11-27 10:44:55 +00:00
" # La meilleur solution et sa valeur\n",
2021-11-26 16:57:38 +00:00
" BestProfit=-1\n",
" Bestsol=[]\n",
"\n",
2021-11-27 10:44:55 +00:00
" # Compter le nombre de noeud explorés\n",
" current_node_number = 0\n",
"\n",
2021-11-26 16:57:38 +00:00
" stop = false\n",
2021-11-27 10:20:11 +00:00
" affich = false\n",
2021-11-26 16:57:38 +00:00
"\n",
2021-11-27 10:44:55 +00:00
" # On ajoute le premier noeud à explorer (la racine)\n",
2021-11-26 16:57:38 +00:00
" push!(listvars, [-1 for p in price])\n",
2021-11-27 10:20:11 +00:00
" push!(listvals, Objective(last(listvars), price))\n",
2021-11-26 16:57:38 +00:00
"\n",
" while (!stop)\n",
2021-11-27 10:44:55 +00:00
" # Le noeud actuel\n",
2021-11-27 10:20:11 +00:00
" x = last(listvars)\n",
2021-11-26 16:57:38 +00:00
"\n",
2021-11-27 10:20:11 +00:00
" if affich\n",
" print(\"----------\\nNode n°\", current_node_number, \" : \")\n",
" println(\" \")\n",
" println(\"\\nPrevious Solution memorized \", \" with bestprofit \", BestProfit, \"\\n\")\n",
2021-11-26 16:57:38 +00:00
" end\n",
"\n",
2021-11-27 10:44:55 +00:00
" # Test de sondabilité du noeud actuel\n",
" # -> On mets a jour la solution et sa valeur si besoin\n",
2021-11-27 10:20:11 +00:00
" TA, TO, TR, Bestsol, BestProfit = TestsSondabilite_relaxlin(x, price, weight, capacity, BestProfit, Bestsol, affich)\n",
2021-11-26 16:57:38 +00:00
" \n",
" is_node_sondable = TA || TO || TR\n",
" if (!is_node_sondable)\n",
2021-11-27 10:44:55 +00:00
" # Le noeud n'est pas sondable, on le sépare en 2 sous-noeuds\n",
2021-11-26 16:57:38 +00:00
" listvars, listvals = SeparerNoeud_relaxlin(price, listvars, listvals)\n",
" else\n",
2021-11-27 10:44:55 +00:00
" # Le noeud est sondable, on passe au noeud suivant\n",
2021-11-26 16:57:38 +00:00
" listvars, listvals, stop = ExplorerAutreNoeud_relaxlin(listvars, listvals)\n",
" end\n",
"\n",
2021-11-27 10:44:55 +00:00
" # On évite de spammer l'output donc on n'affiche pas tout les résultats\n",
" if current_node_number % 1000000 == 100\n",
2021-11-27 10:20:11 +00:00
" affich = true\n",
" else\n",
" affich = false\n",
" end\n",
2021-11-27 10:44:55 +00:00
"\n",
2021-11-26 16:57:38 +00:00
" current_node_number += 1\n",
" end\n",
"\n",
" println(\"\\n******\\n\\nOptimal value = \", BestProfit, \"\\n\\nOptimal x=\", Bestsol)\n",
"\n",
"end\n",
"\n",
2021-11-27 10:44:55 +00:00
"SolveKnapInstance(\"data/subset_sum/knapPI_6_50_1000_1_-994.opb\")"
2021-11-26 16:57:38 +00:00
]
2021-11-27 10:20:11 +00:00
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
2021-11-26 13:51:01 +00:00
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.6.3",
"language": "julia",
"name": "julia-1.6"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
2021-11-26 16:57:38 +00:00
"version": "1.6.4"
2021-11-26 13:51:01 +00:00
}
},
"nbformat": 4,
"nbformat_minor": 4
}