コード例 #1
0
 /// <summary>
 /// Find qubit with the specified time in the set. If such qubit is not present,
 /// find either maximum value less than it or minimum value greater than it.
 /// This function uses one call to SortedSet.TryGetValue() so it takes log(N) time, where N - number of nodes.
 /// </summary>
 /// <param name="requestedTime">Sample time to find</param>
 /// <param name="getLowerBound">"true" to find maximum value &lt;= requestedTime, "false" to find minimum value &gt;= requestedTime</param>
 /// <param name="actualTime">Time found in the set</param>
 /// <returns>"true" if the requested bound was found in the set, "false" otherwise</returns>
 public bool FindBound(ComplexTime requestedTime, bool getLowerBound, out ComplexTime actualTime)
 {
     // We use the following approach:
     // We call function TryGetValue on a sorted set. If value is found, we return it.
     // Otherwise TryGetValue must make conclusion that the value is absent.
     // Any comparison-based algorithm without caching must inspect both
     // maximum value less than the sample and minimum value greater than the sample.
     // So they must be among the values seen since reset.
     // So we just need to harvest them from VisitingComparer.
     Sample.Time = requestedTime;
     NodeComparer.ResetForComparison(Sample);
     if (QubitsSortedByTime.TryGetValue(Sample, out QubitTimeNode foundValue))
     {
         actualTime = foundValue.Time;
         return(true);
     }
     if (getLowerBound)
     {
         actualTime = NodeComparer.MaxLowerBound;
         return(!actualTime.IsEqualTo(ComplexTime.MinValue));
     }
     else
     {
         actualTime = NodeComparer.MinUpperBound;
         return(!actualTime.IsEqualTo(ComplexTime.MaxValue));
     }
 }
コード例 #2
0
        /// <summary>
        /// Compares two complex times. First DepthTime is compared, then TrailingZeroDepthGateCount is compared.
        /// </summary>
        /// <returns>0 when a = b, -1 when a&lt; b, and 1 when a &gt; b</returns>
        internal static int Compare(ComplexTime a, ComplexTime b)
        {
            int result = a.DepthTime.CompareTo(b.DepthTime);

            if (result != 0)
            {
                return(result);
            }
            return(a.TrailingZeroDepthGateCount.CompareTo(b.TrailingZeroDepthGateCount));
        }
コード例 #3
0
        /// <summary>
        /// Subtracts argument ComplexTime from "this" ComplexTime. Returns the result.
        /// Depth times are assumed to be precise for comparison.
        /// </summary>
        /// <param name="time">Time to subtract from this object.</param>
        /// <returns>Result of subtraction.</returns>
        internal ComplexTime Subtract(ComplexTime time)
        {
            if (DepthTime == time.DepthTime)
            {
                return(new ComplexTime(0, TrailingZeroDepthGateCount - time.TrailingZeroDepthGateCount));
            }
            double result = DepthTime - time.DepthTime;

            if (result <= 0)
            {
                // This could happen due to insufficient floating point calculation precision.
                throw new ArgumentException("Result of ComplexTime subtraction is not positive.");
            }
            return(new ComplexTime(result, 0));
        }
