![]() | |||||||||||||
| |||||||||||||
Python notebooks Description Python notebooks available in the GitHub repository python-notebooks.
Source Files By clicking on a file name, a preview is opened at the bottom of this page. Data Files
callback_newnode.ipynb { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# **Vizualizing the Branch-and-Bound tree of a problem after (partially) solving it**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "***callback_newnode.ipynb***\n", "\n", "This example shows how to visualize the Branch-and-Bound (B&B) tree of a problem after (partially) solving it. It assumes that all variables to be branched on in the problem are binary variables.\n", "\n", "© Copyright 2025 Fair Isaac Corporation\n", "\n", "Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.\n", " \n", "Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\n", "\n", "This example uses FICO® Xpress software. By running it, you agree to the Community License terms of the [Xpress Shrinkwrap License Agreement](https://www.fico.com/en/shrinkwrap-license-agreement-fico-xpress-optimization-suite-on-premises) with respect to the FICO® Xpress software. See the [licensing options](https://www.fico.com/en/fico-xpress-trial-and-licensing-options) overview for additional details and information about obtaining a paid license." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Install the xpress package\n", "%pip install -q xpress" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this example, we read a problem from an external file and define **a callback function to save information of each node of the B&B tree during an optimization run**, which stops after a pre-defined number of nodes have been explored. The tree is plotted after the solve. \n", "\n", "*Note: Callback functions are user–defined routines to be specified to the Optimizer which are called at specific stages during the optimization process, prompting the Optimizer to return to the user's program before continuing with the solution algorithm. Check out the online documentation to learn more about [using callback functions](https://www.fico.com/fico-xpress-optimization/docs/latest/solver/optimizer/python/HTML/chCallbacks.html).*\n", "\n", "This example uses the [problem.addcbnewnode](https://www.fico.com/fico-xpress-optimization/docs/latest/solver/optimizer/python/HTML/problem.addcbnewnode.html) method, which declares a callback function that will be called every time a new node is created during the branch and bound search. \n", "\n", "\n", "The *storeBBnode* function is defined in the code cell below to store information about each new node in the tree. This is the only operation that needs to be carried out at every node: given a node number (*newnode*), and its parent (*parent*), we store the information in the 'left' and 'right' arrays so that at the end of the B&B we have an explicit B&B tree stored in these arrays." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import networkx as nx\n", "import xpress as xp\n", "import time\n", "\n", "from matplotlib import pyplot as plt\n", "\n", "def storeBBnode(prob, Tree, parent, newnode, branch):\n", " \"\"\"Store the branch-and-bound tree in a pair of dictionaries for left and right sides of branches\"\"\"\n", " \n", " nodes[newnode] = len(nodes) + 1 # store the nodes' labels in the order they are found\n", "\n", " if branch == 0: # check if left branch\n", " left[parent] = newnode\n", " else:\n", " right[parent] = newnode" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We now set up the B&B tree data objects and create a problem. We populate it by reading in a local matrix file. \n", "\n", "We then specify the node callback with [problem.addcbnewnode](https://www.fico.com/fico-xpress-optimization/docs/latest/solver/optimizer/python/HTML/problem.addcbnewnode.html) so that we can collect information at each new node. The first argument must be the function defined previously, while the second argumentis a data object (for example the graph *T*), which in this case is not used by the callback function.\n", "\n", "Furthermore, the [maxnode](https://www.fico.com/fico-xpress-optimization/docs/latest/solver/optimizer/HTML/MAXNODE.html) control defines the maximum number of nodes (10) that are explored in the B&B tree. This value is not a hard limit, particularly when exploring nodes using multiple threads. Therefore, we allow the use of only one thread via the [threads](https://www.fico.com/fico-xpress-optimization/docs/latest/solver/optimizer/HTML/THREADS.html) control, to ensure that the MAXNODE limit is fulfilled when searching the B&B tree." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "T = nx.Graph() # define a networkx graph to store the branch-and-bound tree\n", "card_subtree = {} # to store the cardinality of the subtree rooted at each node\n", "pos = {} # to store the position of each node in the plot\n", "\n", "# Define the dictionaries to store the left and right children of each node\n", "left = {}\n", "right = {}\n", "nodes = {1: 1} # dictionary for labeling the nodes in the order they are found, root node indexed at 1\n", "\n", "start_time = time.time()\n", "\n", "p = xp.problem()\n", "\n", "p.read('mc11.mps.gz')\n", "\n", "p.addcbnewnode(storeBBnode, T)\n", "\n", "p.controls.maxnode = 10 # limit the number of nodes that will be explored\n", "p.controls.threads = 1 # limit the number of threads to 1 to ensure that the maxnode limit is respected\n", "\n", "p.optimize()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The code cell below defines two functions: \n", " - the function *postorder_count*, which computes the cardinality of a subtree for each node by recursively counting nodes.\n", " - the function *setpos* that sets a position for each node in the graph depending on the cardinality of each subtree.\n", "\n", "\n", "The nodes and corresponding edges are then plotted in a tree with numbered nodes in the order they were found by Xpress Optimizer, using the tree graph drawing functionality from the *network* package." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "image/png": "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5xAR5OdVpskEpXlOEgBItx+pi5jXmFsbwtnZCesizpl9vayfk5HkPT+S/DT7wVZoHVQZTy7YrpK78vPX/rOqmkD1ip65Syw61/dTtRu/2Hjipp8vy/Nz4/VW3OdUErzeSAu84oioRKRjx4LwaLMs5kc61YaPpxuq+lybxu7ZJCB3SvvrzVE4cPqS+pOXaepb6u2Zgk2poRfWKABaP6eino9M0//+bFf8tue0qm0oujWsglsbB+CfI/FYcei/4Fmr52QkpvPzvzuboHfTalh5ME4tK5Bs6LxMReY//uco7gytju+e7IgvN0WpkeOnutXDoTOX8OMO80QXLc5P3uvt5b5Ni/WcalYqhwGtrn2v+fXRVxnZF6cuXMmt68rrjbTCgJKISmRIhyB89W+U2dee6loPtSr/1z/4jmbV1R+xdNcpJKdnFWvb8gb7cMcgaP2cino+l9IyVeHsLg38cW/rmnBxclLFqN/567Bq83f1qvbPyUhM56dp9Ws1JHs3rar+3MgUfMmo5APz/sUrfZvixduD1drcNYfj8eYfB29aP6nF+cl7vRX3OQVWLocJff7rLCVM/99yPDE3oOT1RlpxuiqNQYmISmDo/HBsPp5Y6gLn+ZGRlc71/LBgeAdowYjPyUiMdn6M9nyImAZGRCU2bUCoWkNoTbI92a5WjPicjMRo58doz4eIASURlVigr5fqemNN0rZQtqsVIz4nIzHa+THa8yFiQElEpTK4XRAm9GlklW1N7BOMB9ppv+7LiM/JSIx2foz2fMixcQ0lEVlk8bYYvPbbAWTlXC3RejBZ7yVTdDKqorc3QiM+JyMx2vkx2vMhx8SAkogsJjUkJy/Zhw1HE9SbXGFviqbvd23gr9Z76XWKzojPyUiMdn6M9nzI8TCgJCKriYxLxqLwGKyNiEdMYqpZNxCn6wWXpUaelDVpEFAB9sCIz8lIjHZ+jPZ8yHEwoCQim0hJz0JUYgoysnJUX2FpBWfv3TuM+JyMxGjnx2jPh4yNASURERERWYRZ3kRERERkEQaURERERGQRBpREREREZBEGlERERERkEQaURERERGQRBpREREREZBEGlERERERkEQaURERERGQRBpREREREZBEGlERERERkEQaURERERGQRBpREREREZBEGlERERERkEQaURERERGQRBpREREREZBEGlERERERkEQaURERERGQRBpREREREZBEGlERERERkEQaURERERGQRBpREREREZBEGlERERERkEQaURERERGQRBpREREREZBEGlERERERkEQaURERERGQRBpREREREZBEGlERERERkEQaURERERGQRBpREREREZBEGlERERERkEQaURERERGQRBpREREREZBEGlERERERkEQaURERERGQRBpREREREZBEGlEREREQES/w/zZQFzB0nwFEAAAAASUVORK5CYII=", "text/plain": [ "<Figure size 640x480 with 1 Axes>" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "def postorder_count(node):\n", " \"\"\"Recursively count nodes to compute the cardinality of a subtree for\n", " each node\"\"\"\n", "\n", " card = 0\n", "\n", " if node in left.keys(): # see if node has a left key\n", " postorder_count(left[node])\n", " card += card_subtree[left[node]]\n", "\n", " if node in right.keys(): # see if node has a right key\n", " postorder_count(right[node])\n", " card += card_subtree[right[node]]\n", "\n", " card_subtree[node] = 1 + card\n", "\n", "def setpos(T, node, curpos, st_width, depth):\n", "\n", " \"\"\"\n", " Set position depending on cardinality of each subtree\n", " \"\"\"\n", "\n", " # Special condition: we are at the root\n", " if node == 1:\n", " T.add_node(node, pos=(0.5, 1))\n", "\n", " # Use a convex combination of subtree comparison and depth to assign a width to each subtree\n", " alpha = 0.01\n", "\n", " if node in left.keys():\n", "\n", " # X position in the graph should not just depend on depth,\n", " # otherwise we'd see a long and thin subtree and it would just\n", " # look like a path\n", "\n", " leftwidth = st_width * (alpha * .7 + (1 - alpha) *\n", " card_subtree[left[node]] /\n", " card_subtree[node])\n", " leftpos = curpos - (st_width - leftwidth) / 2\n", "\n", " T.add_node(left[node], pos=(leftpos, - depth))\n", " T.add_edge(node, left[node])\n", " setpos(T, left[node], leftpos, leftwidth, depth + 1)\n", "\n", " if node in right.keys():\n", "\n", " rightwidth = st_width * (alpha * .5 + (1 - alpha) *\n", " card_subtree[right[node]] /\n", " card_subtree[node])\n", " rightpos = curpos + (st_width - rightwidth) / 2\n", "\n", " T.add_node(right[node], pos=(rightpos, - depth))\n", " T.add_edge(node, right[node])\n", " setpos(T, right[node], rightpos, rightwidth, depth + 1)\n", "\n", "\n", "postorder_count(1) # assign card_subtree to each node\n", "\n", "# Determine the position of each node depending on subtree cardinalities\n", "setpos(T, 1, 0.5, 1, 0)\n", "\n", "pos = nx.get_node_attributes(T, 'pos')\n", "\n", "nx.draw(T, pos, labels=nodes, font_color='white') # create B&B tree representation\n", "plt.show() # display the tree" ] } ], "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.12.9" } }, "nbformat": 4, "nbformat_minor": 2 }
| |||||||||||||
© Copyright 2025 Fair Isaac Corporation. |