/// <summary>
        /// A slightly faster version to construct a colored image from 3 quantumCircuits, 1 per channel, (which should represent a colored image).
        /// Used after image effect are applied to the image (the circuit) to get the modified picture
        /// This version should produce less garbage, however, it only makes a small difference, since the python part is the same (and the slow part)
        /// </summary>
        /// <param name="redCircuit">The circuit representing the red color channel of the (modified) image.</param>
        /// <param name="greenCircuit">The circuit representing the green color channel of the (modified) image</param>
        /// <param name="blueCircuit">The circuit representing the blue color channel of the (modified) image</param>
        /// <param name="useLog">If logarithmic decoding should be used to decode the image.</param>
        /// <returns></returns>
        public Texture2D GetColoreTextureFast(QuantumCircuit redCircuit, QuantumCircuit greenCircuit, QuantumCircuit blueCircuit, bool useLog = false)
        {
            MicroQiskitSimulator simulator = new MicroQiskitSimulator();

            //Trying optimazations (less garbage). Negative side is we need the full arrays
            // TODO make circuit initialization better
            double[]        probabilities = new double[MathHelper.IntegerPower(2, redCircuit.NumberOfQubits)];
            ComplexNumber[] amplitudes    = null;

            string[] stringArray = QuantumImageHelper.CalculateNameStrings(probabilities.Length, redCircuit.NumberOfQubits);

            simulator.CalculateProbabilities(redCircuit, ref probabilities, ref amplitudes);

            IronPython.Runtime.PythonDictionary redDictionary = pythonFile.HeightFromProbabilities(stringArray, probabilities, probabilities.Length, redCircuit.DimensionString, useLog);

            simulator.CalculateProbabilities(greenCircuit, ref probabilities, ref amplitudes);
            IronPython.Runtime.PythonDictionary greenDictionary = pythonFile.HeightFromProbabilities(stringArray, probabilities, probabilities.Length, greenCircuit.DimensionString, useLog);

            simulator.CalculateProbabilities(blueCircuit, ref probabilities, ref amplitudes);
            IronPython.Runtime.PythonDictionary blueDictionary = pythonFile.HeightFromProbabilities(stringArray, probabilities, probabilities.Length, blueCircuit.DimensionString, useLog);

            return(QuantumImageHelper.CalculateColorTexture(redDictionary, greenDictionary, blueDictionary, redCircuit.DimensionString));
        }
    IEnumerator meshAnimationOptimized()
    {
        //It is important to create a copy of the vertices and only use "inputMesh.vertices" only once
        // since this is a get function. Meaning in every call of the function the mesh will be copied.
        Vector3[] inputVertices    = InputMesh.vertices;
        int       numberOfVertices = inputVertices.Length;

        //We look at our input being 2 dimensional. One dimension is the number of vertices,
        //the other dimension is the vector x,y,z

        //We create lines for the first dimension the number of vertices
        int numberOfVertexCubits = Mathf.CeilToInt(Mathf.Log(numberOfVertices) / Mathf.Log(2));

        //The lines are needed to encode the data in a way that encoding of neighbouring vertices only differ in 1 bit
        int[] linesVertices = QuantumImageHelper.MakeLinesInt(numberOfVertexCubits);

        //We create lines for the second dimension the vector x,y,z so there are only 3 values (thats where the 3 comes from).
        //The 2 is to transform the thing to base 2 since we need the logarithm in base 2.
        int numberOfVectorQubits = Mathf.CeilToInt(Mathf.Log(3) / Mathf.Log(2));

        //The lines are needed to encode the data in a way that the encoding of x and y as well as y and z only differ in 1 bit.
        int[] linesVector = QuantumImageHelper.MakeLinesInt(numberOfVectorQubits);

        //Creating a circuit big enough to fit in the mesh data
        int            numberOfQubits = numberOfVertexCubits + numberOfVectorQubits;
        QuantumCircuit circuit        = new QuantumCircuit(numberOfQubits, numberOfQubits, true);

        //Since we work with probabilities, we need the values to be positive (or 0).
        //Therefore we want to translate the values adding an offset to our values, such that they become positive.

        //Getting the smallest (most negative) values to use for the displacement
        //initiate values as 0
        float minX = 0;
        float minY = 0;
        float minZ = 0;

        for (int i = 0; i < inputVertices.Length; i++)
        {
            if (inputVertices[i].x < minX)
            {
                minX = inputVertices[i].x;
            }
            if (inputVertices[i].y < minY)
            {
                minY = inputVertices[i].y;
            }
            if (inputVertices[i].z < minZ)
            {
                minZ = inputVertices[i].z;
            }
        }

        //Needed to transform the position of our 2 dimensions mentioned above into a single array.
        //The indexes look like this:  0_X, 0_Y, 0_Z, 0_?, 1_X, 1_Y, 1_Z.... Where 0,1 etc stand for the vertex number
        //X,Y,Z stands for the respective coordinates and ? is just a placeholder which is not really needed (but we need to have a power of 2 so 4 values for our 3)
        int maxHeight = linesVector.Length;

        for (int i = 0; i < numberOfVertices; i++)
        {
            //We use the lines produced above to calculate the new position
            int index = linesVertices[i] * maxHeight;
            //We interpret the values as probabilities. And the amplitudes are the square root of the probabilities.
            circuit.Amplitudes[index + linesVector[0]].Real = Math.Sqrt(inputVertices[i].x - minX);
            circuit.Amplitudes[index + linesVector[1]].Real = Math.Sqrt(inputVertices[i].y - minY);
            circuit.Amplitudes[index + linesVector[2]].Real = Math.Sqrt(inputVertices[i].z - minZ);
        }

        //We need to normalize the circuit, since probabilities should add up to 1.
        //We store the factor used for normalization in order to reverse this scaling later.
        circuit.Normalize();
        double normalizationFactor = circuit.OriginalSum;

        //We don't want to allocate as phew memory as possible in order to minimize garbage collection
        //Therefore, we reuse the defined arrays
        double[]  realAmplitudes = new double[circuit.AmplitudeLength];
        Vector3[] outPutVertices = new Vector3[numberOfVertices];

        //Making a copy of the amplitudes of the circuit
        for (int i = 0; i < circuit.AmplitudeLength; i++)
        {
            realAmplitudes[i] = circuit.Amplitudes[i].Real;
        }

        //Creating a new mesh, at this point it is just a copy of the input mesh
        Mesh outputMesh = new Mesh();

        outputMesh.name      = InputMesh.name + " blurred";
        outputMesh.vertices  = inputVertices;
        outputMesh.triangles = InputMesh.triangles;
        outputMesh.uv        = InputMesh.uv;
        outputMesh.RecalculateNormals();
        outputMesh.RecalculateTangents();
        MicroQiskitSimulator simulator = new MicroQiskitSimulator();

        double[]        probs      = new double[circuit.AmplitudeLength]; //simulator.GetProbabilities(circuit);
        ComplexNumber[] amplitudes = new ComplexNumber[circuit.AmplitudeLength];

        //Setting the new mesh to the target
        //We can now just manipulate the vertices of this mesh in order to change it.
        //No need to create new meshes
        TargetMesh.sharedMesh = outputMesh;
        OutputMesh            = outputMesh;

        float rotation = 0.0f;
        float progress = 0;

        //Making sure to have no endless loop
        if (Duration <= 0)
        {
            Duration = 1;
        }

        //Creating an animation by blurring the mesh step by step
        //Duration is the duration of the animation, StartRotation and Endrotation give
        //The starting points and endpoints of the animation the rest is interpolated.
        while (progress < 1)
        {
            //Calculating progress for the animation
            progress += Time.deltaTime / Duration;
            //Rotation is interpolated between endRotation and startRtoation depending on progress
            rotation = progress * EndRotation + (1 - progress) * StartRotation;

            //Resetting the circuit (deleting the gates)
            circuit.ResetGates();
            //Reusing the circuit by filling in the original values before the calculation again
            for (int i = 0; i < circuit.AmplitudeLength; i++)
            {
                circuit.Amplitudes[i].Real = realAmplitudes[i];
            }

            //Applying the operation to the circuit (the blur effect)
            ApplyPartialQ(circuit, rotation);

            //Calculating probabilities
            simulator.CalculateProbabilities(circuit, ref probs, ref amplitudes);

            //Filling in the new calculated values into the vertices
            for (int i = 0; i < numberOfVertices; i++)
            {
                int index = linesVertices[i] * maxHeight;
                //Since we have probabilities already we do not need to square them.
                //We undo the normalization from above and the translation (offset) from the beginning
                outPutVertices[i].x = (float)(probs[index + linesVector[0]] * normalizationFactor) + minX;
                outPutVertices[i].y = (float)(probs[index + linesVector[1]] * normalizationFactor) + minY;
                outPutVertices[i].z = (float)(probs[index + linesVector[2]] * normalizationFactor) + minZ;
            }

            //We set the new vertices to the mesh, this way the mesh changes its form automatically
            //and we do not need to construct a new mesh.
            outputMesh.vertices = outPutVertices;
            //wait until next frame.
            yield return(null);
        }

        // Reverse animation going back to startRotation
        if (reverseAnimation)
        {
            while (progress > 0)
            {
                //Calculating progress for the animation going back
                progress -= Time.deltaTime / Duration;
                //Rotation is interpolated between endRotation and startRtoation depending on progress
                rotation = progress * EndRotation + (1 - progress) * StartRotation;

                //Resetting the circuit (deleting the gates)
                circuit.ResetGates();
                //Reusing the circuit by filling in the original values before the calculation again
                for (int i = 0; i < circuit.AmplitudeLength; i++)
                {
                    circuit.Amplitudes[i].Real = realAmplitudes[i];
                }

                //Applying the operation to the circuit (the blur effect)
                ApplyPartialQ(circuit, rotation);

                //Calculating probabilities
                simulator.CalculateProbabilities(circuit, ref probs, ref amplitudes);

                //Filling the new calculated values into the vertices
                for (int i = 0; i < numberOfVertices; i++)
                {
                    int index = linesVertices[i] * maxHeight;
                    //Since we have probabilities already we do not need to square them.
                    //We undo the normalization from above and the translation (offset) from the beginning
                    outPutVertices[i].x = (float)(probs[index + linesVector[0]] * normalizationFactor) + minX;
                    outPutVertices[i].y = (float)(probs[index + linesVector[1]] * normalizationFactor) + minY;
                    outPutVertices[i].z = (float)(probs[index + linesVector[2]] * normalizationFactor) + minZ;
                }

                outputMesh.vertices = outPutVertices;

                //We set the new vertices to the mesh, this way the mesh changes its form automatically
                //and we do not need to construct a new mesh.outputMesh.vertices = outPutVertices;
                //wait until next frame.
                yield return(null);
            }
        }
    }