コード例 #4
0
        public void OnPrimitiveOperation(int id, object[] qubitsTraceData, double primitiveOperationDuration)
        {
            IEnumerable <QubitTimeMetrics> qubitsMetrics = qubitsTraceData.Cast <QubitTimeMetrics>();

            if (optimizeDepth)
            {
                // When we optimize for depth we may need to adjust qubit start times in addition to qubit end times.
                if (qubitsTraceData.Length == 1)
                {
                    // Single qubit gate always advances end time by operation duration
                    // in case qubit is fixed or not fixed in time.
                    ((QubitTimeMetrics)qubitsTraceData[0]).EndTime =
                        ((QubitTimeMetrics)qubitsTraceData[0]).EndTime.AdvanceBy(primitiveOperationDuration);
                }
                else
                {
                    // Multi-qubit gate fixes all qubits in time and advances end time
                    // First, figure out what time it is. It's max over fixed and not fixed times.
                    ComplexTime maxEndTime = ComplexTime.Zero;
                    foreach (QubitTimeMetrics q in qubitsMetrics)
                    {
                        maxEndTime = ComplexTime.Max(maxEndTime, q.EndTime);
                    }
                    // Now we fix qubits that are not yet fixed by adjusting their start time.
                    // And adjust end time for all qubits involved.
                    foreach (QubitTimeMetrics q in qubitsMetrics)
                    {
                        if (q.StartTime.IsEqualTo(ComplexTime.MinValue))
                        {
                            q.StartTime = maxEndTime.Subtract(q.EndTime);
                        }
                        q.EndTime = maxEndTime.AdvanceBy(primitiveOperationDuration);
                    }
                }
            }
            else
            {
                // When we don't optimize for depth we use max availability time
                // as gate execution time and then adjust availability time of qubits involved
                double startTime = MaxAvailableTime(qubitsMetrics);
                foreach (QubitTimeMetrics q in qubitsMetrics)
                {
                    qubitAvailabilityTime[q.QubitId] = startTime + primitiveOperationDuration;
                }
            }
        }
コード例 #5
0
        /// <summary>
        /// Add Qubit to the set with specified time. Multiple qubits with the same time can be added.
        /// Complexity is log(N), where N - number of nodes.
        /// </summary>
        /// <param name="qubitId">Id of a qubit to add to the set.</param>
        /// <param name="time">Time of the qubit.</param>
        public void Add(long qubitId, ComplexTime time)
        {
            QubitTimeNode newNode = new QubitTimeNode(qubitId, time);

            if (QubitsSortedByTime.Add(newNode))
            {
                // New item was added to the set, we are done.
                return;
            }
            if (!QubitsSortedByTime.TryGetValue(newNode, out QubitTimeNode existingNode))
            {
                // We cannot add, but we cannot find a node with the same value. Is this a floating point glitch?
                Debug.Assert(false, "Cannot add a value to SortedSet<QubitTimeNode> that isn't in the set.");
                return;
            }
            // Add new node to the linked list as a second element.
            newNode.NextNode      = existingNode.NextNode;
            existingNode.NextNode = newNode;
        }
コード例 #6
0
        /// <summary>
        /// Remove one qubit with given time from the set. Complexity is log(N), where N - number of nodes.
        /// </summary>
        /// <param name="time">Remove qubit with this time.</param>
        /// <returns>QubitId if qubit is found. Throws exception if it is not found.</returns>
        public long Remove(ComplexTime time)
        {
            Sample.Time = time;
            if (!QubitsSortedByTime.TryGetValue(Sample, out QubitTimeNode foundValue))
            {
                throw new ApplicationException("Cannot get qubit that should be present in a qubit pool.");
            }
            if (foundValue.NextNode == null)
            {
                // Remove only node from the tree.
                long qubitId = foundValue.QubitId;
                QubitsSortedByTime.Remove(Sample);
                return(qubitId);
            }
            // Get second node in the list.
            QubitTimeNode nodeToRemove = foundValue.NextNode;

            // Remove second node from the list.
            foundValue.NextNode = nodeToRemove.NextNode;
            return(nodeToRemove.QubitId);
        }
コード例 #7
0
            /// <summary>
            /// Compares Time field of two nodes. Also updates MaxLowerBound and MinUpperBound.
            /// </summary>
            /// <returns>Result of comparison of Time field of QubitTimeNode</returns>
            public int Compare(QubitTimeNode a, QubitTimeNode b)
            {
                // Note that comparison of a and b nodes to Sample is "by reference" in this function.
                int result = ComplexTime.Compare(a.Time, b.Time);

                if (result > 0)
                {
                    if (a == Sample && b != Sample)
                    {
                        MaxLowerBound = ComplexTime.Max(MaxLowerBound, b.Time);
                    }
                    else if (a != Sample && b == Sample)
                    {
                        MinUpperBound = ComplexTime.Min(MinUpperBound, a.Time);
                    }
                }
                else if (result < 0)
                {
                    if (a == Sample && b != Sample)
                    {
                        MinUpperBound = ComplexTime.Min(MinUpperBound, b.Time);
                    }
                    else if (a != Sample && b == Sample)
                    {
                        MaxLowerBound = ComplexTime.Max(MaxLowerBound, a.Time);
                    }
                }
                else
                {
                    // We found the value if one argument is the sample and the other is not.
                    if ((a == Sample) != (b == Sample))
                    {
                        MaxLowerBound = b.Time;
                        MinUpperBound = b.Time;
                    }
                }
                return(result);
            }
