{"id":3503,"date":"2024-08-20T17:18:15","date_gmt":"2024-08-20T17:18:15","guid":{"rendered":"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/"},"modified":"2025-03-05T03:38:22","modified_gmt":"2025-03-05T08:38:22","slug":"solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b","status":"publish","type":"post","link":"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/","title":{"rendered":"Solving a Constrained Project Scheduling Problem with Quantum Annealing"},"content":{"rendered":"<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"7d8082\" data-has-transparency=\"false\" style=\"--dominant-color: #7d8082;\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1024\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1woUHmBFHvIjPXDecLnDYqg.jpg\" alt=\"Why did the dog fail quantum mechanics class? He couldn&#039;t grasp the concept of super-paws-ition. Quantum superposition is the principle where a quantum system can exist in multiple states simultaneously until it is measured, at which point it collapses into one of the possible states. (Image generated by DALLE-3)\" class=\"wp-image-3504 not-transparent\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1woUHmBFHvIjPXDecLnDYqg.jpg 1024w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1woUHmBFHvIjPXDecLnDYqg-300x300.jpg 300w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1woUHmBFHvIjPXDecLnDYqg-150x150.jpg 150w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1woUHmBFHvIjPXDecLnDYqg-768x768.jpg 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Why did the dog fail quantum mechanics class? He couldn&#8217;t grasp the concept of super-paws-ition. Quantum superposition is the principle where a quantum system can exist in multiple states simultaneously until it is measured, at which point it collapses into one of the possible states. (Image generated by DALLE-3)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">I&#8217;m really excited to share this article with you because it&#8217;s closely tied to my current research: optimizing project schedules with quantum computing. My passion for this topic comes from my background as a project manager and my ongoing research into how quantum computing can help solving complex optimization problems. During my PhD, I specifically looked into how today&#8217;s quantum technology could be used to tackle complex scheduling challenges, that are specific for the field of project management.<\/p>\n<p class=\"wp-block-paragraph\">We&#8217;re living in an incredible era where quantum computers are no longer just a concept &#8211; they&#8217;re real and being used. Imagine what Richard Feynman would say about them! However, these machines aren&#8217;t fully ready yet. They&#8217;re often referred to as NISQ (Noisy Intermediate-Scale Quantum) devices, a term coined by quantum computing pioneer John Preskill. These machines are still considered early versions of the more advanced quantum computers we hope to see in the future.<\/p>\n<p class=\"wp-block-paragraph\">Currently, they&#8217;re small, with only a few qubits (quantum bits of information) available. For comparison, it&#8217;s not uncommon today to have a laptop with 16GB of RAM, which equates to around 128 billion bits of information, that we can work with. In contrast, the largest quantum computers have fewer than 6,000 qubits. Moreover, qubits are highly sensitive to noise, and the limited number of qubits makes it challenging to correct errors and perform complex calculations.<\/p>\n<p class=\"wp-block-paragraph\">Despite these challenges, the quantum computers we have today are powerful enough to test out algorithms and see their potential for solving tough problems. In broad terms there are two main types of quantum computers: universal quantum machines, like the ones from IBM and Google, which work on a circuit-gate model of computation, and quantum annealers, which use adiabatic evolution principles (Technically speaking there is a third type of quantum computer, which are measurement based quantum machines, but these ones are still in early development). In quantum computing, &quot;universal&quot; means that these machines can, in theory, run any quantum algorithm by implementing any quantum mechanical gate (including classical gates). While quantum annealers might not be universal, they&#8217;re still super promising for optimization tasks.<\/p>\n<p class=\"wp-block-paragraph\">In this article, I&#8217;ll walk you through how you can use a quantum annealer provided by a company called <a href=\"None\">D-Wave<\/a> to optimize project schedules, this article is based on one of my recently published research papers [1]. If you&#8217;re interested in a deeper dive, I invite you to read my full research article, which you can access using the link down below.<\/p>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p><a href=\"https:\/\/www.nature.com\/articles\/s41598-024-67168-6\"><strong>Solving the resource constrained project scheduling problem with quantum annealing &#8211; Scientific&#8230;<\/strong><\/a><\/p><\/blockquote>\n<p class=\"wp-block-paragraph\">Before we get into the coding, I&#8217;ll give you a quick intro to quantum annealing and how it&#8217;s used in optimization. Let&#8217;s get started!<\/p>\n<p class=\"wp-block-paragraph\"><strong>Article index:<\/strong><\/p>\n<ul class=\"wp-block-list\">\n<li><a href=\"#2622\">What is quantum annealing?<\/a><\/li>\n<li><a href=\"#b57e\">The RCPSP and it&#8217;s binary MILP formulation<\/a><\/li>\n<li><a href=\"#2ce8\">Installing the libraries and setting up the Colab environment<\/a><\/li>\n<li><a href=\"#7b62\">D-wave CQM for the RCPSP<\/a><\/li>\n<li><a href=\"#a41e\">Solving the instance and extracting the output<\/a><\/li>\n<li><a href=\"#32e8\">Conclusions<\/a><\/li>\n<li><a href=\"#70d7\">References<\/a><\/li>\n<\/ul>\n<h2 class=\"wp-block-heading\">What is quantum annealing?<\/h2>\n<p class=\"wp-block-paragraph\">Quantum Annealing is a quantum metaheuristic designed to solve combinatorial optimization problems by leveraging the principles of quantum mechanics [2]. This approach is inspired by simulated annealing [4], a classical metaheuristic where a system is gradually cooled to reach a state of minimum energy. In quantum annealing, quantum phenomena such as superposition (where a quantum system can exist in multiple states simultaneously until measured, at which point it collapses into one of the possible states) and quantum tunneling are utilized to efficiently navigate through local minima, with the goal of finding the global minimum of a cost function.<\/p>\n<p class=\"wp-block-paragraph\">Quantum annealing devices are primarily employed for optimization purposes, such as finding the minimum or maximum value of a problem. Imagine trying to find the lowest point in a rugged, hilly landscape aka the &quot;best&quot; solution to a problem. Traditional methods might get stuck in small dips, mistaking them for the lowest point. In contrast, a quantum annealer leverages the properties of quantum mechanics, attempting to tunnel through these local minima and guide the system to the true lowest point, or optimal solution. The effectiveness of quantum annealing, compared to its classical counterpart, can vary depending on the specific problem and the hardware used. The literature presents both theoretical proofs [3] that highlight the advantages of quantum annealing, as well as contrasting perspectives, particularly when compared to simulated annealing<\/p>\n<p class=\"wp-block-paragraph\">At the core of quantum annealing is the profound concept that the universe naturally tends to seek states of minimum energy, known as ground states. Quantum annealing also relies on the &quot;adiabatic theorem&quot; of quantum mechanics and the evolution of quantum systems as described by the time-dependent Schr\u00f6dinger equation.<\/p>\n<iframe loading=\"lazy\" class=\"wp-block-html\" src=\"https:\/\/cdn.embedly.com\/widgets\/media.html?src=https%3A%2F%2Fmath.embed.fun%2Fembed%2FagmkpAKExrqZx8sMwfYXn9&amp;display_name=Embed+Fun&amp;url=https%3A%2F%2Fmath.embed.fun%2FagmkpAKExrqZx8sMwfYXn9&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=embed\" height=\"152\" width=\"200\"><\/iframe>\n<p class=\"wp-block-paragraph\">Optimization problems can be represented as physical systems and formulated as energy Hamiltonian problems, which are mathematical representations of a system&#8217;s total energy. A common approach is to use the ISING model to encode the optimization problem into a physical system. In this model, the optimization problem is mapped onto a representation of the magnetic spin of each qubit, interacting in a two-dimensional lattice grid, as shown in Figure 1 below.<\/p>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"ede7ec\" data-has-transparency=\"false\" style=\"--dominant-color: #ede7ec;\" loading=\"lazy\" decoding=\"async\" width=\"601\" height=\"427\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1a6Nqy2Rt1C33P4rcYvQB8Q-1.gif\" alt=\"Figure 1. ISING Two Dimensional Lattice (Image created by the author)\" class=\"wp-image-310400 not-transparent\" \/><figcaption class=\"wp-element-caption\">Figure 1. ISING Two Dimensional Lattice (Image created by the author)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">The mathematical representation of the energy Hamiltonian <strong>H\u2081<\/strong>\u200b in the ISING model is given by the formula below:<\/p>\n<iframe loading=\"lazy\" class=\"wp-block-html\" src=\"https:\/\/cdn.embedly.com\/widgets\/media.html?src=https%3A%2F%2Fmath.embed.fun%2Fembed%2F4TtUxgKvzQfsspPzZLuy7x&amp;display_name=Embed+Fun&amp;url=https%3A%2F%2Fmath.embed.fun%2F4TtUxgKvzQfsspPzZLuy7x&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=embed\" height=\"112\" width=\"570\"><\/iframe>\n<p class=\"wp-block-paragraph\">Here, \u03c3<em>\u1d62<\/em>\u200b is the Z-Pauli gate applied to qubit <em><code>i<\/code><\/em>, which takes the value <code>+1<\/code> if the qubit is pointing upwards and <code>-1<\/code> if it is oriented downwards. <em>J\u1d62 \u2c7c<\/em>\u200b represents the interaction coefficient between qubits <em><code>i<\/code><\/em> and <em><code>j<\/code><\/em>, while <em>H\u1d62<\/em>\u200b represents the coefficient of an external magnetic field interacting with qubit <em><code>i<\/code><\/em>. Fortunately, most common optimization problems can be encoded using this model, as the ISING problem is NP-Complete, as demonstrated by Istrail in 2000 [5]. In this model, each variable is binary, acting like a magnet that can only point up or down. These magnets will naturally try to orient themselves to minimize the energy of the entire grid, resulting in the system&#8217;s minimum energy. The solution to the problem is simply the configuration of the magnets after they have evolved and properly aligned themselves.<\/p>\n<p class=\"wp-block-paragraph\">You&#8217;ve likely already encountered some of the principles of this model without even realizing it. If you&#8217;ve ever played with magnets, you know that when you have two or more, they naturally try to align their poles in opposite directions to minimize the total energy of the system, as illustrated in Figure 2.<\/p>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"eeebee\" data-has-transparency=\"false\" style=\"--dominant-color: #eeebee;\" loading=\"lazy\" decoding=\"async\" width=\"1152\" height=\"648\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1WEdMl-Vht6KAfHuG1EKM0A-1.gif\" alt=\"Figure 2. Magnets minimizing energy (Image created by the Author)\" class=\"wp-image-310401 not-transparent\" \/><figcaption class=\"wp-element-caption\">Figure 2. Magnets minimizing energy (Image created by the Author)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Mother Nature is a giant optimizer, that tries to solve this problem on her own. As illustrated in Figure 3 if we start with a random assortment of spin particles, each oriented in a different direction, they will naturally attempt to realign themselves, seeking the minimum energy state. Quantum annealing leverages this principle. However, this process doesn&#8217;t always guarantee finding the absolute global minimum, as nature can still get stuck in local minima. That&#8217;s why we also rely on the power of the adiabatic theorem.<\/p>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"c3c4c2\" data-has-transparency=\"false\" style=\"--dominant-color: #c3c4c2;\" loading=\"lazy\" decoding=\"async\" width=\"400\" height=\"300\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1_NR_zj-SC5czbouY_cL3EQ-1.gif\" alt=\"Figure 3. Quench of an ISING system on a two-dimensional square lattice (500 \u00d7 500) starting from a random configuration (Image downloaded from Wilkipedia https:\/\/en.wikipedia.org\/wiki\/Ising_model)\" class=\"wp-image-310402 not-transparent\" \/><figcaption class=\"wp-element-caption\">Figure 3. Quench of an ISING system on a two-dimensional square lattice (500 \u00d7 500) starting from a random configuration (Image downloaded from Wilkipedia <a href=\"https:\/\/en.wikipedia.org\/wiki\/Ising_model\">https:\/\/en.wikipedia.org\/wiki\/Ising_model<\/a>)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">The adiabatic theorem, first formally stated by Max Born in 1928 (although Einstein had also explored the concept earlier), tells us that:<\/p>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>If a system starts in its lowest energy state and changes &quot;slowly enough&quot;, it will remain in that minimum energy state as it evolves.<\/p><\/blockquote>\n<p class=\"wp-block-paragraph\">This theorem and its impact on quantum annealing can be challenging to grasp, so I&#8217;m going to use a metaphor that has worked well for me in the past. Keep in mind that, like all metaphors, it may not be entirely accurate from a formal physics perspective (it is not), but it serves as a helpful way to illustrate the concept.<\/p>\n<p class=\"wp-block-paragraph\">Imagine we have a toddler who, in this example, represents a quantum system. Let&#8217;s get creative, like Elon Musk, and call this child Psi <strong>\u03a8<\/strong>. Now, Psi <strong>\u03a8<\/strong> can interact with various environments within the house where they live. These environments represent what we&#8217;ll call energy Hamiltonians. For instance, one Hamiltonian could be the living room of the house, with a comfy couch in front of the TV, as shown in Figure 4.<\/p>\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1801\" height=\"1125\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1M3UEJzfk58uVDI0mkCzDCQ-1.png\" alt=\"Figure 4. Energy Hamiltonian metaphor example (Image created by the author using Midjourney)\" class=\"wp-image-310403\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1M3UEJzfk58uVDI0mkCzDCQ-1.png 1801w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1M3UEJzfk58uVDI0mkCzDCQ-1-300x187.png 300w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1M3UEJzfk58uVDI0mkCzDCQ-1-1024x640.png 1024w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1M3UEJzfk58uVDI0mkCzDCQ-1-768x480.png 768w\" sizes=\"auto, (max-width: 1801px) 100vw, 1801px\" \/><figcaption class=\"wp-element-caption\">Figure 4. Energy Hamiltonian metaphor example (Image created by the author using Midjourney)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Another Hamiltonian could be for example the bedroom of Psi <strong>\u03a8<\/strong>, as depicted in Figure 5.<\/p>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"b47782\" data-has-transparency=\"true\" style=\"--dominant-color: #b47782;\" loading=\"lazy\" decoding=\"async\" width=\"2000\" height=\"1125\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1s3B1o4QX0TYFBiaBegAa0A-1.png\" alt=\"Figure 5. Energy Hamiltonian metaphor example (Image created by the author using Midjourney)\" class=\"wp-image-314003 has-transparency\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1s3B1o4QX0TYFBiaBegAa0A-1.png 2000w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1s3B1o4QX0TYFBiaBegAa0A-1-300x169.png 300w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1s3B1o4QX0TYFBiaBegAa0A-1-1024x576.png 1024w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1s3B1o4QX0TYFBiaBegAa0A-1-768x432.png 768w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1s3B1o4QX0TYFBiaBegAa0A-1-1536x864.png 1536w\" sizes=\"auto, (max-width: 2000px) 100vw, 2000px\" \/><figcaption class=\"wp-element-caption\">Figure 5. Energy Hamiltonian metaphor example (Image created by the author using Midjourney)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Now, Psi <strong>\u03a8<\/strong> can exist in various energetic states. For example, Psi <strong>\u03a8<\/strong> could be in an excited state, let&#8217;s say they&#8217;re in the middle of a sugar rush, as shown in Figure 6.<\/p>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"887f71\" data-has-transparency=\"true\" style=\"--dominant-color: #887f71;\" loading=\"lazy\" decoding=\"async\" width=\"1213\" height=\"1125\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1T-Gmck1LAFIFfzH1mJCnrA-1.png\" alt=\"Figure 6. Very Exited State \u03a8 (Image created by DALLE-3)\" class=\"wp-image-314004 has-transparency\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1T-Gmck1LAFIFfzH1mJCnrA-1.png 1213w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1T-Gmck1LAFIFfzH1mJCnrA-1-300x278.png 300w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1T-Gmck1LAFIFfzH1mJCnrA-1-1024x950.png 1024w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1T-Gmck1LAFIFfzH1mJCnrA-1-768x712.png 768w\" sizes=\"auto, (max-width: 1213px) 100vw, 1213px\" \/><figcaption class=\"wp-element-caption\">Figure 6. Very Exited State <strong>\u03a8<\/strong> (Image created by DALLE-3)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Psi <strong>\u03a8<\/strong> <strong><strong> can also be in a ground state, a state of minimum energy. For example Psi <\/strong><\/strong> \u03a8 might be in deep sleep as shown in Figure 7.<\/p>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"53504c\" data-has-transparency=\"true\" style=\"--dominant-color: #53504c;\" loading=\"lazy\" decoding=\"async\" width=\"1125\" height=\"1125\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/16EIqP37KB8mr6qHsktaYow-1.png\" alt=\"Figure 7. Ground State \u03a8 (Image created by DALLE-3)\" class=\"wp-image-314005 has-transparency\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/16EIqP37KB8mr6qHsktaYow-1.png 1125w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/16EIqP37KB8mr6qHsktaYow-1-300x300.png 300w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/16EIqP37KB8mr6qHsktaYow-1-1024x1024.png 1024w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/16EIqP37KB8mr6qHsktaYow-1-150x150.png 150w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/16EIqP37KB8mr6qHsktaYow-1-768x768.png 768w\" sizes=\"auto, (max-width: 1125px) 100vw, 1125px\" \/><figcaption class=\"wp-element-caption\">Figure 7. Ground State <strong>\u03a8<\/strong> (Image created by DALLE-3)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Now, there are certain Hamiltonians, which we&#8217;ll call <em>H\u2080<\/em>\u200b, where Psi <strong>\u03a8<\/strong> will naturally evolve toward a minimum energy ground state. For instance, if we let Psi <strong>\u03a8<\/strong> play in the living room, even if they start in an excited state, they&#8217;ll eventually tire out and fall asleep on that comfy sofa, as shown in Figure 8. (I remember a childhood friend&#8217;s house with a terrace overlooking a beautiful valley, where you could feel the fresh mountain breeze. The terrace had a sofa and was filled with chimes that sang with the wind. It was one of the most relaxing environments I&#8217;ve ever experienced, and I&#8217;m sure anyone would naturally settle into a ground state in that kind of &quot;Hamiltonian&quot;.)<\/p>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"77736d\" data-has-transparency=\"true\" style=\"--dominant-color: #77736d;\" loading=\"lazy\" decoding=\"async\" width=\"1786\" height=\"905\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1asIYq715bOPDMHC7K7DQeQ-1.png\" alt=\"Figure 8. Easy Hamiltonians H\u2080 (Images created by DALLE-3)\" class=\"wp-image-314006 has-transparency\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1asIYq715bOPDMHC7K7DQeQ-1.png 1786w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1asIYq715bOPDMHC7K7DQeQ-1-300x152.png 300w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1asIYq715bOPDMHC7K7DQeQ-1-1024x519.png 1024w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1asIYq715bOPDMHC7K7DQeQ-1-768x389.png 768w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1asIYq715bOPDMHC7K7DQeQ-1-1536x778.png 1536w\" sizes=\"auto, (max-width: 1786px) 100vw, 1786px\" \/><figcaption class=\"wp-element-caption\">Figure 8. Easy Hamiltonians <em>H\u2080<\/em> (Images created by DALLE-3)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">In contrast, there are other Hamiltonians &#8211; typically the ones we&#8217;re most interested in &#8211; called <em>H\u2081<\/em>\u200b, where it&#8217;s much more difficult for Psi <strong>\u03a8<\/strong> to reach the ground state. For example, Psi <strong>\u03a8<\/strong> really struggles to fall asleep when they are in their bedroom, as shown in Figure 9.<\/p>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"8a7b6e\" data-has-transparency=\"true\" style=\"--dominant-color: #8a7b6e;\" loading=\"lazy\" decoding=\"async\" width=\"1125\" height=\"1125\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1Fke54TGJ62z8PYQKB5JBpQ-1.png\" alt=\"Figure 9. Hamiltonians of interest H\u2081 and \u03a8 in exited state (Image created by DALLE-3)\" class=\"wp-image-314007 has-transparency\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1Fke54TGJ62z8PYQKB5JBpQ-1.png 1125w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1Fke54TGJ62z8PYQKB5JBpQ-1-300x300.png 300w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1Fke54TGJ62z8PYQKB5JBpQ-1-1024x1024.png 1024w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1Fke54TGJ62z8PYQKB5JBpQ-1-150x150.png 150w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1Fke54TGJ62z8PYQKB5JBpQ-1-768x768.png 768w\" sizes=\"auto, (max-width: 1125px) 100vw, 1125px\" \/><figcaption class=\"wp-element-caption\">Figure 9. Hamiltonians of interest <em>H\u2081 and<\/em> <strong>\u03a8<\/strong> in exited state (Image created by DALLE-3)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Unfortunately, what we really want is for Psi <strong>\u03a8<\/strong> to be in the ground state of <em>H\u2081<\/em>\u200b &#8211; in other words, we want Psi <strong>\u03a8<\/strong> to be fully asleep in their bedroom . But that&#8217;s tough to achieve, so what do we do?<\/p>\n<p class=\"wp-block-paragraph\">Quantum annealing advises us not to fight against the current. Instead of directly seeking the ground state of <em>H\u2081<\/em>\u200b, it suggests leveraging the power of the adiabatic theorem. Quantum annealing says, &quot;Look, the starting point of this process should be an easy Hamiltonian, <em>H\u2080<\/em>\u200b&quot;. We first allow Psi <strong>\u03a8<\/strong> to naturally evolve into a ground state because it&#8217;s easy to achieve this in <em>H\u2080<\/em>\u200b. So, we let Psi <strong>\u03a8<\/strong> play in the living room, and once they are fully asleep on that comfy sofa, then &#8211; and only then &#8211; do we very gently, very softly, without disturbing their sweet dreams, begin to slowly change the Hamiltonian from <em>H\u2080<\/em>\u200b to <em>H\u2081<\/em>\u200b. We gently pick them up from the sofa, slowly climb the stairs, and softly place them in their bed. If we do this process correctly and &quot;slowly enough&quot; (adiabatically), by the end of it, we should find Psi <strong>\u03a8<\/strong> in the ground state &#8211; not of <em>H\u2080<\/em>\u200b, but of <em>H\u2081,<\/em> as shown in Figure 10\u200b. And voila \ud83e\udd50, this means that we could use this technique to find the ground states of Hamiltonians of interest H<em>\u2081.<\/em><\/p>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"766a5e\" data-has-transparency=\"true\" style=\"--dominant-color: #766a5e;\" loading=\"lazy\" decoding=\"async\" width=\"2653\" height=\"1072\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1gsJWp_4kMw-sm_3B4PIFgQ-1.png\" alt=\"Figure 10. Adiabatic evolution of \u03a8 (Image created by DALLE-3)\" class=\"wp-image-314008 has-transparency\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1gsJWp_4kMw-sm_3B4PIFgQ-1.png 2653w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1gsJWp_4kMw-sm_3B4PIFgQ-1-300x121.png 300w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1gsJWp_4kMw-sm_3B4PIFgQ-1-1024x414.png 1024w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1gsJWp_4kMw-sm_3B4PIFgQ-1-768x310.png 768w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1gsJWp_4kMw-sm_3B4PIFgQ-1-1536x621.png 1536w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1gsJWp_4kMw-sm_3B4PIFgQ-1-2048x828.png 2048w\" sizes=\"auto, (max-width: 2653px) 100vw, 2653px\" \/><figcaption class=\"wp-element-caption\">Figure 10. Adiabatic evolution of <strong>\u03a8<\/strong> (Image created by DALLE-3)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Great! So, this means that we can indeed use this technique to solve complex optimization problems. All we need to do is find a way to encode the problem into an <em>H\u2081<\/em> (using the ISING model)\u200b and identify a suitable <em>H\u2080<\/em>\u200b. Then, we gradually transition from <em>H\u2080<\/em>\u200b to <em>H\u2081<\/em>\u200b by following the annealing schedule outlined below.<\/p>\n<iframe loading=\"lazy\" class=\"wp-block-html\" src=\"https:\/\/cdn.embedly.com\/widgets\/media.html?src=https%3A%2F%2Fmath.embed.fun%2Fembed%2F3YBhoAgNmeMwEjAzrnmBG&amp;display_name=Embed+Fun&amp;url=https%3A%2F%2Fmath.embed.fun%2F3YBhoAgNmeMwEjAzrnmBG&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=embed\" height=\"96\" width=\"386\"><\/iframe>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"f7f6f5\" data-has-transparency=\"true\" style=\"--dominant-color: #f7f6f5;\" loading=\"lazy\" decoding=\"async\" width=\"1741\" height=\"550\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/19vTzZvsd56DHl2KTQT95Uw-1.png\" alt=\"Figure 11. Annealing schedule (Image created by the author)\" class=\"wp-image-314009 has-transparency\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/19vTzZvsd56DHl2KTQT95Uw-1.png 1741w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/19vTzZvsd56DHl2KTQT95Uw-1-300x95.png 300w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/19vTzZvsd56DHl2KTQT95Uw-1-1024x323.png 1024w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/19vTzZvsd56DHl2KTQT95Uw-1-768x243.png 768w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/19vTzZvsd56DHl2KTQT95Uw-1-1536x485.png 1536w\" sizes=\"auto, (max-width: 1741px) 100vw, 1741px\" \/><figcaption class=\"wp-element-caption\">Figure 11. Annealing schedule (Image created by the author)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">At this point, you might be wondering, &quot;What about <em>H\u2080<\/em>\u200b? How do we find it?&quot; Fortunately, the initial Hamiltonian <em>H\u2080<\/em> is easy to identify. We typically use a Hamiltonian known as the &quot;tunneling Hamiltonian,&quot; which is described by Equation 4 below. The ground state for this Hamiltonian is simply each qubit in a &quot;uniform&quot; superposition (equal probability of being 0 or 1).<\/p>\n<iframe loading=\"lazy\" class=\"wp-block-html\" src=\"https:\/\/cdn.embedly.com\/widgets\/media.html?src=https%3A%2F%2Fmath.embed.fun%2Fembed%2FiAKKk9ecMXN2vsBot79R1M&amp;display_name=Embed+Fun&amp;url=https%3A%2F%2Fmath.embed.fun%2FiAKKk9ecMXN2vsBot79R1M&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=embed\" height=\"143\" width=\"200\"><\/iframe>\n<p class=\"wp-block-paragraph\">Now, when it comes to optimization, we often prefer not to use the <strong>+1<\/strong>,<strong>\u22121<\/strong> basis of the ISING model. Instead, we like to encode optimization problems into Hamiltonians <em>H\u2081<\/em>\u200b\u200b using an equivalent isomorphic formulation of the ISING model called QUBO (Quadratic Unconstrained Binary Optimization). QUBO expresses the problem as minimizing a quadratic polynomial over binary variables that can be either 0 or 1. When we formulate a problem as a QUBO, we must represent all variables of our optimization problem as binary and include each constraint as a penalty term added to the objective function. An excellent guide on how to do this was published by Fred Glover [6].<\/p>\n<p class=\"wp-block-paragraph\">Once the optimization problem is in QUBO or ISING form, it must be mapped onto the quantum chip. The chip has a fixed architecture for the qubits &#8211; a topology, if you will (the current generation of D-wave quantum annealers uses a topology known as Pegasus). Since the qubits are not fully connected, we need to be creative when mapping the problem into the quantum chip. If for example a qubit <em><code>i<\/code><\/em> needs to interact with qubit <em><code>j<\/code><\/em>, but they aren&#8217;t directly connected in the machine&#8217;s topology, we need to find other qubits (or a group of them) that form a connecting path between <em><code>i<\/code><\/em> and <em><code>j<\/code><\/em>. This path is known as a &quot;chain&quot;, and the process of mapping a problem onto the quantum chip is called minor embedding, this process consumes extra qubits that are now going to be used as logical qubits. Minor embedding is not trivial, as it is also an NP problem, but we can rely on heuristics to help find these embeddings. An example of the mapping produced from my <a href=\"https:\/\/www.nature.com\/articles\/s41598-024-67168-6\">research<\/a> can be seen in Figure 12 below.<\/p>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"d3d3d3\" data-has-transparency=\"false\" style=\"--dominant-color: #d3d3d3;\" loading=\"lazy\" decoding=\"async\" width=\"1562\" height=\"839\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/0WaYJcMRk_BYm40Vt-1.png\" alt=\"Figure 12. Minor embeddings for an RCPSP instance used in the research article of the author (Image created by the author)\" class=\"wp-image-314010 not-transparent\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/0WaYJcMRk_BYm40Vt-1.png 1562w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/0WaYJcMRk_BYm40Vt-1-300x161.png 300w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/0WaYJcMRk_BYm40Vt-1-1024x550.png 1024w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/0WaYJcMRk_BYm40Vt-1-768x413.png 768w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/0WaYJcMRk_BYm40Vt-1-1536x825.png 1536w\" sizes=\"auto, (max-width: 1562px) 100vw, 1562px\" \/><figcaption class=\"wp-element-caption\">Figure 12. Minor embeddings for an RCPSP instance used in the research article of the author (Image created by the author)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">There&#8217;s one small detail about the current generation of quantum annealers: it&#8217;s been nearly impossible to recreate the ideal conditions required by the adiabatic theorem. Even minor disturbances, like those caused by <a href=\"https:\/\/www.nature.com\/articles\/s41534-021-00431-0\">cosmic rays<\/a> [9], can disrupt the ground state and interfere with the annealing process. That&#8217;s why, in practice, we run the annealing process multiple times and consider all the output solutions as samples. We then collect these samples and select the one with the lowest energy hoping that it is the optimal solution.<\/p>\n<p class=\"wp-block-paragraph\">Now that we have a solid understanding of how quantum annealing works, let&#8217;s move on to the next section, where we&#8217;ll apply it to solve one of the most challenging scheduling problems &#8211; the Resource-Constrained Project Scheduling Problem (RCPSP).<\/p>\n<h2 class=\"wp-block-heading\">The RCPSP and it&#8217;s binary MILP formulation<\/h2>\n<p class=\"wp-block-paragraph\">As a reminder, we&#8217;re tackling a project scheduling problem where we need to manage limited resources, such as workers or equipment. This problem is known as the Resource-Constrained Project Scheduling Problem (RCPSP). It&#8217;s a challenging combinatorial optimization problem, classified as NP-hard by Blazewicz et al. (1983) [7]. The project consists of many tasks, each with its own duration and resource requirements, and there&#8217;s a maximum capacity for each resource. Additionally, tasks have &quot;precedence constraints,&quot; meaning some tasks must be completed before others can begin. (Note that there are different types of precedence constraints; the &quot;Finish-to-Start&quot; (FS) type is the most common.)<\/p>\n<p class=\"wp-block-paragraph\">The main goal is to create a schedule with the minimum makespan &#8211; a plan that determines the timing of each task to complete the entire project as quickly as possible. Our schedule must respect all constraints, which means we must adhere to precedence requirements (not breaking the order of tasks) and ensure that resource usage doesn&#8217;t exceed the available capacities.<\/p>\n<p class=\"wp-block-paragraph\">There are many different Mixed Integer Linear Programming (MILP) formulations for the RCPSP, but we need to choose one that best adapts to quantum annealing. In my research, we explored 12 of the most commonly used formulations for the RCPSP. We selected the one that consumes the fewest qubits, as qubits are a precious resource in the current stage of quantum computing development, and their availability is a limiting factor. After an extensive analysis, we determined that the most suitable formulation is the time-indexed binary formulation of Pritzker et al. (1969) [8]. For more details on how we reach this conclusion, please refer to the research <a href=\"https:\/\/www.nature.com\/articles\/s41598-024-67168-6\">article<\/a>.<\/p>\n<p class=\"wp-block-paragraph\">This is a binary formulation where we have one binary variable <code>x_{i,t}<\/code> for each activity <code>i<\/code> and starting date <code>t<\/code>. This variable equals <strong>1<\/strong> if activity <code>i<\/code> starts on day <code>t<\/code>, and <strong>0<\/strong> otherwise. The total number of variables is equal to the number of project activities (plus two extra dummy activities &#8211; one for the project &#8216;Start&#8217; and one for the project &#8216;End&#8217;) multiplied by the number of possible start dates <code>t<\/code>. The number of possible start dates is determined by the project time horizon <code>T<\/code>, which represents the maximum possible project duration. Each task has a duration <code>p_i<\/code> and a resource consumption <code>u_{i,k}<\/code>\u200b for each resource <code>k<\/code>. Precedence constraints are provided as a list of tuples <code>E<\/code> in the form <code>(i,j)<\/code>, indicating that task <code>j<\/code> cannot start until task <code>i<\/code> is finished.<\/p>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"f9f9f9\" data-has-transparency=\"true\" style=\"--dominant-color: #f9f9f9;\" loading=\"lazy\" decoding=\"async\" width=\"875\" height=\"340\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/06v9fzGJJ3UQLquaP-1.png\" alt=\"Figure 13. Pritzker et al. 1969 mathematical programming formulation for the RCPSP (Image created by the author)\" class=\"wp-image-314011 has-transparency\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/06v9fzGJJ3UQLquaP-1.png 875w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/06v9fzGJJ3UQLquaP-1-300x117.png 300w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/06v9fzGJJ3UQLquaP-1-768x298.png 768w\" sizes=\"auto, (max-width: 875px) 100vw, 875px\" \/><figcaption class=\"wp-element-caption\">Figure 13. Pritzker et al. 1969 mathematical programming formulation for the RCPSP (Image created by the author)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">The formulation above might look daunting at first sight, but it is actually quite simple.<\/p>\n<ol class=\"wp-block-list\">\n<li>The objective function (1) represents the sum of all possible start dates for the dummy variable <code>x_{n+1,t}<\/code>\u200b (where these dummy variables represent the project&#8217;s end date). We know that only one of these variables will equal 1 for a specific<code>t<\/code>. Therefore, by minimizing the sum of the product <code>t*x_{n+1,t}<\/code>, we are effectively minimizing the project duration.<\/li>\n<li>Constraint (2) ensures that each activity <code>i<\/code> has exactly one start date.<\/li>\n<li>Constraint (3) ensures that if an activity <code>j<\/code> follows another activity <code>i<\/code>, then activity <code>j<\/code> must start after the finish date of activity <code>i<\/code>, which is equal to the start date of <code>i<\/code> plus its duration <code>p_i<\/code>\u200b.<\/li>\n<li>Finally, Constraint (4) guarantees that for any time period <code>t<\/code>, the schedule does not exceed the capacity <code>R_k<\/code> for any resource <code>k<\/code>.<\/li>\n<\/ol>\n<p class=\"wp-block-paragraph\">In this article, we will solve a project with 21 activities <code>(n=21)<\/code> (including the two dummy ones) and two resources <code>(k=2)<\/code>. The project details are provided in Table 1 below.<\/p>\n<div class=\"wp-block-tds-gist-embed\">\n\t<script src=\"https:\/\/gist.github.com\/ceche1212\/b14efd2aac1d44a0ceb3ed93310b47b3.js\"><\/script>\n<\/div>\n\n<p class=\"wp-block-paragraph\">You can also download the instance as a text file in the <code>.rcp<\/code> format using the GitHub link provided below.<\/p>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p><a href=\"https:\/\/github.com\/ceche1212\/medium_rcpsp_dwave_cqm\/blob\/main\/RCPSP_19_instance.rcp\"><strong>medium_rcpsp_dwave_cqm\/RCPSP_19_instance.rcp at main \u00b7 ceche1212\/medium_rcpsp_dwave_cqm<\/strong><\/a><\/p><\/blockquote>\n<p class=\"wp-block-paragraph\">Our project instance in the <code>.rcp<\/code> format is shown in the text file below.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">  21    2 \n  10   10\n\n   0   0   0  11 2 3 4 5 6 10 16 17 18 19 20 \n   3   1   1   3 15 14 7 \n   3   2   8   3 13 12 11 \n   3   5   5   2 12 11 \n   2   7   3   1 9 \n   2   5   6   1 8 \n   2   0   0   1 12 \n   3   4   4   1 11 \n   9   4   6   1 11 \n   4   5   4   1 11 \n   3   5   6   1 21\n   3   7   5   1 21\n   6   9   6   1 21\n   4   7   0   1 21\n   7   6   3   1 21\n   2   5   3   1 21\n   1   3   7   1 21\n   1   0   6   1 21\n   2   6   4   1 21\n   5   4   8   1 21\n   0   0   0   0<\/code><\/pre>\n<p class=\"wp-block-paragraph\">The first line of the <code>.rcp<\/code> instance is always empty. The next line contains the number of project tasks\/activities (including the dummy start and dummy end activities), followed by the number of resources <code>k<\/code>. In our project, we have two resources. Starting with the fourth line of the text file, you&#8217;ll find data specific to each project task\/activity. The first column contains the duration <code>p_i<\/code> of the activities. The next <code>k<\/code> columns provide information on the amount of resources required <code>u_{i,k}<\/code>\u200b for activity <code>i<\/code> and resource <code>k<\/code>. The subsequent columns contain the precedence constraints, listing the activities that have activity <code>i<\/code> as a predecessor. For example, in the instance below, activities 11, 2, 3, 4, 5, 6, 10, 16, 17, 18, 19, and 20 require activity 1 to be completed before they can start.<\/p>\n<h2 class=\"wp-block-heading\">Installing the libraries and setting up the Colab environment<\/h2>\n<p class=\"wp-block-paragraph\">In this section, we&#8217;ll walk through the steps to install and import the necessary libraries for solving our project scheduling problem, including setting up your D-Wave environment in Google Colab. We&#8217;ll also install <code>[cheche_pm](https:\/\/pypi.org\/project\/cheche-pm\/)<\/code>, a <a href=\"https:\/\/pypi.org\/project\/cheche-pm\/\">Python library<\/a> I developed to simplify importing project data and constructing the required data structures for our optimization model. If you&#8217;re unfamiliar with <code>cheche_pm<\/code>, I recommend checking out another article where I&#8217;ve detailed its functionalities for a deeper understanding of its capabilities.<\/p>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p><a href=\"https:\/\/medium.com\/@luisfernandopa1212\/efficient-project-scheduling-with-python-the-critical-path-method-19a3f8235f91\"><strong>Efficient Project Scheduling with Python. The Critical Path Method<\/strong><\/a><\/p><\/blockquote>\n<p class=\"wp-block-paragraph\">Let&#8217;s start first with getting your D-wave leap API token.<\/p>\n<ul class=\"wp-block-list\">\n<li>\n<ol class=\"wp-block-list\">\n<li>Go to <a href=\"https:\/\/cloud.dwavesys.com\/leap\/login\/?next=\/leap\/\">https:\/\/cloud.dwavesys.com\/leap\/login\/?next=\/leap\/<\/a> and click on sign-up to create a new account. Please note that to create an account, you are going to be asked to provide the address to one of your GitHub repo&#8217;s.<\/li>\n<\/ol>\n<\/li>\n<\/ul>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"87868e\" data-has-transparency=\"false\" style=\"--dominant-color: #87868e;\" loading=\"lazy\" decoding=\"async\" width=\"1551\" height=\"866\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1dAvj0I80FRV8n-eIYaR3Cg-1.png\" alt=\"Figure 14. Dwave-Leap site (Snapshot taken by the author)\" class=\"wp-image-314012 not-transparent\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1dAvj0I80FRV8n-eIYaR3Cg-1.png 1551w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1dAvj0I80FRV8n-eIYaR3Cg-1-300x168.png 300w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1dAvj0I80FRV8n-eIYaR3Cg-1-1024x572.png 1024w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1dAvj0I80FRV8n-eIYaR3Cg-1-768x429.png 768w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1dAvj0I80FRV8n-eIYaR3Cg-1-1536x858.png 1536w\" sizes=\"auto, (max-width: 1551px) 100vw, 1551px\" \/><figcaption class=\"wp-element-caption\">Figure 14. Dwave-Leap site (Snapshot taken by the author)<\/figcaption><\/figure>\n<ul class=\"wp-block-list\">\n<li>\n<ol class=\"wp-block-list\" start=\"2\">\n<li>Once you have created your account, please proceed to login and on the left-down side of your dashboard you will find your personnel API token.<\/li>\n<\/ol>\n<\/li>\n<\/ul>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"f3f3f4\" data-has-transparency=\"true\" style=\"--dominant-color: #f3f3f4;\" loading=\"lazy\" decoding=\"async\" width=\"2000\" height=\"1057\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1Zk42R_PILfQoPsBWhnb5FQ-1.png\" alt=\"Figure 15. Dwave-Leap dashboard (Snapshot taken by the author)\" class=\"wp-image-314013 has-transparency\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1Zk42R_PILfQoPsBWhnb5FQ-1.png 2000w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1Zk42R_PILfQoPsBWhnb5FQ-1-300x159.png 300w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1Zk42R_PILfQoPsBWhnb5FQ-1-1024x541.png 1024w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1Zk42R_PILfQoPsBWhnb5FQ-1-768x406.png 768w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1Zk42R_PILfQoPsBWhnb5FQ-1-1536x812.png 1536w\" sizes=\"auto, (max-width: 2000px) 100vw, 2000px\" \/><figcaption class=\"wp-element-caption\">Figure 15. Dwave-Leap dashboard (Snapshot taken by the author)<\/figcaption><\/figure>\n<ul class=\"wp-block-list\">\n<li>\n<ol class=\"wp-block-list\" start=\"3\">\n<li>Copy your API token and paste it in the secrets tab of google colab using the key name <code>dwave_leap<\/code>. We will later import this secret key into the python session without having to reveal it, similar as the process of importing keys from a <code>.env<\/code> file.<\/li>\n<\/ol>\n<\/li>\n<\/ul>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"f3f4f4\" data-has-transparency=\"false\" style=\"--dominant-color: #f3f4f4;\" loading=\"lazy\" decoding=\"async\" width=\"605\" height=\"588\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1jeuZX9DLJSAZ29e9VbeTKg-1.png\" alt=\"Figure 16. Google Colab Secrets (Snapshot taken by the author)\" class=\"wp-image-314014 not-transparent\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1jeuZX9DLJSAZ29e9VbeTKg-1.png 605w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1jeuZX9DLJSAZ29e9VbeTKg-1-300x292.png 300w\" sizes=\"auto, (max-width: 605px) 100vw, 605px\" \/><figcaption class=\"wp-element-caption\">Figure 16. Google Colab Secrets (Snapshot taken by the author)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Now that we have our D-wave key, let&#8217;s proceed to install and import the required libraries and setup the development environment. We can achieve this by following the snippet of code below.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">!pip install cheche_pm\n!pip install dwave-ocean-sdk\n\nfrom itertools import product\nfrom dwave.system.samplers import DWaveSampler\nfrom dwave.system.composites import EmbeddingComposite\nfrom dimod import ConstrainedQuadraticModel, CQM, SampleSet,\nfrom dwave.system import LeapHybridCQMSampler\nfrom dimod.vartypes import Vartype\nfrom dimod import Binary, quicksum\nfrom cheche_pm import Project \nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport requests\nfrom google.colab import userdata<\/code><\/pre>\n<p class=\"wp-block-paragraph\">We will now proceed to setup the D-Wave key using the <code>userdata.get<\/code> method of google colab.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">endpoint = &#039;https:\/\/cloud.dwavesys.com\/sapi&#039;\ntoken = userdata.get(&#039;dwave_leap&#039;) <\/code><\/pre>\n<p class=\"wp-block-paragraph\">Now that the environment is set up, let&#8217;s move on to importing the project data and generating the required data structures. We&#8217;ll use some of the functionalities of <code>cheche_pm<\/code> for this. I&#8217;ve coded a method that allows us to read RCPSP instances directly from a .rcp file. We&#8217;ll use this method to download the <a href=\"https:\/\/raw.githubusercontent.com\/ceche1212\/medium_rcpsp_dwave_cqm\/main\/RCPSP_19_instance.rcp\">instance data from my GitHub repo<\/a>, import it into our Colab session, and create a Project instance by reading the <code>.rcp<\/code> file..<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">url = &#039;https:\/\/raw.githubusercontent.com\/ceche1212\/medium_rcpsp_dwave_cqm\/main\/RCPSP_19_instance.rcp&#039;\n\nresponse = requests.get(url)\n\n# Check if the request was successful\nif response.status_code == 200:\n    # Write the content to a file\n    with open(&quot;instance.rcp&quot;, &quot;w&quot;) as file:\n        file.write(response.text)\n    print(&quot;File downloaded and saved as &#039;instance.rcp&#039;&quot;)\nelse:\n    print(&quot;Failed to download the file. Status code:&quot;, response.status_code)\n\nproject = Project.from_rangen_1_rcp_file(&#039;instance.rcp&#039;)\nproject.create_project_dict()<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Now that we have the project data, let&#8217;s visualize it using a project network diagram. This diagram represents a graph <code>G(V,S)<\/code> where each node in <code>V<\/code> is a project activity and each edge in <code>S<\/code> represents a precedence constraint. We can create this diagram using the <code>.plot_network_diagram<\/code> function from <code>cheche_pm<\/code>, which leverages <code>pydot<\/code> to generate and plot the graph.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">project.plot_network_diagram()<\/code><\/pre>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"fafafa\" data-has-transparency=\"false\" style=\"--dominant-color: #fafafa;\" loading=\"lazy\" decoding=\"async\" width=\"1000\" height=\"1000\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1YjIHKMvYpXUW3OhWnG0UQQ-1.jpeg\" alt=\"Figure 17. Project Network Diagram (Image created by the author)\" class=\"wp-image-314015 not-transparent\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1YjIHKMvYpXUW3OhWnG0UQQ-1.jpeg 1000w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1YjIHKMvYpXUW3OhWnG0UQQ-1-300x300.jpeg 300w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1YjIHKMvYpXUW3OhWnG0UQQ-1-150x150.jpeg 150w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1YjIHKMvYpXUW3OhWnG0UQQ-1-768x768.jpeg 768w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><figcaption class=\"wp-element-caption\">Figure 17. Project Network Diagram (Image created by the author)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">We can also generate the data structures typically needed to formulate an RCPSP instance as a MILP. The <code>cheche_pm<\/code> library includes a method called <code>.produce_outputs_for_MILP<\/code>, which outputs a dictionary containing all the necessary data structures.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">n,p,S,U,C,naive_ph = project.produce_outputs_for_MILP().values()<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Here, <code>n<\/code> represents the number of project activities, <code>p<\/code> is a list of activity durations, <code>S<\/code> is a list of all precedence constraints, <code>U<\/code> is a list of resource consumption for each activity and each resource, and <code>C<\/code> is a list of resource capacities. The naive project duration, or time horizon <code>naive_ph<\/code>, is the sum of all activity durations, which is equivalent to executing the activities sequentially.<\/p>\n<p class=\"wp-block-paragraph\">As I mentioned in the introduction of this article, qubits are a precious resource. Our formulation requires a number of variables\/qubits equal to the combination of <code>n+2<\/code> activities and <code>t<\/code> potential start times, with <code>t<\/code> ranging from 0 up to the time horizon <code>naive_ph<\/code>. Currently, the <code>naive_ph<\/code> for this project instance is 65 days, meaning we&#8217;re using a very conservative upper bound. If we can find a better upper bound, we can drastically reduce the number of qubits required and make the quantum annealer&#8217;s job easier. Fortunately, there are many constructive heuristics for project scheduling that can help us establish a better upper bound for the project time horizon. The <code>cheche_pm<\/code> library includes a collection of these heuristics, which we can easily call by following the code snippet below.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">heuristic = project.run_all_pl_heuristics(max_resources=C)\nnew_ph = heuristic[&#039;makespan&#039;]<\/code><\/pre>\n<p class=\"wp-block-paragraph\">The method generates a bar graph showing the different makespans for each heuristic tested by <code>cheche_pm<\/code>.<\/p>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"bd86c3\" data-has-transparency=\"false\" style=\"--dominant-color: #bd86c3;\" loading=\"lazy\" decoding=\"async\" width=\"1380\" height=\"581\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1CxlyNeVeWQQoZnMxVvo7tQ-1.png\" alt=\"Figure 18. Bar graph of the makespan of different heuristics tested (Image created by the author)\" class=\"wp-image-314016 not-transparent\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1CxlyNeVeWQQoZnMxVvo7tQ-1.png 1380w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1CxlyNeVeWQQoZnMxVvo7tQ-1-300x126.png 300w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1CxlyNeVeWQQoZnMxVvo7tQ-1-1024x431.png 1024w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1CxlyNeVeWQQoZnMxVvo7tQ-1-768x323.png 768w\" sizes=\"auto, (max-width: 1380px) 100vw, 1380px\" \/><figcaption class=\"wp-element-caption\">Figure 18. Bar graph of the makespan of different heuristics tested (Image created by the author)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Using this method, we were able to reduce the project time horizon from 65 to 40 days. This reduction allows us to save 525 qubits ((65\u221240)\u00d721), representing a significant decrease in qubit usage, thanks to simple heuristics that run in fractions of a second.<\/p>\n<p class=\"wp-block-paragraph\">Now that we&#8217;ve optimized our project time horizon and gathered all the necessary data, let&#8217;s proceed to optimize the project schedule using the quantum annealer.<\/p>\n<h2 class=\"wp-block-heading\">D-wave CQM for the RCPSP<\/h2>\n<p class=\"wp-block-paragraph\">D-Wave offers various methods for solving optimization problems. If your problem is already in QUBO form, you can create a Binary Quadratic Model (BQM) and solve it. That&#8217;s exactly what I did in <a href=\"https:\/\/www.nature.com\/articles\/s41598-024-67168-6\">my research article<\/a>. However, in this article, I wanted to demonstrate a simplified process that allows you to use the quantum annealer with a framework and language similar to those used by other commercial tools like Pyomo, CPLEX or Gurobi.<\/p>\n<p class=\"wp-block-paragraph\">Here, we&#8217;ll use D-Wave&#8217;s Constrained Quadratic Model (CQM), which employs a hybrid quantum-classical approach. This approach simplifies the formulation process and enables us to solve larger problem instances. With the current Advantage 6.4 quantum annealer and the CQM solver, we can tackle problems with up to 1 million binary variables. In contrast, D-Wave&#8217;s purely quantum BQM method is limited to 5,760 available qubits, making it unsuitable for the project size we&#8217;re addressing in this article. The advantage of using a BQM, is that you have total control of the annealing parameters and the schedule, moreover you can use more advanced techniques such as Reverse Quantum Annealing, which is similar as starting the annealing evolution from a warm start.<\/p>\n<p class=\"wp-block-paragraph\">If you&#8217;re interested in learning how to transform the RCPSP into a QUBO and solve smaller instances of the problem using the purely quantum BQM method, I cover that in detail in my research article. A link to all the BQM code used during the research is provided there, and the article is open access, so feel free to read it and download it.<\/p>\n<p class=\"wp-block-paragraph\">To create a CQM model of our project, we simply follow the code below:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">(R, J, T) = (range(len(C)), range(len(p)), range(new_ph))\n\n# Create empty model\ncqm=ConstrainedQuadraticModel()\n\n# Create binary variables\nx = {(i, t): Binary(f&#039;x{i}_{t}&#039;) for i in J for t in T}\n\n# Create objective function (1)\nobjective = quicksum(t*x[(n+1,t)] for t in T)\ncqm.set_objective(objective)\n\n# Add constraint (2)\nfor a in J:\n  cqm.add_constraint( quicksum(x[(a,t)] for t in T) == 1 )\n\n# Add constraint (3) Precedence constraints\nfor (j,s) in S:\n  cqm.add_constraint( quicksum( t*x[(s,t)] - t*x[(j,t)] for t in T ) &gt;= p[j])\n\n# Add constraint (4) Resource capacity constraints\nfor (r, t) in product(R, T):\n  r_c = quicksum( U[j][r]*x[(j,t2)] for j in J for t2 in range(max(0, t - p[j] + 1), t + 1))\n  cqm.add_constraint( r_c &lt;= C[r] )\n\nprint(&quot;CQM model created with number of variables = &quot;,len(cqm.variables))<\/code><\/pre>\n<p class=\"wp-block-paragraph\">The CQM model has been created with a total of 840 variables. Now, we just need to invoke the hybrid QA sampler to solve it. First, we&#8217;ll create an empty sampler and pass in our API token and endpoint connection (defined at the start of the previous section).<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">cqm_sampler = LeapHybridCQMSampler(endpoint=endpoint, token=token,)<\/code><\/pre>\n<p class=\"wp-block-paragraph\">With the sampler created, the final step is to perform the QA evolution and retrieve the solution samples.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">problem_name = &#039;RCPSP_Medium_Article&#039;\n\nsampleset = cqm_sampler.sample_cqm(cqm,label=problem_name)\n\nannealing_solutions = len(sampleset) # number of solutions inside sampleset\n\nrunning_time = sampleset.info[&#039;run_time&#039;] # running time reported in microseconds\n\nprint(f&quot;Annealing stoped after {running_time\/1e6:.2f} seconds. {annealing_solutions} obtained&quot;)<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Solving the instance and extracting the output<\/h2>\n<p class=\"wp-block-paragraph\">After 5.002 seconds, we obtained 58 samples from the hybrid quantum annealing process. Now, let&#8217;s extract the best solution and generate the output visualizations for our project.<\/p>\n<p class=\"wp-block-paragraph\">We can create a dataframe from the results currently stored in the variable <code>sampleset<\/code>. This dataframe will have three columns: the solution, the energy (which represents the objective function value), and a boolean variable indicating whether the solution obtained from the quantum annealer is valid (feasible) or not.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-ini\">df_sampleset = sampleset.to_pandas_dataframe(sample_column=True)\ndf_sampleset = df_sampleset[[&#039;sample&#039;,&#039;energy&#039;,&#039;is_feasible&#039;]]\ndf_sampleset = df_sampleset.sort_values(by = [&#039;is_feasible&#039;,&#039;energy&#039;], ascending = [False,True])<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Let&#8217;s also proceed to extract the best feasible solution of our problem and see if the quantum annealer was able to obtain the optimal project schedule.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">try:\n  feasible_sampleset = sampleset.filter(lambda row: row.is_feasible)\n  best = feasible_sampleset.first\nexcept:\n  print(&#039;No Feasible solution found&#039;)\n\nZ = best.energy #objective value of the best solution\nX_out = best.sample #best solution\n\nprint(f&quot;Solution obtained with a final project duration of {Z} days&quot;)<\/code><\/pre>\n<p class=\"wp-block-paragraph\">The quantum annealer successfully produced a feasible project schedule with a makespan of 39 days, which corresponds to the optimal solution for this project instance. Now that we have the solution, let&#8217;s proceed to extract it into a schedule dictionary.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">SCHEDULE = dict()\nfor act in project.PROJECT:\n\n  i = project.PROJECT[act][&#039;idx&#039;]\n  for t in range(new_ph):\n    key = f&#039;x{i}_{t}&#039;\n    if X_out[key] == 1:\n      row = {&#039;ES&#039;:t,&#039;EF&#039;:t+p[i]}\n      SCHEDULE[act] = row\n      print(act,row)<\/code><\/pre>\n<p class=\"wp-block-paragraph\">With the schedule now stored in a dictionary, we can use another functionality of <code>cheche_pm<\/code> to produce a Gantt chart by calling the <code>.plot_date_gantt<\/code> method within the library.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">schedule_df = project.generate_datetime_schedule(SCHEDULE)\n\nproject.plot_date_gantt(schedule_df,plot_type = &#039;matplotlib&#039;)<\/code><\/pre>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"f5e5e5\" data-has-transparency=\"true\" style=\"--dominant-color: #f5e5e5;\" loading=\"lazy\" decoding=\"async\" width=\"989\" height=\"590\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1eoPpatNhfP9Nnpx9zHoE9Q-1.png\" alt=\"Figure 19. Gantt Chart of the solution (Image created by the author)\" class=\"wp-image-314017 has-transparency\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1eoPpatNhfP9Nnpx9zHoE9Q-1.png 989w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1eoPpatNhfP9Nnpx9zHoE9Q-1-300x179.png 300w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1eoPpatNhfP9Nnpx9zHoE9Q-1-768x458.png 768w\" sizes=\"auto, (max-width: 989px) 100vw, 989px\" \/><figcaption class=\"wp-element-caption\">Figure 19. Gantt Chart of the solution (Image created by the author)<\/figcaption><\/figure>\n<h2 class=\"wp-block-heading\">Conclusions<\/h2>\n<p class=\"wp-block-paragraph\">In conclusion, this article has guided you through a detailed process of using D-Wave&#8217;s Constrained Quadratic Model (CQM) to schedule a resource-constrained project. I&#8217;ve explained what quantum annealing is and how it can be applied to optimization problems, all based on my own <a href=\"https:\/\/www.nature.com\/articles\/s41598-024-67168-6\/figures\/3\">research<\/a>. It&#8217;s important to remember that, unlike classical optimization methods such as branch-and-bound, quantum annealing doesn&#8217;t guarantee optimality since it&#8217;s a heuristic method. However, it&#8217;s an extremely powerful heuristic that can be applied to a wide range of optimization problems.<\/p>\n<p class=\"wp-block-paragraph\">I also compared Gurobi and quantum annealing on the same instance we have worked with in this article, but this time using for both methods the naive time horizon. As shown in Figure 20, Gurobi took 446.9 seconds to produce the optimal solution of 39 days using the naive time horizon, while quantum annealing took only 5.1 seconds to generate a near-optimal solution of 40 days.<\/p>\n<figure class=\"wp-block-image size-large\"><img data-dominant-color=\"fcfbfb\" data-has-transparency=\"true\" style=\"--dominant-color: #fcfbfb;\" loading=\"lazy\" decoding=\"async\" width=\"1976\" height=\"743\" src=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1ChuwmgLtQ-ptp9eNUn9KUg-1.png\" alt=\"Figure 20. Benchmark of gurobi and D-waves CQM (Image created by the author)\" class=\"wp-image-314018 has-transparency\" srcset=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1ChuwmgLtQ-ptp9eNUn9KUg-1.png 1976w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1ChuwmgLtQ-ptp9eNUn9KUg-1-300x113.png 300w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1ChuwmgLtQ-ptp9eNUn9KUg-1-1024x385.png 1024w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1ChuwmgLtQ-ptp9eNUn9KUg-1-768x289.png 768w, https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1ChuwmgLtQ-ptp9eNUn9KUg-1-1536x578.png 1536w\" sizes=\"auto, (max-width: 1976px) 100vw, 1976px\" \/><figcaption class=\"wp-element-caption\">Figure 20. Benchmark of gurobi and D-waves CQM (Image created by the author)<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Even though quantum annealing didn&#8217;t achieve the optimal solution in this benchmark, the beauty of heuristics lies in their speed and flexibility. Heuristics can be combined with exact methods to reach the optimal solution more quickly. In fact, most commercial solvers run a series of heuristics before employing more rigorous methods. When the solution from quantum annealing was used as a warm start for Gurobi, the entire process only took 83.5 seconds (including the time for QA) to produce the optimal solution \ud83c\udf89 .<\/p>\n<p class=\"wp-block-paragraph\">In my opinion, the true beauty of quantum computing isn&#8217;t just about proving supremacy or proving clear quantum advantages; it&#8217;s about how we can combine these quantum capabilities with classical methods to create even more powerful solutions to challenging. In summary I think hybrid is the future, and that is where I am currently steering my research.<\/p>\n<p class=\"wp-block-paragraph\">You can find the entire notebook with the code developed for this article in the link to my GitHub repository just below.<\/p>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p><a href=\"https:\/\/github.com\/ceche1212\/medium_rcpsp_dwave_cqm\/blob\/main\/RCPSP_DWAVE_CQM_Medium.ipynb\"><strong>medium_rcpsp_dwave_cqm\/RCPSP_DWAVE_CQM_Medium.ipynb at main \u00b7 ceche1212\/medium_rcpsp_dwave_cqm<\/strong><\/a><\/p><\/blockquote>\n<p class=\"wp-block-paragraph\">I sincerely hope that this article had been enjoyable and had served as a helpful resource for anyone, trying to learn more about quantum computing and more specifically about quantum annealing. If so, I&#8217;d love to hear your thoughts! Please feel free to leave a comment or show your appreciation with a clap \ud83d\udc4f . And if you&#8217;re interested in staying updated on my latest articles, consider following me on Medium. Your support and feedback are what drive me to keep exploring and sharing. Thank you for taking the time to read, and stay tuned for more insights in my next article!<\/p>\n<h2 class=\"wp-block-heading\">References<\/h2>\n<ul class=\"wp-block-list\">\n<li>[1] P\u00e9rez Armas, L. F., Creemers, S., &amp; Deleplanque, S. (2024). Solving the resource constrained project scheduling problem with quantum annealing. <em>Scientific Reports<\/em>, <em>14<\/em>(1), 16784. <a href=\"https:\/\/doi.org\/10.1038\/s41598-024-67168-6\">https:\/\/doi.org\/10.1038\/s41598-024-67168-6<\/a><\/li>\n<li>[2] Albash, T., &amp; Lidar, D. A. (2018). Adiabatic quantum computation. <em>Reviews of Modern Physics<\/em>, <em>90<\/em>(1), 015002.<\/li>\n<li>[3] Kadowaki, T., &amp; Nishimori, H. (1998). Quantum annealing in the transverse Ising model. <em>Physical Review E<\/em>, <em>58<\/em>(5), 5355.<\/li>\n<li>[4] Kirkpatrick, S., Gelatt Jr, C. D., &amp; Vecchi, M. P. (1983). Optimization by simulated annealing. <em>science<\/em>, <em>220<\/em>(4598), 671\u2013680.<\/li>\n<li>[5] Istrail, S. (2000, May). Statistical mechanics, three-dimensionality and NP-completeness: I. Universality of intracatability for the partition function of the Ising model across non-planar surfaces. In <em>Proceedings of the thirty-second annual ACM symposium on Theory of computing<\/em> (pp. 87\u201396).<\/li>\n<li>[6] Glover, F., Kochenberger, G., &amp; Du, Y. (2019). Quantum Bridge Analytics I: a tutorial on formulating and using QUBO models. <em>4or<\/em>, <em>17<\/em>(4), 335\u2013371.<\/li>\n<li>[7] Blazewicz, J., Lenstra, J. K., &amp; Kan, A. R. (1983). Scheduling subject to resource constraints: classification and complexity. <em>Discrete applied mathematics<\/em>, <em>5<\/em>(1), 11\u201324.<\/li>\n<li>[8] Pritsker A, Watters L, Wolfe P (1969) Multi-project scheduling with limited resources: a zero-one programming approach. Manage Sci 16:93\u2013108<\/li>\n<li>[9] Martinis, J.M. Saving superconducting quantum processors from decay and correlated errors generated by gamma and cosmic rays. <em>npj Quantum Inf<\/em> <strong>7<\/strong>, 90 (2021). <a href=\"https:\/\/doi.org\/10.1038\/s41534-021-00431-0\">https:\/\/doi.org\/10.1038\/s41534-021-00431-0<\/a><\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>Solving the resource constrained project scheduling problem (RCPSP) with D-Wave&#8217;s hybrid constrained quadratic model (CQM)<\/p>\n","protected":false},"author":18,"featured_media":3504,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"is_member_only":true,"sub_heading":"Solving the resource constrained project scheduling problem (RCPSP) with D-Wave's hybrid constrained quadratic model (CQM)","footnotes":""},"categories":[44],"tags":[448,468,470,471,472],"sponsor":[],"coauthors":[29711],"class_list":["post-3503","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-data-science","tag-data-science","tag-deep-dives","tag-operations-research","tag-project-management","tag-quantum-computing"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v25.2 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Solving a Constrained Project Scheduling Problem with Quantum Annealing | Towards Data Science<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Solving a Constrained Project Scheduling Problem with Quantum Annealing | Towards Data Science\" \/>\n<meta property=\"og:description\" content=\"Solving the resource constrained project scheduling problem (RCPSP) with D-Wave&#039;s hybrid constrained quadratic model (CQM)\" \/>\n<meta property=\"og:url\" content=\"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/\" \/>\n<meta property=\"og:site_name\" content=\"Towards Data Science\" \/>\n<meta property=\"article:published_time\" content=\"2024-08-20T17:18:15+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-03-05T08:38:22+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1woUHmBFHvIjPXDecLnDYqg.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"1024\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Luis Fernando P\u00c9REZ ARMAS, Ph.D.\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@TDataScience\" \/>\n<meta name=\"twitter:site\" content=\"@TDataScience\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Luis Fernando P\u00c9REZ ARMAS, Ph.D.\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"29 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/\"},\"author\":{\"name\":\"TDS Editors\",\"@id\":\"https:\/\/towardsdatascience.com\/#\/schema\/person\/f9925d336b6fe962b03ad8281d90b8ee\"},\"headline\":\"Solving a Constrained Project Scheduling Problem with Quantum Annealing\",\"datePublished\":\"2024-08-20T17:18:15+00:00\",\"dateModified\":\"2025-03-05T08:38:22+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/\"},\"wordCount\":5171,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/towardsdatascience.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1woUHmBFHvIjPXDecLnDYqg.jpg\",\"keywords\":[\"Data Science\",\"Deep Dives\",\"Operations Research\",\"Project Management\",\"Quantum Computing\"],\"articleSection\":[\"Data Science\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/\",\"url\":\"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/\",\"name\":\"Solving a Constrained Project Scheduling Problem with Quantum Annealing | Towards Data Science\",\"isPartOf\":{\"@id\":\"https:\/\/towardsdatascience.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1woUHmBFHvIjPXDecLnDYqg.jpg\",\"datePublished\":\"2024-08-20T17:18:15+00:00\",\"dateModified\":\"2025-03-05T08:38:22+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/#primaryimage\",\"url\":\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1woUHmBFHvIjPXDecLnDYqg.jpg\",\"contentUrl\":\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1woUHmBFHvIjPXDecLnDYqg.jpg\",\"width\":1024,\"height\":1024,\"caption\":\"Why did the dog fail quantum mechanics class? He couldn't grasp the concept of super-paws-ition. Quantum superposition is the principle where a quantum system can exist in multiple states simultaneously until it is measured, at which point it collapses into one of the possible states. (Image generated by DALLE-3)\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/towardsdatascience.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Solving a Constrained Project Scheduling Problem with Quantum Annealing\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/towardsdatascience.com\/#website\",\"url\":\"https:\/\/towardsdatascience.com\/\",\"name\":\"Towards Data Science\",\"description\":\"Publish AI, ML &amp; data-science insights to a global community of data professionals.\",\"publisher\":{\"@id\":\"https:\/\/towardsdatascience.com\/#organization\"},\"alternateName\":\"TDS\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/towardsdatascience.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/towardsdatascience.com\/#organization\",\"name\":\"Towards Data Science\",\"alternateName\":\"TDS\",\"url\":\"https:\/\/towardsdatascience.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/towardsdatascience.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2025\/02\/tds-logo.jpg\",\"contentUrl\":\"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2025\/02\/tds-logo.jpg\",\"width\":696,\"height\":696,\"caption\":\"Towards Data Science\"},\"image\":{\"@id\":\"https:\/\/towardsdatascience.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/TDataScience\",\"https:\/\/www.youtube.com\/c\/TowardsDataScience\",\"https:\/\/www.linkedin.com\/company\/towards-data-science\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/towardsdatascience.com\/#\/schema\/person\/f9925d336b6fe962b03ad8281d90b8ee\",\"name\":\"TDS Editors\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/towardsdatascience.com\/#\/schema\/person\/image\/23494c9101089ad44ae88ce9d2f56aac\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/?s=96&d=mm&r=g\",\"caption\":\"TDS Editors\"},\"description\":\"Building a vibrant data science and machine learning community. Share your insights and projects with our global audience: bit.ly\/write-for-tds\",\"url\":\"https:\/\/towardsdatascience.com\/author\/towardsdatascience\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Solving a Constrained Project Scheduling Problem with Quantum Annealing | Towards Data Science","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/","og_locale":"en_US","og_type":"article","og_title":"Solving a Constrained Project Scheduling Problem with Quantum Annealing | Towards Data Science","og_description":"Solving the resource constrained project scheduling problem (RCPSP) with D-Wave's hybrid constrained quadratic model (CQM)","og_url":"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/","og_site_name":"Towards Data Science","article_published_time":"2024-08-20T17:18:15+00:00","article_modified_time":"2025-03-05T08:38:22+00:00","og_image":[{"width":1024,"height":1024,"url":"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1woUHmBFHvIjPXDecLnDYqg.jpg","type":"image\/jpeg"}],"author":"Luis Fernando P\u00c9REZ ARMAS, Ph.D.","twitter_card":"summary_large_image","twitter_creator":"@TDataScience","twitter_site":"@TDataScience","twitter_misc":{"Written by":"Luis Fernando P\u00c9REZ ARMAS, Ph.D.","Est. reading time":"29 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/#article","isPartOf":{"@id":"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/"},"author":{"name":"TDS Editors","@id":"https:\/\/towardsdatascience.com\/#\/schema\/person\/f9925d336b6fe962b03ad8281d90b8ee"},"headline":"Solving a Constrained Project Scheduling Problem with Quantum Annealing","datePublished":"2024-08-20T17:18:15+00:00","dateModified":"2025-03-05T08:38:22+00:00","mainEntityOfPage":{"@id":"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/"},"wordCount":5171,"commentCount":0,"publisher":{"@id":"https:\/\/towardsdatascience.com\/#organization"},"image":{"@id":"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/#primaryimage"},"thumbnailUrl":"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1woUHmBFHvIjPXDecLnDYqg.jpg","keywords":["Data Science","Deep Dives","Operations Research","Project Management","Quantum Computing"],"articleSection":["Data Science"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/","url":"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/","name":"Solving a Constrained Project Scheduling Problem with Quantum Annealing | Towards Data Science","isPartOf":{"@id":"https:\/\/towardsdatascience.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/#primaryimage"},"image":{"@id":"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/#primaryimage"},"thumbnailUrl":"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1woUHmBFHvIjPXDecLnDYqg.jpg","datePublished":"2024-08-20T17:18:15+00:00","dateModified":"2025-03-05T08:38:22+00:00","breadcrumb":{"@id":"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/#primaryimage","url":"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1woUHmBFHvIjPXDecLnDYqg.jpg","contentUrl":"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2024\/08\/1woUHmBFHvIjPXDecLnDYqg.jpg","width":1024,"height":1024,"caption":"Why did the dog fail quantum mechanics class? He couldn't grasp the concept of super-paws-ition. Quantum superposition is the principle where a quantum system can exist in multiple states simultaneously until it is measured, at which point it collapses into one of the possible states. (Image generated by DALLE-3)"},{"@type":"BreadcrumbList","@id":"https:\/\/towardsdatascience.com\/solving-a-constrained-project-scheduling-problem-with-quantum-annealing-d0640e657a3b\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/towardsdatascience.com\/"},{"@type":"ListItem","position":2,"name":"Solving a Constrained Project Scheduling Problem with Quantum Annealing"}]},{"@type":"WebSite","@id":"https:\/\/towardsdatascience.com\/#website","url":"https:\/\/towardsdatascience.com\/","name":"Towards Data Science","description":"Publish AI, ML &amp; data-science insights to a global community of data professionals.","publisher":{"@id":"https:\/\/towardsdatascience.com\/#organization"},"alternateName":"TDS","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/towardsdatascience.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/towardsdatascience.com\/#organization","name":"Towards Data Science","alternateName":"TDS","url":"https:\/\/towardsdatascience.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/towardsdatascience.com\/#\/schema\/logo\/image\/","url":"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2025\/02\/tds-logo.jpg","contentUrl":"https:\/\/towardsdatascience.com\/wp-content\/uploads\/2025\/02\/tds-logo.jpg","width":696,"height":696,"caption":"Towards Data Science"},"image":{"@id":"https:\/\/towardsdatascience.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/TDataScience","https:\/\/www.youtube.com\/c\/TowardsDataScience","https:\/\/www.linkedin.com\/company\/towards-data-science\/"]},{"@type":"Person","@id":"https:\/\/towardsdatascience.com\/#\/schema\/person\/f9925d336b6fe962b03ad8281d90b8ee","name":"TDS Editors","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/towardsdatascience.com\/#\/schema\/person\/image\/23494c9101089ad44ae88ce9d2f56aac","url":"https:\/\/secure.gravatar.com\/avatar\/?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/?s=96&d=mm&r=g","caption":"TDS Editors"},"description":"Building a vibrant data science and machine learning community. Share your insights and projects with our global audience: bit.ly\/write-for-tds","url":"https:\/\/towardsdatascience.com\/author\/towardsdatascience\/"}]}},"distributor_meta":false,"distributor_terms":false,"distributor_media":false,"distributor_original_site_name":"Towards Data Science","distributor_original_site_url":"https:\/\/towardsdatascience.com","push-errors":false,"_links":{"self":[{"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/posts\/3503","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/users\/18"}],"replies":[{"embeddable":true,"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/comments?post=3503"}],"version-history":[{"count":0,"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/posts\/3503\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/media\/3504"}],"wp:attachment":[{"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/media?parent=3503"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/categories?post=3503"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/tags?post=3503"},{"taxonomy":"sponsor","embeddable":true,"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/sponsor?post=3503"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/towardsdatascience.com\/wp-json\/wp\/v2\/coauthors?post=3503"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}