Quantum Solar Optimization

How it works

The technical details

How a home battery schedule becomes something a quantum computer can solve, and how I make sure the answers are right. Written as the questions a technical reader tends to ask.

What kind of problem is this, really?

The day is split into time slots. In each slot the battery can charge, discharge, or sit idle, and the choices are linked: charging now fills the battery, which limits what you can discharge later. That coupling across time is what makes it a genuine combinatorial optimization problem, with on the order of 10 billion (10¹⁰) possible schedules for a single day. You cannot just try them one by one as the problem grows.

What exactly goes in, and what comes out?

An instance is a day split into T time slots, with three aligned hourly series (price in $/kWh, solar generation in kWh, household load in kWh) plus the battery's parameters: usable capacity, per-slot charge/discharge power, and starting state of charge. Every solver returns the same shape of answer: a charge/discharge decision for each slot, from which the state-of-charge trajectory and the day's total cost follow. The quantum path is the one difference: QAOA does not return a single answer but a distribution. Measuring the circuit thousands of times yields thousands of candidate bit-strings with counts, each decoding to a schedule; I score them and keep the best feasible one. Identical inputs and outputs across solvers are what make the three-way comparison fair.

How do you turn a schedule into something a quantum computer can optimize?

I write each slot's choices as binary variables (charge on/off, discharge on/off) and express the electricity cost as a QUBO, a quadratic function of those bits. A QUBO maps directly onto an Ising Hamiltonian, the energy function a quantum optimizer minimizes. Finding its lowest-energy state is the same as finding the cheapest schedule.

How do you enforce the battery’s physical limits?

The state of charge must stay between empty and full in every slot. Because the state of charge is a running sum of the charge and discharge choices, that limit is a one-sided inequality, and a plain quadratic cannot represent a one-sided cutoff. So I use the standard technique: slack variables. Extra bits encode how much room is left, turning each inequality into an equality that I square into a penalty. When the schedule is physically valid the penalty is exactly zero; when it is not, the penalty adds cost. It is an exact encoding, not an approximation.

How do you choose the penalty strength?

The penalties have to outweigh any money the solver could save by breaking a rule, or it would “cheat” by draining a battery it never filled. So I scale the penalty weights to the size of the cost itself: large enough to dominate, but not so large that they drown out the optimization. A small helper computes them from the problem's price range.

How is it actually solved on the quantum side?

With QAOA (the Quantum Approximate Optimization Algorithm) on Qiskit's Aer simulator. I hand-built the variational loop from the ansatz, the simulator, and a classical optimizer, rather than calling a black-box library, so every step is explicit and testable, and so I actually understand what each part does. A full walkthrough with the runnable code, from the battery day to the circuit to IBM's hardware, is on the quantum implementation page.

How can my ordinary laptop imitate a quantum computer?

Because quantum mechanics, for all its strangeness, is exactly predictable arithmetic. Physics says the complete state of n qubits is a list of 2n numbers, one for each possible outcome: two qubits is a list of four numbers, and my 22-qubit test problem is a list of about 4 million. The simulator stores that list in memory. Each quantum gate is a matrix, and running the circuit means multiplying the list by one matrix after another, ordinary arithmetic. So my laptop imitates a quantum computer the way a weather model imitates a storm: nothing quantum happens inside the machine.

Interference is not faked either; it falls out of the arithmetic. The numbers in the list can be negative, so when two paths lead to the same outcome they can reinforce (+0.5 and +0.5) or cancel (+0.5 and -0.5). That canceling is interference, and QAOA's whole job of making cheap schedules likely is, on the simulator, additions where some terms carry minus signs. Measurement is just as plain: square each number to get a probability, then roll dice by those probabilities. The 4,096 draws in my results were 4,096 dice rolls.

The catch is the size of the list. Every qubit doubles it. My 6-qubit test problems need only 64 numbers, but each round of tuning updates the whole list again and again, which is why the 22-qubit simulation took about 20 to 40 minutes. At about 30 qubits, roughly a billion numbers, the list outgrows my laptop's memory. At 50 it outgrows every classical computer on Earth. At the 156 qubits of ibm_fez, the list would need roughly as many numbers as there are atoms in all of Earth's oceans. A real quantum chip never stores this list at all: its qubits simply are the physical state the list describes, and nature carries the bookkeeping for free. That doubling is the wall, and it is also the entire reason quantum computers might someday matter.