コード例 #8
0
 /// <summary>
 /// Compare objects assuming they are QubitTimeMetrics. Compare by StartTime.
 /// </summary>
 private static int CompareAsQubitTimeMetricsByStartTime(object x, object y)
 {
     return(ComplexTime.Compare(((QubitTimeMetrics)x).StartTime, ((QubitTimeMetrics)y).StartTime));
 }
コード例 #9
0
        public void OnRelease(object[] qubitsTraceData)
        {
            OperationCallRecord opRec = operationCallStack.Peek();

            opRec.ReleasedQubitsAvailableTime = Max(
                opRec.ReleasedQubitsAvailableTime,
                MaxAvailableTime(qubitsTraceData.Cast <QubitTimeMetrics>()));

            if (optimizeDepth)
            {
                // Performing width computation and applying reuse heuristics.
                // First we fix busy time periods for all qubits involved.
                foreach (QubitTimeMetrics q in qubitsTraceData.Cast <QubitTimeMetrics>())
                {
                    // If qubit is not fixed in time we fix it at zero.
                    if (q.StartTime.IsEqualTo(ComplexTime.MinValue))
                    {
                        q.StartTime = ComplexTime.Zero;
                    }
                }

                // Then we sort qubits ascending by the start of busy time. This would result in optimal reuse if:
                // (1) We were not allowed to move gates in time.
                // (2) We were sorting all qubits of the cirquit, not just this block.
                // In reality these statements aren't true, so this is only a heuristic rather than the optimal reuse of qubits.
                Array.Sort(qubitsTraceData, CompareAsQubitTimeMetricsByStartTime);

                // Reuse qubits if possible or increase count of qubits used.
                foreach (QubitTimeMetrics q in qubitsTraceData.Cast <QubitTimeMetrics>())
                {
                    // If qubit wasn't used in any gate. We don't allocate it.
                    if (q.EndTime.IsEqualTo(ComplexTime.Zero))
                    {
                        continue;
                    }

                    // Then we find if we can reuse existing qubits.
                    bool reuseExistingAfterNew = qubitStartTimes.FindBound(q.EndTime, getLowerBound: false, out ComplexTime existingStart);
                    bool reuseNewAfterExising  = qubitEndTimes.FindBound(q.StartTime, getLowerBound: true, out ComplexTime existingEnd);
                    if (reuseNewAfterExising && reuseExistingAfterNew)
                    {
                        // If we can do both, see which reuse creates a shorter gap and leave it for reuse.
                        if (ComplexTime.Compare(q.StartTime.Subtract(existingEnd), existingStart.Subtract(q.EndTime)) > 0)
                        {
                            reuseNewAfterExising = false;
                        }
                        else
                        {
                            reuseExistingAfterNew = false;
                        }
                    }

                    if (reuseNewAfterExising)
                    {
                        // If we place new qubit after existing - update end time of existing qubit
                        long idToReuse = qubitEndTimes.Remove(existingEnd);
                        qubitEndTimes.Add(idToReuse, q.EndTime);
                    }
                    else if (reuseExistingAfterNew)
                    {
                        // If we place new qubit before existing - update start time of existing qubit
                        long idToReuse = qubitStartTimes.Remove(existingStart);
                        qubitStartTimes.Add(idToReuse, q.StartTime);
                    }
                    else
                    {
                        // We cannot reuse existing qubits. Use new qubit.
                        long id = maxQubitId;
                        maxQubitId++;
                        qubitStartTimes.Add(id, q.StartTime);
                        qubitEndTimes.Add(id, q.EndTime);
                    }
                }
            }
        }
