public void OnOperationEnd(object[] returnedQubitsTraceData)
        {
            double maxReturnedQubitsAvailableTime = 0;

            if (returnedQubitsTraceData != null)
            {
                maxReturnedQubitsAvailableTime = MaxAvailableTime(returnedQubitsTraceData.Cast <QubitTimeMetrics>());
            }
            OperationCallRecord opRec = operationCallStack.Pop();

            Debug.Assert(operationCallStack.Count != 0, "Operation call stack must never get empty");
            double inputQubitsAvailableTime = MaxAvailableTime(opRec.InputQubitMetrics);
            double operationEndTime         =
                Max(
                    Max(maxReturnedQubitsAvailableTime, opRec.ReturnedQubitsAvailableTime),
                    Max(opRec.ReleasedQubitsAvailableTime, inputQubitsAvailableTime));
            OperationCallRecord caller = operationCallStack.Peek();

            caller.ReleasedQubitsAvailableTime = Max(opRec.ReleasedQubitsAvailableTime, caller.ReleasedQubitsAvailableTime);
            caller.ReturnedQubitsAvailableTime = Max(opRec.ReturnedQubitsAvailableTime, caller.ReturnedQubitsAvailableTime);

            double[] metrics =
                StatisticsRecord(
                    Depth: operationEndTime - opRec.MaxOperationStartTime,
                    StartTimeDifference: opRec.MaxOperationStartTime - opRec.MinOperationStartTime,
                    Width: maxQubitId - opRec.MaxQubitIdAtStart);

            stats.AddSample(
                new CallGraphEdge(opRec.OperationName, caller.OperationName, opRec.FunctorSpecialization, caller.FunctorSpecialization),
                metrics);
        }
        public void OnOperationEnd(object[] returnedQubitsTraceData)
        {
            OperationCallRecord or = operationCallStack.Pop();

            Debug.Assert(operationCallStack.Count != 0, "Operation call stack is empty. This likely caused by unbalanced OnOperationStart/End");
            OperationCallRecord opCaller = operationCallStack.Peek();

            opCaller.MaxAllocated = Max(opCaller.MaxAllocated, or.MaxAllocated);

            double[] statRecord = StatisticsRecord(
                InputWidth: or.InputWidth,
                ExtraWidth: or.MaxAllocated - or.QubitsAllocatedAtStart,
                ReturnWidth: returnedQubitsTraceData.Length,
                BorrowedWidth: or.MaxBorrowed);
            CallGraphEdge callGraphEdge = new CallGraphEdge(or.OperationName, opCaller.OperationName, or.Variant, opCaller.Variant);

            statisticsCollector.AddSample(callGraphEdge, statRecord);
        }