One more consequence: because the simulation is exact arithmetic, its qubits are perfect and noise free, the ideal machine. Real qubits are not, which is exactly why the simulator and hardware results differed, and why running on ibm_fez was the actual test.

How do you know the answer is correct?

I solve the same problem three independent ways: brute force (try every schedule, correct by definition but only practical for small days), a dynamic program (exact and efficient), and QAOA (the quantum method). On every test instance so far, all three agree, and the full test suite runs automatically in CI on every change, so a mistake would be caught immediately. This three-way agreement is the backbone of the project.

Why compare the classical solvers by cost, not by identical schedules?

Two different schedules can cost exactly the same, for example charging in one cheap hour instead of another equally cheap hour. So requiring the brute-force and dynamic-program answers to be identical would sometimes flag a disagreement when both are, in fact, optimal. The right check is that they reach the same minimum cost and that the schedule is physically feasible. That is the invariant the tests assert.

Have the checks themselves ever been challenged?

Once so far. A reviewer flagged the uniform-random baseline in the scaling study as a statistical bug. Before changing anything, I tested the claim: an independent Monte Carlo simulation draws thousands of random schedules, scores the best of each batch empirically, and compares the result against the closed-form formula the reviewer questioned. The two agreed; the formula was correct, and the docstring now explains it more clearly. That Monte Carlo comparison stayed in the test suite as a permanent regression test, so the baseline is re-verified on every future change.

Why is the dynamic program exact and fast?

Battery scheduling has optimal substructure: the cheapest way to reach a given battery level at a given hour does not depend on how you got there. That lets a dynamic program build the best schedule step by step across a grid of battery levels, in time that grows roughly linearly with the number of hours instead of exponentially. It is both my efficient exact solver and the yardstick I hold QAOA against.

If a classical program already solves this exactly, why use a quantum computer at all?

For one home on one day, you do not need one: the dynamic program solves it exactly and almost instantly, and I say so plainly. The quantum side matters for two reasons. First, having an exactly solvable version is the only way to really test a quantum method, because I know the right answer and can measure precisely how close QAOA gets. Second, the reason to care about quantum optimization is scale: coordinating many homes, or a whole neighborhood of batteries, at fine time resolution makes the exact classical methods blow up, and that harder regime is where quantum approaches are being explored. This project is the small, checkable version of that larger question.

Wait, couldn't every house just run my program itself?

Yes, and that is the right first instinct. Different homes just mean different inputs to the same easy problem, and my program solves any one of them in a tenth of a millisecond. Ten thousand independent homes is ten thousand independent solves, no quantum computer required. Any pitch that jumps from “many households” straight to “therefore quantum” is skipping something.

What it skips is that at scale the homes stop being independent. A neighborhood transformer can only carry so much charging at once, and every battery reading the same price schedule reaches the same conclusion at the same moment: charge now, it is cheap. Two hundred individually perfect plans can add up to a physically impossible one, and enough batteries chasing the same cheap hours reshape the very demand pattern the prices were built on, creating a new spike at the exact moment the cheap rate begins. Once your best plan depends on what your neighbors' batteries do, the problem couples, and coupled planning is where exact classical methods hit their own exponential wall, the same doubling that stopped my laptop, now on the classical side.

Even then, classical computing does not simply give up: clever decomposition methods keep a fast per-house solver as the inner engine and coordinate the fleet around it, and they work well. The quantum bet lives at the far end, on problems so tightly coupled that even the clever classical tricks degrade, and whether quantum methods will ever win there is an open question. My one-house problem is a scale model of that giant, small enough that I know the exact answer, so I can measure how far today's quantum methods actually stand from the goal. Right now, the measured distance is large.

How well does QAOA actually do on this problem?

Measured, not guessed: the study is committed to the repo (docs/results) as a CSV and four plots, all produced on the noise-free Aer simulator. Across instances from 2 to 6 time slots (6 to 22 qubits once slack variables are counted), with up to 3 QAOA layers, 4,096 shots, and multiple restarts: at 6 qubits QAOA returns the exact optimum on every instance, by 14 qubits only sometimes, and at 18 to 22 qubits, with this few layers, never.