コード例 #10
0
        public void OnRelease(object[] qubitsTraceData)
        {
            OperationCallRecord opRec = operationCallStack.Peek();

            opRec.ReleasedQubitsAvailableTime = Max(
                opRec.ReleasedQubitsAvailableTime,
                MaxAvailableTime(qubitsTraceData.Cast <QubitTimeMetrics>()));

            if (optimizeDepth)
            {
                // Doing width reuse heuristics and width computation.
                foreach (QubitTimeMetrics q in qubitsTraceData.Cast <QubitTimeMetrics>())
                {
                    // If qubit wasn't used in any gate. We don't allocate it.
                    if (q.EndTime.IsEqualTo(ComplexTime.Zero))
                    {
                        continue;
                    }

                    // If qubit is not fixed in time we fix it at zero.
                    if (q.StartTime.IsEqualTo(ComplexTime.MinValue))
                    {
                        q.StartTime = ComplexTime.Zero;
                    }

                    // Then we find if we can reuse existing qubits.
                    bool reuseExistingAfterNew = qubitStartTimes.FindBound(q.EndTime, getLowerBound: false, out ComplexTime existingStart);
                    bool reuseNewAfterExising  = qubitEndTimes.FindBound(q.StartTime, getLowerBound: true, out ComplexTime existingEnd);
                    if (reuseNewAfterExising && reuseExistingAfterNew)
                    {
                        // If we can do both, see which reuse creates a shorter gap and leave it for reuse.
                        if (ComplexTime.Compare(q.StartTime.Subtract(existingEnd), existingStart.Subtract(q.EndTime)) > 0)
                        {
                            reuseNewAfterExising = false;
                        }
                        else
                        {
                            reuseExistingAfterNew = false;
                        }
                    }

                    if (reuseNewAfterExising)
                    {
                        // If we place new qubit after existing - update end time of existing qubit
                        long idToReuse = qubitEndTimes.Remove(existingEnd);
                        qubitEndTimes.Add(idToReuse, q.EndTime);
                    }
                    else if (reuseExistingAfterNew)
                    {
                        // If we place new qubit before existing - update start time of existing qubit
                        long idToReuse = qubitStartTimes.Remove(existingStart);
                        qubitStartTimes.Add(idToReuse, q.StartTime);
                    }
                    else
                    {
                        // We cannot reuse existing qubits. Use new qubit.
                        long id = maxQubitId;
                        maxQubitId++;
                        qubitStartTimes.Add(id, q.StartTime);
                        qubitEndTimes.Add(id, q.EndTime);
                    }
                }
            }
        }
コード例 #11
0
 /// <summary>
 /// Resets minimum and maximum value of nodes seen from the set.
 /// Also sets sample object, which should not be counted because it is not an object from the set.
 /// </summary>
 /// <param name="sample">Sample object that is not considered for minimum and maximum.</param>
 internal void ResetForComparison(QubitTimeNode sample)
 {
     MaxLowerBound = ComplexTime.MinValue;
     MinUpperBound = ComplexTime.MaxValue;
     Sample        = sample;
 }
コード例 #12
0
 internal QubitTimeNode(long qubitId, ComplexTime time)
 {
     QubitId  = qubitId;
     Time     = time;
     NextNode = null;
 }
コード例 #13
0
 /// <summary>
 /// Finds largest of the two ComplexTime arguments.
 /// </summary>
 /// <returns>Largest of the two arguments according to comparison.</returns>
 internal static ComplexTime Max(ComplexTime a, ComplexTime b)
 {
     return(Compare(a, b) > 0 ? a : b);
 }
コード例 #14
0
 /// <summary>
 /// Returns true if this ComplexTime is the same as the argument.
 /// </summary>
 internal bool IsEqualTo(ComplexTime t)
 {
     return(Compare(this, t) == 0);
 }