diff --git a/src/Simulation/EntryPointDriver.Tests/Tests.fs b/src/Simulation/EntryPointDriver.Tests/Tests.fs index 7f242fdc5a0..9d3c9c5d0aa 100644 --- a/src/Simulation/EntryPointDriver.Tests/Tests.fs +++ b/src/Simulation/EntryPointDriver.Tests/Tests.fs @@ -474,15 +474,15 @@ let ``Shadows --shots`` () = // The expected output from the resources estimator. let private resourceSummary = - "Metric Sum - CNOT 0 - QubitClifford 1 - R 0 - Measure 1 - T 0 - Depth 0 - Width 1 - BorrowedWidth 0" + "Metric Sum Max + CNOT 0 0 + QubitClifford 1 1 + R 0 0 + Measure 1 1 + T 0 0 + Depth 0 0 + Width 1 1 + BorrowedWidth 0 0" [] let ``Supports QuantumSimulator`` () = diff --git a/src/Simulation/Simulators.Tests/Circuits/ResourcesEstimator.qs b/src/Simulation/Simulators.Tests/Circuits/ResourcesEstimator.qs index b209762cc09..dd3e52fc884 100644 --- a/src/Simulation/Simulators.Tests/Circuits/ResourcesEstimator.qs +++ b/src/Simulation/Simulators.Tests/Circuits/ResourcesEstimator.qs @@ -17,6 +17,27 @@ namespace Microsoft.Quantum.Simulation.Simulators.Tests } } + // When multiple operations are traced by resource estimator, + // it should report cumulative statistics in the end. + operation Operation_1_of_2() : Unit + { + using ((a, b) = (Qubit(), Qubit())) { + H(a); + CNOT(a, b); + T(b); + } + } + operation Operation_2_of_2() : Result + { + using ((a, b, c) = (Qubit(), Qubit(), Qubit())) { + X(a); + CNOT(a, b); + Rx(0.42, b); + CNOT(b, c); + return M(c); + } + } + // Tests for Depth and Width lower bounds operation DepthDifferentQubits () : Unit { diff --git a/src/Simulation/Simulators.Tests/ResourcesEstimatorTests.cs b/src/Simulation/Simulators.Tests/ResourcesEstimatorTests.cs index 2128f458764..0a60328484d 100644 --- a/src/Simulation/Simulators.Tests/ResourcesEstimatorTests.cs +++ b/src/Simulation/Simulators.Tests/ResourcesEstimatorTests.cs @@ -2,9 +2,8 @@ // Licensed under the MIT License. using System; -using System.Collections.Generic; using System.Linq; -using System.Text; +using System.Data; using Microsoft.Quantum.Simulation.QCTraceSimulatorRuntime; using Xunit; @@ -95,10 +94,10 @@ public void ToTSVTest() var cols = rows[0].Split('\t'); Assert.Equal("Metric", cols[0].Trim()); - Assert.Equal(2, cols.Length); + Assert.Equal(3, cols.Length); var cliffords = rows.First(r => r.StartsWith("QubitClifford")).Split('\t'); - Assert.Equal(2, cliffords.Length); + Assert.Equal(3, cliffords.Length); Assert.Equal("2", cliffords[1]); } @@ -138,5 +137,43 @@ public void DepthVersusWidthTest() Assert.Equal(1.0, data.Rows.Find("Width")["Sum"]); Assert.Equal(1.0, data.Rows.Find("Depth")["Sum"]); } + + /// + /// Verifies that for multiple separately traced operations, the final + /// statistics are cumulative. + /// + [Fact] + public void VerifyTracingMultipleOperationsTest() + { + ResourcesEstimator sim = new ResourcesEstimator(); + + Operation_1_of_2.Run(sim).Wait(); + DataTable data1 = sim.Data; + + Assert.Equal(1.0, data1.Rows.Find("CNOT")["Sum"]); + Assert.Equal(1.0, data1.Rows.Find("QubitClifford")["Sum"]); + Assert.Equal(1.0, data1.Rows.Find("T")["Sum"]); + Assert.Equal(0.0, data1.Rows.Find("R")["Sum"]); + Assert.Equal(0.0, data1.Rows.Find("Measure")["Sum"]); + Assert.Equal(2.0, data1.Rows.Find("Width")["Sum"]); + + Operation_2_of_2.Run(sim).Wait(); + DataTable data2 = sim.Data; + + // Aggregated stats for both operations. + Assert.Equal(1.0 + 2.0, data2.Rows.Find("CNOT")["Sum"]); + Assert.Equal(1.0 + 1.0, data2.Rows.Find("QubitClifford")["Sum"]); + Assert.Equal(1.0 + 0.0, data2.Rows.Find("T")["Sum"]); + Assert.Equal(0.0 + 1.0, data2.Rows.Find("R")["Sum"]); + Assert.Equal(0.0 + 1.0, data2.Rows.Find("Measure")["Sum"]); + Assert.Equal(2.0 + 3.0, data2.Rows.Find("Width")["Sum"]); + Assert.Equal(System.Math.Max(2.0, 3.0), data2.Rows.Find("Width")["Max"]); + + // Run again to confirm two operations isn't the limit! + VerySimpleEstimate.Run(sim).Wait(); + DataTable data3 = sim.Data; + Assert.Equal(2.0 + 3.0 + 3.0, data3.Rows.Find("Width")["Sum"]); + Assert.Equal(3.0, data3.Rows.Find("Width")["Max"]); + } } } diff --git a/src/Simulation/Simulators/ResourcesEstimator/ResourcesEstimator.cs b/src/Simulation/Simulators/ResourcesEstimator/ResourcesEstimator.cs index ec0e80ddef1..d08847898cf 100644 --- a/src/Simulation/Simulators/ResourcesEstimator/ResourcesEstimator.cs +++ b/src/Simulation/Simulators/ResourcesEstimator/ResourcesEstimator.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System; -using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.Linq; @@ -113,6 +112,7 @@ public virtual DataTable Data table.Columns.Add(new DataColumn { DataType = typeof(string), ColumnName = "Metric" }); table.Columns.Add(new DataColumn { DataType = typeof(double), ColumnName = "Sum" }); + table.Columns.Add(new DataColumn { DataType = typeof(double), ColumnName = "Max" }); table.PrimaryKey = new DataColumn[] { table.Columns[0] }; foreach (var l in CoreConfig.Listeners) @@ -121,11 +121,9 @@ public virtual DataTable Data if (l is ICallGraphStatistics collector) { var results = collector.Results.ToTable(); - Debug.Assert(results.rows.Count() == 1); Debug.Assert(results.keyColumnNames.Length > 2 && results.keyColumnNames[2] == "Caller"); - var root = results.rows.FirstOrDefault(r => r.KeyRow[2] == CallGraphEdge.CallGraphRootHashed); - + var roots = results.rows.Where(r => r.KeyRow[2] == CallGraphEdge.CallGraphRootHashed); var s_idx = Array.FindIndex(results.statisticsNames, n => n == "Sum"); for (var m_idx = 0; m_idx < results.metricNames.Length; m_idx++) @@ -133,12 +131,21 @@ public virtual DataTable Data var label = GetMetricLabel(results.metricNames[m_idx]); if (label == null) continue; - var row = table.NewRow(); + DataRow row = table.NewRow(); row["Metric"] = label; if (m_idx >= 0 && s_idx >= 0) - { - row["Sum"] = root.DataRow[m_idx, s_idx]; + { + Double sum = 0; + Double max = 0; // all our metrics are positive + foreach (var r in roots) + { + Double metric_value = r.DataRow[m_idx, s_idx]; + sum += metric_value; + max = System.Math.Max(max, metric_value); + } + row["Sum"] = sum; + row["Max"] = max; } table.Rows.Add(row);