The yardstick for sampling quality is the exact probability that a single uniformly random bit-string is optimal, computed by counting the optimal states (the formula the Monte Carlo regression test guards). Against it, the 6-qubit results were mixed: the best runs put 2 to 4.5 times more probability on optimal schedules than chance, the single-layer circuit roughly doubled the odds averaged across instances, and several deeper runs fell well below the random baseline. Beyond about 14 qubits the optimal mass drops below what 4,096 shots can resolve, so only upper bounds remain.

The exact dynamic program answers every one of these instances in a fraction of a millisecond. So on today's setup the quantum method is measurably better than guessing and far slower and less accurate than the classical solver, and there are now numbers that say precisely by how much. The chart further down this page shows the headline comparison.

If the simulator is perfect, why run IBM's real machine at all?

The short answer: at my problem sizes, not for the answers. The simulator computes them instantly, exactly, for free. If the goal were just the result, real hardware would add only queue time and noise.

I need it for three other things. First, to turn a prediction into an experiment. Everything from the simulator is theory: the exactly calculated forecast of what an ideal quantum computer would do. The hardware run is the moment this project stops saying “quantum mechanics implies these statistics” and starts saying “I sent these circuits to actual superconducting qubits near absolute zero, and here is what came back.” Second, to measure the one thing the simulator cannot contain: noise. Real qubits drift, gates misfire slightly, readouts flip, and how much depends on the specific chip, the specific day, and my specific circuits. The gap between the ideal distribution I already have and the hardware distribution I can only measure is a number that exists nowhere except in the experiment. It also probes a real tension: deeper circuits should be sharper in theory but are noisier in practice, and I compared one layer against two on the real machine (the outcome did not settle it cleanly; the ordering reflected how well each circuit had been tuned more than its depth). Third, because the simulator is a dead end and hardware is the road. My own scaling study walked up to that wall: past about 30 qubits my laptop cannot even hold the list, and past about 50 no classical computer on Earth can. Any future where quantum optimization matters runs on hardware by necessity. So I am doing what you should do with any vehicle before trusting it past the last checkpoint you can verify: driving it on the stretch of road where I still know the right answer.

In one line: the simulator tells me what a perfect quantum computer would do. The last question is what a real one does, and that can only be measured, not simulated.

How was the run on real hardware set up?

Three gated stages, so nothing reaches the real machine by accident:

  1. Tune. Set the QAOA angles on the local simulator and save them. This is done, and the parameters are committed to the repo.
  2. Dry run. Print the chosen backend, the transpiled circuits, the shot count (4,096), and the estimated seconds of QPU time, without submitting anything.
  3. Submit. Send it for real, only behind an explicit confirmation flag, so IBM's roughly ten free minutes a month cannot be spent by accident.

An analysis notebook then compares the sampled schedules from three sources (exact solver, simulator, and hardware), including the total variation distance between the distributions, to measure how much real-device noise changes the answer.

The run is also pre-registered: a document committed before any hardware results exist records the circuits (four tuned QAOA circuits, 6 to 10 qubits, on an IBM Heron device), the metrics, the interpretation rules for each possible outcome, and a falsifiable prediction: the shallower reps=1 circuit should retain at least as much optimal-state mass as the deeper reps=2 circuit, because extra two-qubit gates add device noise. The analysis pipeline was rehearsed end to end on synthetic counts, so when the real counts came back from ibm_fez they dropped into a finished report. The results are on the project page.

How does real-world data get into the model?

Three loaders, all real and mutually coherent for Golden, Colorado:

  • Solar comes from NREL's PVWatts model through its public API: given a location and a panel setup, it returns a physically modeled hourly generation profile, which I validate with sanity checks (no generation at night, plausible daytime peaks) and test offline against saved responses, so the test suite never depends on the network.
  • Prices come from the OpenEI Utility Rate Database entry for Xcel Energy's Colorado Residential Energy TOU tariff (Schedule RE-TOU), flattened into an hourly $/kWh series using all-in prices, with the tariff snapshot and its caveats documented in the repo.
  • Household load comes from NREL's ResStock End-Use Load Profiles: a representative Colorado single-family-detached summer-weekday profile, about 30.5 kWh per day, packaged as a local CSV with no network calls and its derivation documented.

