示例#1
0
        //Helper functions, which need python code, thats why they are not exported to QuantumImageHelper
        #region Internal Helper Functions

        IronPython.Runtime.PythonDictionary getBlurDictionaryFromData(out string heightDimensions, double[,] imageData, float rotation, bool useLog = false)
        {
            //dynamic pythonHelper = PythonFile.QuantumBlurHelper("Helper");
            blurHelper.SetHeights(imageData, imageData.GetLength(0), imageData.GetLength(1), useLog);
            blurHelper.ApplyPartialX(rotation);

            dynamic circuit        = blurHelper.GetCircuit();
            int     numberofQubits = circuit.num_qubits;

            heightDimensions = circuit.name;


            QuantumCircuit       quantumCircuit = QuantumImageHelper.ParseCircuit(circuit.data, numberofQubits);
            MicroQiskitSimulator simulator      = new MicroQiskitSimulator();

            double[] doubleArray = new double[0];
            string[] stringArray = new string[0];

            QuantumImageHelper.GetProbabilityArrays(simulator.GetProbabilities(quantumCircuit), numberofQubits, ref doubleArray, ref stringArray);
            IronPython.Runtime.PythonDictionary dictionary = pythonFile.HeightFromProbabilities(stringArray, doubleArray, doubleArray.Length, heightDimensions, useLog);

            return(dictionary);
        }
示例#2
0
        /// <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));
        }
示例#3
0
        public static Texture2D CalculateColorTexture(QuantumCircuit redCircuit, QuantumCircuit greenCircuit, QuantumCircuit blueCircuit, int width, int height, bool renormalize = false)
        {
            Texture2D texture = new Texture2D(width, height);

            int widthLog  = Mathf.CeilToInt(Mathf.Log(width) / Mathf.Log(2));
            int heightLog = widthLog;

            int[] widthLines  = MakeLinesInt(widthLog);
            int[] heightLines = widthLines;

            if (height != width)
            {
                heightLog   = Mathf.CeilToInt(Mathf.Log(height) / Mathf.Log(2));
                heightLines = MakeLinesInt(heightLog);
            }

            MicroQiskitSimulator simulator = new MicroQiskitSimulator();

            double[] redProbs   = simulator.GetProbabilities(redCircuit);
            double[] greenProbs = simulator.GetProbabilities(greenCircuit);
            double[] blueProbs  = simulator.GetProbabilities(blueCircuit);


            double normalizationRed   = 0;
            double normalizationGreen = 0;
            double normalizationBlue  = 0;

            if (!renormalize && redCircuit.OriginalSum > 0 && greenCircuit.OriginalSum > 0 && blueCircuit.OriginalSum > 0)
            {
                normalizationRed   = redCircuit.OriginalSum;
                normalizationGreen = greenCircuit.OriginalSum;
                normalizationBlue  = blueCircuit.OriginalSum;
            }
            else
            {
                for (int i = 0; i < width; i++)
                {
                    for (int j = 0; j < height; j++)
                    {
                        int pos = widthLines[i] * height + heightLines[j];
                        if (redProbs[pos] > normalizationRed)
                        {
                            normalizationRed = redProbs[pos];
                        }
                        if (greenProbs[pos] > normalizationGreen)
                        {
                            normalizationGreen = greenProbs[pos];
                        }
                        if (blueProbs[pos] > normalizationBlue)
                        {
                            normalizationBlue = blueProbs[pos];
                        }
                    }
                }
                normalizationRed   = 1.0 / normalizationRed;
                normalizationGreen = 1.0 / normalizationGreen;
                normalizationBlue  = 1.0 / normalizationBlue;
            }


            float redValue;
            float greenValue;
            float blueValue;

            int posX = 0;

            for (int x = 0; x < width; x++)
            {
                posX = widthLines[x] * height;
                for (int y = 0; y < height; y++)
                {
                    int index = posX + heightLines[y];
                    redValue   = (float)(redProbs[index] * normalizationRed);
                    greenValue = (float)(greenProbs[index] * normalizationGreen);
                    blueValue  = (float)(blueProbs[index] * normalizationBlue);
                    texture.SetPixel(x, y, new Color(redValue, greenValue, blueValue));
                }
            }
            texture.Apply();
            return(texture);
        }
    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);
            }
        }
    }
    /// <summary>
    /// Creates a blurred version of the input mesh, according to the rotation. The bigger the rotation the stronger the blur effect.
    /// The model gets unrecognizeable as soon as the rotation gets to big
    /// </summary>
    /// <param name="inputMesh">The mesh to produce a blurred version of.</param>
    /// <param name="rotation">Can be between 0 and 3.1415 (pi). For starting 0.1 would be a good value.</param>
    /// <returns>A blurred (distorted) mesh of the original input mesh. </returns>
    public Mesh CreateBluredMesh(Mesh inputMesh, float rotation)
    {
        //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[] vertices         = inputMesh.vertices;
        int       numberOfVertices = vertices.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 < vertices.Length; i++)
        {
            if (vertices[i].x < minX)
            {
                minX = vertices[i].x;
            }
            if (vertices[i].y < minY)
            {
                minY = vertices[i].y;
            }
            if (vertices[i].z < minZ)
            {
                minZ = vertices[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(vertices[i].x - minX);
            circuit.Amplitudes[index + linesVector[1]].Real = Math.Sqrt(vertices[i].y - minY);
            circuit.Amplitudes[index + linesVector[2]].Real = Math.Sqrt(vertices[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 apply the effect to the circuit. Here this is the normal blur effect also used in the images.
        ApplyPartialQ(circuit, rotation);

        //Calculating the probabilities after having applied the operation above

        SimulatorBase simulator = new MicroQiskitSimulator();

        //MicroQiskitSimulator simulator = new MicroQiskitSimulator();
        //QiskitSimulator simulator = new QiskitSimulator();

        double[] probs = simulator.GetProbabilities(circuit);

        //Fill in the new calculated values back 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
            vertices[i].x = (float)(probs[index + linesVector[0]] * normalizationFactor) + minX;
            vertices[i].y = (float)(probs[index + linesVector[1]] * normalizationFactor) + minY;
            vertices[i].z = (float)(probs[index + linesVector[2]] * normalizationFactor) + minZ;
        }

        //creating the new mesh
        Mesh outputMesh = new Mesh();

        //setting the newly calculated vertices
        outputMesh.vertices = vertices;
        //Copying most stuff from original mesh
        outputMesh.name      = inputMesh.name + " blurred";
        outputMesh.triangles = inputMesh.triangles;
        outputMesh.uv        = inputMesh.uv;
        //Recalculating normals for correct lighning
        outputMesh.RecalculateNormals();

        //returning the mesh
        return(outputMesh);
    }