 So, Alex just gave a nice overview of how to solve a problem on D-Wave's QPU, and nice overview of our ocean stack, ocean SDK, so how to map application-specific application domain problem onto something that we currently support like graph mapping or constraint compilation and then to map that into a BQM, and then when you have a BQM, you can use some of the samplers to solve them. However, the problem Alex mentioned with what a few problems is too big to fit the QPU, then you need to resort to decomposition. You need to slice the problem onto smaller problems and solve each smaller problem on a QPU, and D-Wave Hybrid is the framework we developed. It fits in this layer of samplers. It allows you to construct a new sampler, which is a decomposing sampler. So, Hybrid stands for actually Hybrid Synchronous Decomposition Sampler Framework. It's a minimal Python framework. Heavily leverages ocean tools, and it's built atop of ocean tools. And the actual framework is just minimal syntactic glue that binds all that together, and it allows you to leverage quantum and classical resources because, as Alex mentioned, sometimes you want to solve some of the problems, portions of your problem on a classical or some sub-problems classically and some quantum, using a QPU or some other quantum machine. So, you need to have a way to combine those easily. And since they are Hybrid, basically as you will see soon, is a data flow programming model paradigm kind of language. Independent parts are executed concurrently, and concept of decomposition is inherent. So, usually when you want to use Hybrid, you have a large problem. So, problems are broken into pieces. And the concept of probabilistic sampling or probabilistic approach is embedded or quarked to Hybrid because we use sample sets or sets of samples to represent our solution. So, quick motivation. Imagine you have a pseudocode for your algorithm you want to use. Experts like that. So, you see you have some taboo search over there. You have a decomposition based on energy impact of variables at a particular sampler that you're deconstructing your problem at. Then you have some loops. Then you have some sampling on a QPU. And that usually translates to a thousand plus lines of C code. Specifically, this is QB solve and this is QB solve's code in C. And I imagine you can represent more or less the same algorithm using a few lines of Python code and a few blocks which are understood, which you can tweak or you can even create your own blocks. But the point is the structure is visible. So, the functional structure is like this, of the solver. You can see immediately you have a loop which in two branches try to run taboo. In parallel, it decomposes the problem based on energy impact, sends that off to a QPU, the one problem, combines the sub-solution back to a global sample, picks the better one. So, by the way, this red arrow here means in the racing branches, which I will mention briefly later, the concept is once the one branch is done it will interrupt the other one. It will get the best solution from the other branch. It will incorporate that into the final solution. So, we pick the better solution here by this argmin block and we'll loop until some condition is met. So, the idea is to visually outline the algorithm for code to be easy to tweak. Because you can easily tweak parameters, you can easily tweak structure. And also to extend you can create your own blocks. And benchmarking profiling is one of the core features. So, we profile by default. But also on the other hand we wanted to balance simplicity with expressiveness. So, this is not as general as it could be. You cannot build a general graph. You cannot build a terms-of-flow kind of model with this. Because we wanted to stick to functionality usually required by algorithms to be studied for decomposition. And we wanted to provide a library of such building blocks, which are then understood and easily extendable by developers. So, quick demo. I'm not sure you can see the code here. I can actually run the demo on the system. Why not? Because this is a short presentation, so I might as well spend some time on a live demo. And by the way, we have a higher latency here from Europe, but I can still ping the system. And this Wi-Fi is not that fast either. So, the total runtime for one sample is 1.5 seconds, which is pretty slow. But have in mind that it's Wi-Fi, it's Europe-to-U.S. connection. So, can you see? Yeah. Just a short piece of code. So, this is the workflow, which you saw previously. And then just before running that, okay. Actually, it's not. I'm lying. This is another one with a simulated annealing sub-sample here and not a QPU one. So, I actually need to use the QPU. Okay. I'll use this one. Sorry. So, now this is a little bit slower because the QPU block actually, in this step, where we are actually constructing the runnable object, we are contacting the wave and fetching a list of available solvers and picking the first one, which we actually use for QPU sampling. So, the workflow is defined. BQM. For this demo, I'll just use the simplest possible BQM you can imagine. Just a triangle with ABC nodes. And it's kind of a frustrated triangle. And then, based on the BQM, we will construct a state, a hybrid state, which looks, it's more or less glorified dictionary. It contains the problem and samples, but you can put whatever you want in that state. And then, you run the workflow like this. It's some state. You get the future back. And it's still running. So, it's sampling. It has several iterations that it needs to do. It's done now. We can see the results and the result is a final state, which in this case, you can see the energy is minus three and that's the ground state actually. So, yeah. Back to this. It's more or less that. So, as you might have noticed, the basic block is the class is a runable type, actually, which is a composable top-down. As you can see from the example there. And this is the one representation. This is maybe a more readable representation of the class. So, you can see that the flow which is being executed here. So, we have branch, tracing branch, arguments, samplers and all that. All components are runnable types. A runnable takes in a state and produces another state. It's executed synchronously. You can control which executor is it run in. And also, every runnable implements some traits. And traits constrain the connectivity with other blocks and also constrain input and output states. And every runnable is profiled by default. So, yeah. The other primitive of importance is the state, which is something like an immutable mapping type wrapped in a future. It's based between runnables. It carries whatever you need to do. You need to carry between runnables to solve your problem. Usually, that's a minimum. That's problem and samples or sub-problem and sub-samples. And the compliances for the input and output states is checked on runtime by each runnable. So, I would like to walk you through a small buildup of that simple example that we just saw. So, one way to modify the workflow is by tweaking parameters. For example, in the first example, on each iteration, we took only first sub-problem. Over here, we're saying, let's do rolling decomposition of 15% of the problem. And on each run, take some other sub-problem until you reach the 15% of the global problem. And you can go through, for example, the convergence criteria for your looping and things like that. But then you can easily also modify the structure. You can say, okay, let's not just run one sub-problem on each iteration. Let's unwind n sub-problems, depending on the size of the problem. And by the way, the size 50 there, that's the size of the generated sub-problem, which will be then mapped and solved on the QPU. So, for example, if we're solving this on, I don't know, a thousand variables problem on each iteration, you would have seven sub-problems or something like that. And then you would run those seven sub-problems in parallel on a QPU because, you see, we have them reproduced here. So, we would run the same set of sub-problems to seven, basically, parallel executing QPU sub-sampled blocks. And then you would introduce the results into one, and you would use that to inform and generate a new or next state in the next sample, which might be better or not than the one we got by the taboo solver. Another extension, let's say, instead of just running QPU in parallel on all the sub-problems at once, let's run maybe some other class, maybe some other sample, maybe similar to annealing, maybe just try with random variables, random values. So, we might escape the local minimum like that. And then you see the sub-sampler is defined as a parallel execution of QPU, and in this case, random sub-sampler in the workflow. And as I mentioned, and by the way, on the right-hand side, you can see the current structure of the QPU that Alex was refraining from talking, because I think it's important to understand that we are dealing with finite limits. And this is a particularly bad yield. This is not what we have in production, but in production we have more or less a full yield, and that means that every qubit is connected to exactly six other qubits as it should be connected. You see some connections here are missing. So, this is just one of the limitations you need to deal with. Decomposition is more general than that. I mean, when you're trying to multiply two large two big integers, if you cannot do it in a single cycle, you need to divide the problem and divide and conquer it. So, QPU and annealing could be thought of as a quantum machine instruction. So, one anneal cycle is actually execution of one instruction, and instruction acts on a problem, which is a full BQM, and gives you a set of samples. The thing is decomposition is there's no such thing as a general decomposition. You can't have one algorithm which will apply to any problem you have. You will need to tailor the decomposition algorithm to the problem you have at hand, and obviously the computer device. There's a paper called No Free Lunch, which talks about this. On the other hand, there's no shortage of ideas for the decomposition, how to do it. So, there are many heuristic approaches you can try, and also hybrid solvers. There are really many, many ideas how to implement them, how to approach them. And why I'm talking about this, because it's easy to construct your own runnable. You just need to extend a few methods there, and you can easily implement a new control flow block that you're missing in the hybrid. You can implement a new decomposition strategy you might have, or in your sampler, for whatever the matter. And we actually would like you to do that. It's open, it's free, so that would be great. And by the way, here on this picture here, we see the profiling thing by default. So, the timers and the counters that we have, this shows, for example, in this slipper runnable, we are sleeping for three seconds, and we can see that this patch next, the total execution is three seconds, because that's how much took for a racing branch of Taboo and Sleeper to finish. As I mentioned, contributions are very welcome. We have a list of ideas for things that could be done. I mean, the idea of hybrid is in early developer preview state, so things will be changing a lot. And not all of these are created as issues, and we have a repo, but they will, especially if someone is interested tomorrow. We have the workshop. So, I'm going to show you a little bit of what I'm going to talk about so if someone wants to hack a little bit, that would be great. Oh, yeah. And you told me I need to include a developer survey. We have a survey out in which we are trying to get a better feeling of developer requirements for hybrid and for ocean tools. So, if you feel like we would like to contribute, that would be also great. And the slides are available online so you can see the link there. Yeah. That's it. Go ahead. What is the largest number of variables you could imagine to solve using this hybrid approach? So, in the reasonable time, let's say half an hour. Yeah. Okay. So, the question is what's the reasonable number of, highest number of variables a problem could have? We could tackle with this approach. So, I'm experimenting with the problems of size 2000, 2500 variables. And I think we can, with some optimizations, we can go up to maybe 10,000 variable problems. But, yeah. So, for now, I would say around the realm of thousands of variables. But 2000 is what you have on D-Wave already? It's a good point. However, that's with a limited connectivity, right? So, imagine you have a fully connected 2000 variables, then you need to somehow decompose it, run it in sections and things like that. So, that's, yeah. Yeah. Go ahead. You mentioned at one point that you could use different methods to escape local minima. So, I was just wondering if by default the whole strategy is theoretically not guaranteed to give an answer which can escape local minima. So, the local minima problem still exists even though maybe the system is simulated on a completely quantum hardware. So, the local minima problem that still exists there or somehow circumvented? So, the question is about escaping local minima and isn't that solved by quantum device already? Something on those lines? So, the thing is sure, if you can solve, if you can fit your problem on a QPU and you can solve it on a QPU, most likely it won't, you won't get a local minima. We'll get some of the better solutions although it's a probabilistic. So, you might get some of the, and that's a good solution. However, when you're decomposing a huge problem, and I mean as Alex mentioned we have, we're working on problems of size, so hundreds of thousands of variables and eventually hopefully hybrid will get there. It's not quite there yet. But the problem is when you're decomposing and solving small problems, then sure, then you need to have some heuristic algorithm, optimization algorithm to escape local minima. Because only a sub-problem is free of that which is solved on a QPU. And you still have a larger problem and when you combine sub-problems and solutions to sub-problems, then you might still get an unoptimal solution. So, sufficiently large system could escape this problem altogether? Yeah, exactly. Ideally you would have a sufficiently large system. Anything else? Okay. All right, that's the number of questions. So, let's thank the speaker one more time. Cool. There are two talks about D-Wave.