├── .circleci └── config.yml ├── .devcontainer └── devcontainer.json ├── LICENSE ├── README.md ├── maximum_cut.py ├── maximum_cut_ising.py ├── readme_imgs ├── QUBO.png ├── cut_examples.png └── final_QUBO.png ├── requirements.txt └── tests ├── __init__.py └── test_maximum_cut.py /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | dwave: dwave/orb-examples@2 5 | 6 | workflows: 7 | version: 2.1 8 | tests: 9 | jobs: 10 | - dwave/test-linux 11 | - dwave/test-osx 12 | - dwave/test-win 13 | 14 | weekly: 15 | triggers: 16 | - schedule: 17 | cron: "0 23 * * 4" 18 | filters: 19 | branches: 20 | only: 21 | - master 22 | - main 23 | jobs: 24 | - dwave/test-linux: 25 | integration-tests: "canary" 26 | - dwave/test-osx: 27 | integration-tests: "skip" 28 | - dwave/test-win: 29 | integration-tests: "skip" 30 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/debian 3 | { 4 | "name": "Ocean Development Environment", 5 | 6 | // python 3.11 on debian, with latest Ocean and optional packages 7 | // source repo: https://github.com/dwavesystems/ocean-dev-docker 8 | "image": "docker.io/dwavesys/ocean-dev:latest", 9 | 10 | // install repo requirements on create and content update 11 | "updateContentCommand": "pip install -r requirements.txt", 12 | 13 | // forward/expose container services (relevant only when run locally) 14 | "forwardPorts": [ 15 | // dwave-inspector web app 16 | 18000, 18001, 18002, 18003, 18004, 17 | // OAuth connect redirect URIs 18 | 36000, 36001, 36002, 36003, 36004 19 | ], 20 | 21 | "portsAttributes": { 22 | "18000-18004": { 23 | "label": "D-Wave Problem Inspector", 24 | "requireLocalPort": true 25 | }, 26 | "36000-36004": { 27 | "label": "OAuth 2.0 authorization code redirect URI", 28 | "requireLocalPort": true 29 | } 30 | }, 31 | 32 | // Configure tool-specific properties. 33 | "customizations": { 34 | // Configure properties specific to VS Code. 35 | "vscode": { 36 | // Set *default* container specific settings.json values on container create. 37 | "settings": { 38 | "workbench": { 39 | "editorAssociations": { 40 | "*.md": "vscode.markdown.preview.editor" 41 | }, 42 | "startupEditor": "readme" 43 | } 44 | }, 45 | "extensions": [ 46 | "ms-python.python", 47 | "ms-toolsai.jupyter" 48 | ] 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Open in GitHub Codespaces]( 2 | https://img.shields.io/badge/Open%20in%20GitHub%20Codespaces-333?logo=github)]( 3 | https://codespaces.new/dwave-examples/maximum-cut?quickstart=1) 4 | [![Linux/Mac/Windows build status]( 5 | https://circleci.com/gh/dwave-examples/maximum-cut.svg?style=shield)]( 6 | https://circleci.com/gh/dwave-examples/maximum-cut) 7 | 8 | # Maximum Cut 9 | 10 | In this demo, we explore the maximum cut problem. This problem has a wide 11 | variety of real-world applications. 12 | 13 | For example, suppose that we have a set of different computers, each with 14 | different types of connections. Some computers have bluetooth, some have USB 15 | ports, HDMI ports, etc. We want to split our set of computers into two groups 16 | for two different projects, but it's very important that the two groups can 17 | connect to each other. The problem is sometimes the wires and connections don't 18 | work! How can we be sure that we have the best chance at remaining connected? 19 | 20 | One way to solve this problem is with the maximum cut problem. If we think of 21 | our set of computers as a graph (a node/vertex for each computer), and draw an 22 | edge between computers that can connect to each other, we have a model of our 23 | network. If we look for a maximum cut in our graph, then we are looking for a 24 | way to split the nodes into two groups so that there are as many edges as 25 | possible between the groups. In our computer set, this means that we have two 26 | groups with as many connections as possible between the two groups. Now if one 27 | connection goes down, we have many more to use! This way we have created a more 28 | resilient network by providing many redundant connections between groups in case 29 | one connection fails. 30 | 31 | Below we see a simple network of five nodes and three different ways to split 32 | the set of nodes into two groups. The dashed edges in each graph highlight the 33 | cut edges. 34 | 35 | ![Cut examples](readme_imgs/cut_examples.png "Cut examples") 36 | 37 | We will run the maximum cut problem on the network shown above to find the best 38 | way to split the network into two groups to maximize the number of cut edges. 39 | 40 | ## Usage 41 | 42 | To run the demo, type: 43 | ```bash 44 | python maximum_cut.py 45 | ``` 46 | 47 | After running, output will be printed to the command line that provides a list 48 | of nodes in each set (labeled sets S0 and S1), the energy corresponding to the 49 | given solution, and the cut size of the given solution. In addition, there will 50 | be a visual of the lowest energy solution stored in `maxcut_plot.png`. 51 | 52 | ## Code Overview 53 | 54 | The code implements a QUBO formulation of this problem. 55 | 56 | The answer that we are looking for is a partition of the nodes in the graph, so 57 | we will assign a binary variable for each node, i.e. variable x_i denotes 58 | whether node i is in one subset (call it Subset 0) or the other (Subset 1). 59 | 60 | The objective function that we are looking to optimize is maximizing the number 61 | of cut edges. To count how many cut edges we have given a partition of the 62 | nodes (assignment of our binary variables), we consider a single edge in a graph 63 | in the table below. We only want to count an edge if the endpoints are in 64 | different subsets, and so we assign a 1 for the edge_score column in this case 65 | and a 0 otherwise. 66 | 67 | | x_i | x_j | edge_score (i,j) | 68 | | :---: | :---: | :---------------:| 69 | | 0 | 0 | 0 | 70 | | 0 | 1 | 1 | 71 | | 1 | 0 | 1 | 72 | | 1 | 1 | 0 | 73 | 74 | From this table, we see that we can use the expression x_i+x_j-2x_ix_j to 75 | calculate the edge_score column in our table. Now for our entire graph, our 76 | objective function can be written as shown below, where the sum is over all 77 | edges in the graph. 78 | 79 | ![QUBO](readme_imgs/QUBO.png "QUBO") 80 | 81 | Since our system is used to minimize an objective function, we must convert this 82 | maximization problem to a minimization problem by multiplying the expression by 83 | -1. Our final QUBO expression is the following. 84 | 85 | ![Final QUBO](readme_imgs/final_QUBO.png "Final QUBO") 86 | 87 | For the graph shown above, this QUBO results in the following Q matrix. In the 88 | Q matrix (implemented as a dictionary using Ocean), we put the coefficients on 89 | the linear terms in our QUBO along the diagonal and the quadratic terms on the 90 | off-diagonal. 91 | 92 | | | x_0 | x_1 | x_2 | x_3 | x_4 | 93 | |:---:|:---:|:---:|:---:|:---:|:---:| 94 | | x_0 | -2 | 2 | 2 | 0 | 0 | 95 | | x_1 | 0 | -2 | 0 | 2 | 0 | 96 | | x_2 | 0 | 0 | -3 | 2 | 2 | 97 | | x_3 | 0 | 0 | 0 | -3 | 2 | 98 | | x_4 | 0 | 0 | 0 | 0 | -2 | 99 | 100 | In the code, we create this Q matrix as a dictionary iteratively, looping over 101 | the edges in our graph just as we see in the summation of our QUBO expression. 102 | 103 | There are two parameters to be set by the user in this code: chain strength and 104 | number of reads. Since this is a small problem, we set a low number of reads 105 | (shown with `numruns = 10`). For chain strength, we examine the 106 | entries in our Q matrix and choose a relatively large number to enforce chains 107 | in our embedding. For this problem, our matrix entries range from -3 to +2 and 108 | so a value of 8 is chosen for `chainstrength`. 109 | 110 | ## Ising Formulation 111 | 112 | For this demo we also provide the file `maximum_cut_ising.py`, which implements 113 | the Ising form of this problem. 114 | 115 | To run the demo, type: 116 | ```bash 117 | python maximum_cut_ising.py 118 | ``` 119 | 120 | ## References 121 | 122 | Dunning, Iain, Swati Gupta, and John Silberholz. "What works best when? A 123 | systematic evaluation of heuristics for Max-Cut and QUBO." INFORMS Journal on 124 | Computing 30.3 (2018): 608-624. 125 | 126 | ## License 127 | 128 | Released under the Apache License 2.0. See [LICENSE](./LICENSE) file. 129 | -------------------------------------------------------------------------------- /maximum_cut.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 D-Wave Systems, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # ------ Import necessary packages ---- 16 | from collections import defaultdict 17 | 18 | from dwave.system.samplers import DWaveSampler 19 | from dwave.system.composites import EmbeddingComposite 20 | import networkx as nx 21 | 22 | import matplotlib 23 | matplotlib.use("agg") 24 | from matplotlib import pyplot as plt 25 | 26 | # ------- Set up our graph ------- 27 | 28 | # Create empty graph 29 | G = nx.Graph() 30 | 31 | # Add edges to the graph (also adds nodes) 32 | G.add_edges_from([(1,2),(1,3),(2,4),(3,4),(3,5),(4,5)]) 33 | 34 | # ------- Set up our QUBO dictionary ------- 35 | 36 | # Initialize our Q matrix 37 | Q = defaultdict(int) 38 | 39 | # Update Q matrix for every edge in the graph 40 | for i, j in G.edges: 41 | Q[(i,i)]+= -1 42 | Q[(j,j)]+= -1 43 | Q[(i,j)]+= 2 44 | 45 | # ------- Run our QUBO on the QPU ------- 46 | # Set up QPU parameters 47 | chainstrength = 8 48 | numruns = 10 49 | 50 | # Run the QUBO on the solver from your config file 51 | sampler = EmbeddingComposite(DWaveSampler()) 52 | response = sampler.sample_qubo(Q, 53 | chain_strength=chainstrength, 54 | num_reads=numruns, 55 | label='Example - Maximum Cut') 56 | 57 | # ------- Print results to user ------- 58 | print('-' * 60) 59 | print('{:>15s}{:>15s}{:^15s}{:^15s}'.format('Set 0','Set 1','Energy','Cut Size')) 60 | print('-' * 60) 61 | for sample, E in response.data(fields=['sample','energy']): 62 | S0 = [k for k,v in sample.items() if v == 0] 63 | S1 = [k for k,v in sample.items() if v == 1] 64 | print('{:>15s}{:>15s}{:^15s}{:^15s}'.format(str(S0),str(S1),str(E),str(int(-1*E)))) 65 | 66 | # ------- Display results to user ------- 67 | # Grab best result 68 | # Note: "best" result is the result with the lowest energy 69 | # Note2: the look up table (lut) is a dictionary, where the key is the node index 70 | # and the value is the set label. For example, lut[5] = 1, indicates that 71 | # node 5 is in set 1 (S1). 72 | lut = response.first.sample 73 | 74 | # Interpret best result in terms of nodes and edges 75 | S0 = [node for node in G.nodes if not lut[node]] 76 | S1 = [node for node in G.nodes if lut[node]] 77 | cut_edges = [(u, v) for u, v in G.edges if lut[u]!=lut[v]] 78 | uncut_edges = [(u, v) for u, v in G.edges if lut[u]==lut[v]] 79 | 80 | # Display best result 81 | pos = nx.spring_layout(G) 82 | nx.draw_networkx_nodes(G, pos, nodelist=S0, node_color='r') 83 | nx.draw_networkx_nodes(G, pos, nodelist=S1, node_color='c') 84 | nx.draw_networkx_edges(G, pos, edgelist=cut_edges, style='dashdot', alpha=0.5, width=3) 85 | nx.draw_networkx_edges(G, pos, edgelist=uncut_edges, style='solid', width=3) 86 | nx.draw_networkx_labels(G, pos) 87 | 88 | filename = "maxcut_plot.png" 89 | plt.savefig(filename, bbox_inches='tight') 90 | print("\nYour plot is saved to {}".format(filename)) 91 | -------------------------------------------------------------------------------- /maximum_cut_ising.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 D-Wave Systems, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # ------ Import necessary packages ---- 16 | from collections import defaultdict 17 | 18 | from dwave.system.samplers import DWaveSampler 19 | from dwave.system.composites import EmbeddingComposite 20 | from matplotlib import pyplot as plt 21 | import networkx as nx 22 | 23 | # ------- Set up our graph ------- 24 | 25 | # Create empty graph 26 | G = nx.Graph() 27 | 28 | # Add edges to the graph (also adds nodes) 29 | G.add_edges_from([(1,2),(1,3),(2,4),(3,4),(3,5),(4,5)]) 30 | 31 | # ------- Set up our QUBO dictionary ------- 32 | 33 | # Initialize our h vector, J matrix 34 | h = defaultdict(int) 35 | J = defaultdict(int) 36 | 37 | # Update J matrix for every edge in the graph 38 | for i, j in G.edges: 39 | J[(i,j)]+= 1 40 | 41 | # ------- Run our QUBO on the QPU ------- 42 | # Set up QPU parameters 43 | chainstrength = 2 44 | numruns = 10 45 | 46 | # Run the QUBO on the solver from your config file 47 | sampler = EmbeddingComposite(DWaveSampler()) 48 | response = sampler.sample_ising(h, J, 49 | chain_strength=chainstrength, 50 | num_reads=numruns, 51 | label='Example - Maximum Cut Ising') 52 | 53 | # ------- Print results to user ------- 54 | print('-' * 60) 55 | print('{:>15s}{:>15s}{:^15s}{:^15s}'.format('Set 0','Set 1','Energy','Cut Size')) 56 | print('-' * 60) 57 | for sample, E in response.data(fields=['sample','energy']): 58 | S0 = [k for k,v in sample.items() if v == -1] 59 | S1 = [k for k,v in sample.items() if v == 1] 60 | print('{:>15s}{:>15s}{:^15s}{:^15s}'.format(str(S0),str(S1),str(E),str(int((6-E)/2)))) 61 | 62 | # ------- Display results to user ------- 63 | # Grab best result 64 | # Note: "best" result is the result with the lowest energy 65 | # Note2: the look up table (lut) is a dictionary, where the key is the node index 66 | # and the value is the set label. For example, lut[5] = 1, indicates that 67 | # node 5 is in set 1 (S1). 68 | lut = response.first.sample 69 | 70 | # Interpret best result in terms of nodes and edges 71 | S0 = [node for node in G.nodes if lut[node]==-1] 72 | S1 = [node for node in G.nodes if lut[node]==1] 73 | cut_edges = [(u, v) for u, v in G.edges if lut[u]!=lut[v]] 74 | uncut_edges = [(u, v) for u, v in G.edges if lut[u]==lut[v]] 75 | 76 | # Display best result 77 | pos = nx.spring_layout(G) 78 | nx.draw_networkx_nodes(G, pos, nodelist=S0, node_color='r') 79 | nx.draw_networkx_nodes(G, pos, nodelist=S1, node_color='c') 80 | nx.draw_networkx_edges(G, pos, edgelist=cut_edges, style='dashdot', alpha=0.5, width=3) 81 | nx.draw_networkx_edges(G, pos, edgelist=uncut_edges, style='solid', width=3) 82 | nx.draw_networkx_labels(G, pos) 83 | 84 | filename = "maxcut_plot_ising.png" 85 | plt.savefig(filename, bbox_inches='tight') 86 | print("\nYour plot is saved to {}".format(filename)) 87 | -------------------------------------------------------------------------------- /readme_imgs/QUBO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwave-examples/maximum-cut/9f8b53b8463be217f41d02e165894391a314fef4/readme_imgs/QUBO.png -------------------------------------------------------------------------------- /readme_imgs/cut_examples.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwave-examples/maximum-cut/9f8b53b8463be217f41d02e165894391a314fef4/readme_imgs/cut_examples.png -------------------------------------------------------------------------------- /readme_imgs/final_QUBO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwave-examples/maximum-cut/9f8b53b8463be217f41d02e165894391a314fef4/readme_imgs/final_QUBO.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | dwave-ocean-sdk>=3.3.0 2 | matplotlib~=3.0 3 | 4 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dwave-examples/maximum-cut/9f8b53b8463be217f41d02e165894391a314fef4/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_maximum_cut.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 D-Wave Systems Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import os 16 | import subprocess 17 | import sys 18 | import unittest 19 | 20 | # /path/to/demos/maximum-cut/tests/test_maximum_cut.py 21 | project_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 22 | 23 | 24 | class TestDemo(unittest.TestCase): 25 | @unittest.skipIf(os.getenv('SKIP_INT_TESTS'), "Skipping integration test.") 26 | def test_maximum_cut(self): 27 | demo_file = os.path.join(project_dir, 'maximum_cut.py') 28 | output = subprocess.check_output([sys.executable, demo_file]) 29 | output = str(output).upper() 30 | if os.getenv('DEBUG_OUTPUT'): 31 | print("Example output \n" + output) 32 | 33 | with self.subTest(msg="Verify if output contains 'Your plot is saved' \n"): 34 | self.assertIn("Your plot is saved".upper(), output) 35 | with self.subTest(msg="Verify if error string contains in output \n"): 36 | self.assertNotIn("ERROR", output) 37 | with self.subTest(msg="Verify if warning string contains in output \n"): 38 | self.assertNotIn("WARNING", output) 39 | 40 | if __name__ == '__main__': 41 | unittest.main() 42 | --------------------------------------------------------------------------------