/// <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); }
/// <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)); }
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); } } } }
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); } } } }