What does the optimal plan actually save on a real day?

On the real summer-weekday instance (PVWatts solar, RE-TOU prices, ResStock load), the house with no solar and no battery pays $6.11 for the day; with solar and an idle battery, $1.43; with the DP-optimal battery schedule, -$0.50, slightly ahead. Solar alone accounts for $4.68 of the saving; optimal scheduling adds $1.93 of pure price arbitrage, a figure independent of the load level, since arbitrage only moves energy across prices. The schedule is also required to end the day with the battery at its starting level, so the saving cannot come from secretly spending down charge that tomorrow would have to buy back.

Three caveats before extrapolating from this one day:

  • The RE-TOU weekend schedule is flat, so arbitrage is worth $0 two days a week.
  • Winter TOU prices are lower, so an annual figure needs representative days across seasons.
  • The model currently assumes net metering at the retail rate with no round-trip battery losses.

Both refinements are on the roadmap.

How is the schedule chart generated?

A plotting script takes a problem instance and its solved schedule and draws two aligned panels with matplotlib. The top panel shows the inputs: the time-of-use price on one axis, household load and solar generation on the other. The bottom panel shows the decisions: charge and discharge as signed bars, with the state of charge overlaid as a line, so you can verify by eye that the plan charges in cheap or sunny hours, discharges at the evening peak, and never pushes the battery outside its limits. The chart on the project page is the real Golden, Colorado summer weekday, drawn from the re-executed demo notebook; the repo README keeps a synthetic example day as its preview.

What are the limits, and what is next?

With only a few QAOA layers the quantum result usually will not perfectly match the exact optimum; the scaling study above puts numbers on exactly that, and the hardware run showed how much more the real machine's noise takes away (only the smallest circuit beat random guessing on ibm_fez). The data layer is fully real (PVWatts solar, RE-TOU prices, ResStock load). What remains: extending the one-day saving to an annualized figure with representative seasonal days and the flat weekend tariff; adding asymmetric buy/sell rates and round-trip battery losses to the cost model; and comparing slack-free approximate encodings against the exact one to study how each scales.

Measured

The scaling picture

One chart from the study: how the quantum method compares with random guessing as the problem grows.

Log-scale chart titled Quantum method vs random guessing, showing the ratio of QAOA's probability of producing the optimal schedule to uniform random guessing, for problems from 6 to 18 qubits and 1 to 3 QAOA layers. Solid dots at 6 qubits range from about 2 down to well below 1; larger sizes show hollow upper-limit markers with arrows inside a shaded unmeasurable band.
How much likelier than random guessing the quantum method is to land on the exact best plan. Solid dots are direct measurements. Hollow circles with arrows are upper limits: with 4,096 samples, probabilities below about 1 in 4,096 cannot be measured, so the true value lies somewhere below the marker, inside the shaded band. Above the dashed line beats guessing; below it loses. Every point on this chart is from the simulator; on the real machine, only the four smallest circuits (2 and 3 slots, 1 and 2 layers) were run. In short: a modest edge for the best settings on small problems, other settings below random, and beyond about 14 qubits the measurement itself hits its floor.

In one line

The pipeline

Battery problemQUBOIsing HamiltonianQAOA (Aer)

Every result along the way is checked against an exact dynamic program and brute-force enumeration.

Toolkit

Tools & technologies

Classical

  • Python
  • NumPy / SciPy
  • Matplotlib

Quantum

  • IBM Qiskit
  • Qiskit Aer simulator
  • QAOA

Engineering

  • pytest
  • GitHub Actions (CI)
  • Jupyter notebooks

Compute access · 2026

IBM Quantum's Open Plan is free, up to about 10 minutes of real quantum runtime every 28 days on current systems, including the 156-qubit Heron r2 processor. I develop and test on free, unlimited local simulators (Qiskit Aer) and save real-hardware time for final runs.

The short version

Back to the project