From d1d9f54eff871d79dcd920dcf2fb3624aec51082 Mon Sep 17 00:00:00 2001 From: User178-a11y Date: Tue, 13 Oct 2026 22:16:13 +0530 Subject: [PATCH 1/2] Fix ellipsis when reporter limit is one Fixes #810 --- quest/src/core/printer.cpp | 56 +++++++++++++++++++++++++------------- tests/unit/debug.cpp | 34 +++++++++++++++++++++++ 2 files changed, 71 insertions(+), 19 deletions(-) diff --git a/quest/src/core/printer.cpp b/quest/src/core/printer.cpp index 863317c8f..ee469d40f 100644 --- a/quest/src/core/printer.cpp +++ b/quest/src/core/printer.cpp @@ -679,7 +679,8 @@ void printPerRowIndent(string baseIndent, size_t row, string indentPerRow) { void printRowInTwoQuadrants( vector leftRow, vector leftColWidths, - vector rightRow, vector rightColWidths + vector rightRow, vector rightColWidths, + bool isHorizontallyTruncated ) { // print left portion of row for (size_t c=0; c leftColWidths, stringmatr right, vector rightColWidths, vector rowLabels, - string indent, string indentPerRow, size_t rowOffsetForIndent + string indent, string indentPerRow, size_t rowOffsetForIndent, + bool isHorizontallyTruncated ) { for (size_t r=0; r{} : right[r]; - printRowInTwoQuadrants(left[r], leftColWidths, rightRow, rightColWidths); + printRowInTwoQuadrants(left[r], leftColWidths, rightRow, rightColWidths, + isHorizontallyTruncated); // print optional row label, using trailing space left by above row print cout << (rowLabels.empty()? "" : rowLabels[r]); @@ -727,7 +733,8 @@ void printMatrixInFourQuadrants( qcompmatr lowerLeft, qcompmatr lowerRight, vector leftColLabels, vector rightColLabels, // shown above the first row vector upperRowLabels, vector lowerRowLabels, // shown right of the last column - string baseIndent, string indentPerRow, string verticalEllipsis + string baseIndent, string indentPerRow, string verticalEllipsis, + bool isVerticallyTruncated, bool isHorizontallyTruncated ) { // this function prints a matrix which has been prior divided into one, two or four // quadrants, resulting from reporter truncation of the original matrix. It can be @@ -735,12 +742,12 @@ void printMatrixInFourQuadrants( // vertical vectors, diagonal matrices, and lists of scalars (e.g. Pauli coefficients) // the below preconditions are assumed but not enforced: - // - it is valid for lowerLeft to be empty, implying upperLeft contains entire columns; - // in that scenario, lowerRight must also be empty - // - it is valid for upperRight to be empty, implying upperLeft contains entire rows; - // in that scenario, lowerRight must also be empty - // - it is valid for upperRight=lowerLeft=lowerRight to be empty, implying upperLeft - // contains the entire matrix + // - it is valid for lowerLeft to be empty; omitted rows are indicated by + // isVerticallyTruncated, and in that scenario lowerRight must also be empty + // - it is valid for upperRight to be empty; omitted columns are indicated by + // isHorizontallyTruncated, and in that scenario lowerRight must also be empty + // - it is valid for upperRight=lowerLeft=lowerRight to be empty; upperLeft contains + // the entire matrix only when neither truncation flag is set // - it is valid for qcompmatr={} (empty), but it is INVALID to be {{}} (reported non-empty) // - it is INVALID for any qcompmatr to have an inconsistent number of columns across its rows // - it is INVALID for upperLeft and lowerLeft to differ in #columns, though #rows can vary; @@ -776,7 +783,8 @@ void printMatrixInFourQuadrants( // optionally print all column labels if (!leftColLabels.empty()) { cout << baseIndent; - printRowInTwoQuadrants(leftColLabels, leftColWidths, rightColLabels, rightColWidths); + printRowInTwoQuadrants(leftColLabels, leftColWidths, rightColLabels, rightColWidths, + isHorizontallyTruncated); cout << endl; } @@ -785,22 +793,25 @@ void printMatrixInFourQuadrants( upperLeftStrings, leftColWidths, upperRightStrings, rightColWidths, upperRowLabels, - baseIndent, indentPerRow, 0); + baseIndent, indentPerRow, 0, isHorizontallyTruncated); - // finish immediately if there are no lower rows (matrix wasn't vertically truncated) - if (lowerLeftStrings.empty()) + // finish immediately if there are no lower rows and no data was omitted + if (lowerLeftStrings.empty() && !isVerticallyTruncated) return; // otherwise, draw ellipsis, aligned (approx) in the midpoint of leftmost column (which may be indented) printPerRowIndent(baseIndent, upperLeft.size(), indentPerRow); cout << string(leftColWidths[0]/2, MATRIX_SPACE_CHAR) << verticalEllipsis << endl; + if (lowerLeftStrings.empty()) + return; + // print the lower rows (continuing indentation from upper) printContiguousRowsInTwoQuadrants( lowerLeftStrings, leftColWidths, lowerRightStrings, rightColWidths, lowerRowLabels, - baseIndent, indentPerRow, upperLeft.size() + 1); // +1 for ellipsis + baseIndent, indentPerRow, upperLeft.size() + 1, isHorizontallyTruncated); // +1 for ellipsis } @@ -826,6 +837,8 @@ struct MatrixQuadrantInds { qindex rightStartCol=0; qindex lowerStartRow=0; + bool isVerticallyTruncated=false; + bool isHorizontallyTruncated=false; // these are always fixed at 0, but included for clarity qindex leftStartCol = 0; @@ -878,6 +891,8 @@ MatrixQuadrantInds getTruncatedMatrixQuadrantInds(qindex numRows, qindex numCols inds.numLowerRightRows = maxNumLowerRows; inds.numLowerRightCols = maxNumRightCols; } + inds.isVerticallyTruncated = numRows > global_maxNumPrintedRows; + inds.isHorizontallyTruncated = numCols > global_maxNumPrintedCols; return inds; } @@ -1126,7 +1141,8 @@ void printDenseSquareMatrix(T obj, string indent) { printMatrixInFourQuadrants( ul, ur, ll, lr, leftColLabels, rightColLabels, rowLabels, rowLabels, - indent, indentPerRow, VDOTS_CHAR); + indent, indentPerRow, VDOTS_CHAR, + inds.isVerticallyTruncated, inds.isHorizontallyTruncated); } @@ -1257,7 +1273,8 @@ void printVector(T obj, string indent) { printMatrixInFourQuadrants( ul, ur, ll, lr, colLabels, colLabels, upperRowLabels, lowerRowLabels, - indent, indentPerRow, ellipsisChar); + indent, indentPerRow, ellipsisChar, + inds.isVerticallyTruncated, inds.isHorizontallyTruncated); } @@ -1399,7 +1416,8 @@ void print_elems(PauliStrSum sum, string indent) { printMatrixInFourQuadrants( ul, ur, ll, lr, colLabels, colLabels, upperLabels, lowerLabels, - indent, "", VDOTS_CHAR); + indent, "", VDOTS_CHAR, + inds.isVerticallyTruncated, inds.isHorizontallyTruncated); } diff --git a/tests/unit/debug.cpp b/tests/unit/debug.cpp index 421cf55ea..67939b5eb 100644 --- a/tests/unit/debug.cpp +++ b/tests/unit/debug.cpp @@ -112,6 +112,40 @@ TEST_CASE( "setQuESTMaxNumReportedSigFigs", TEST_CATEGORY ) { } +TEST_CASE( "setQuESTMaxNumReportedItems", TEST_CATEGORY ) { + + // Reproduce issue #810: a 2x2 matrix limited to one row and column must + // show that both the row and column were truncated. + CompMatr1 matr = getInlineCompMatr1({{1,2},{3,4}}); + setQuESTNumReportedNewlines(1); + + auto reportWithLimits = [&](qindex maxRows, qindex maxCols) { + setQuESTMaxNumReportedItems(maxRows, maxCols); + + std::stringstream buffer; + std::streambuf * old = std::cout.rdbuf(buffer.rdbuf()); + reportCompMatr1(matr); + std::cout.rdbuf(old); + return buffer.str(); + }; + + std::string truncated = reportWithLimits(1, 1); + std::string unlimited = reportWithLimits(0, 0); + std::string complete = reportWithLimits(2, 2); + + // restore the defaults in printer.cpp for subsequent tests + setQuESTMaxNumReportedItems(32, 4); + setQuESTNumReportedNewlines(2); + + REQUIRE( truncated.find("…") != std::string::npos ); + REQUIRE( truncated.find("⋮") != std::string::npos ); + REQUIRE( unlimited.find("…") == std::string::npos ); + REQUIRE( unlimited.find("⋮") == std::string::npos ); + REQUIRE( complete.find("…") == std::string::npos ); + REQUIRE( complete.find("⋮") == std::string::npos ); +} + + TEST_CASE( "setQuESTNumReportedNewlines", TEST_CATEGORY ) { SECTION( LABEL_CORRECTNESS ) { From 1c0c3fdf12808654bfe80f7da61c2810e0ea097e Mon Sep 17 00:00:00 2001 From: User178-a11y Date: Wed, 14 Oct 2026 01:28:19 +0530 Subject: [PATCH 2/2] Fix reporter truncation tests across MPI ranks --- quest/src/core/printer.cpp | 6 ++- tests/unit/debug.cpp | 85 +++++++++++++++++++++++++------------- 2 files changed, 62 insertions(+), 29 deletions(-) diff --git a/quest/src/core/printer.cpp b/quest/src/core/printer.cpp index ee469d40f..d71db036f 100644 --- a/quest/src/core/printer.cpp +++ b/quest/src/core/printer.cpp @@ -721,6 +721,10 @@ void printContiguousRowsInTwoQuadrants( printRowInTwoQuadrants(left[r], leftColWidths, rightRow, rightColWidths, isHorizontallyTruncated); + // a trailing ellipsis has no spacer when there is no right portion + if (isHorizontallyTruncated && rightRow.empty() && !rowLabels.empty() && !rowLabels[r].empty()) + cout << string(MIN_SPACE_BETWEEN_DENSE_MATRIX_COLS, MATRIX_SPACE_CHAR); + // print optional row label, using trailing space left by above row print cout << (rowLabels.empty()? "" : rowLabels[r]); cout << endl; @@ -795,7 +799,7 @@ void printMatrixInFourQuadrants( upperRowLabels, baseIndent, indentPerRow, 0, isHorizontallyTruncated); - // finish immediately if there are no lower rows and no data was omitted + // finish immediately if there are no lower rows and no rows were omitted if (lowerLeftStrings.empty() && !isVerticallyTruncated) return; diff --git a/tests/unit/debug.cpp b/tests/unit/debug.cpp index 67939b5eb..ad6841598 100644 --- a/tests/unit/debug.cpp +++ b/tests/unit/debug.cpp @@ -92,8 +92,10 @@ TEST_CASE( "setQuESTMaxNumReportedSigFigs", TEST_CATEGORY ) { std::string ref = refs[numSigFigs-1]; - CAPTURE( numSigFigs, ref ); - REQUIRE( out == ref ); + if (getQuESTEnv().rank == 0) { + CAPTURE( numSigFigs, ref ); + REQUIRE( out == ref ); + } } } @@ -114,35 +116,60 @@ TEST_CASE( "setQuESTMaxNumReportedSigFigs", TEST_CATEGORY ) { TEST_CASE( "setQuESTMaxNumReportedItems", TEST_CATEGORY ) { - // Reproduce issue #810: a 2x2 matrix limited to one row and column must - // show that both the row and column were truncated. - CompMatr1 matr = getInlineCompMatr1({{1,2},{3,4}}); - setQuESTNumReportedNewlines(1); + SECTION( LABEL_CORRECTNESS ) { - auto reportWithLimits = [&](qindex maxRows, qindex maxCols) { - setQuESTMaxNumReportedItems(maxRows, maxCols); + // restore stdout and the reporting defaults even if a reporter throws + struct ScopedReportCapture { + std::stringstream buffer; + std::streambuf* old = std::cout.rdbuf(buffer.rdbuf()); - std::stringstream buffer; - std::streambuf * old = std::cout.rdbuf(buffer.rdbuf()); - reportCompMatr1(matr); - std::cout.rdbuf(old); - return buffer.str(); - }; + ~ScopedReportCapture() { + std::cout.rdbuf(old); + setQuESTMaxNumReportedItems(32, 4); + setQuESTNumReportedNewlines(2); + } + }; - std::string truncated = reportWithLimits(1, 1); - std::string unlimited = reportWithLimits(0, 0); - std::string complete = reportWithLimits(2, 2); + auto reportWithLimits = [&](qindex rows, qindex cols, auto report) { + ScopedReportCapture capture; + setQuESTMaxNumReportedItems(rows, cols); + setQuESTNumReportedNewlines(1); + report(); + return capture.buffer.str(); + }; - // restore the defaults in printer.cpp for subsequent tests - setQuESTMaxNumReportedItems(32, 4); - setQuESTNumReportedNewlines(2); + CompMatr1 matr = getInlineCompMatr1({{1,2},{3,4}}); + auto reportMatrix = [&] { reportCompMatr1(matr); }; + DiagMatr2 diag = getInlineDiagMatr2({1,2,3,4}); + + // finish all reporter calls and cleanup on every rank before asserting + vector outputs = { + reportWithLimits(1, 1, reportMatrix), + reportWithLimits(1, 2, reportMatrix), + reportWithLimits(2, 1, reportMatrix), + reportWithLimits(0, 0, reportMatrix), + reportWithLimits(2, 2, reportMatrix), + reportWithLimits(1, 1, [&] { reportDiagMatr2(diag); }) + }; + vector refs = { + " 1 …\n ⋮\n", + " 1 2 \n ⋮\n", + " 1 …\n 3 …\n", + " 1 2 \n 3 4 \n", + " 1 2 \n 3 4 \n", + " 1 \n ⋱\n" + }; - REQUIRE( truncated.find("…") != std::string::npos ); - REQUIRE( truncated.find("⋮") != std::string::npos ); - REQUIRE( unlimited.find("…") == std::string::npos ); - REQUIRE( unlimited.find("⋮") == std::string::npos ); - REQUIRE( complete.find("…") == std::string::npos ); - REQUIRE( complete.find("⋮") == std::string::npos ); + if (getQuESTEnv().rank == 0) { + for (size_t i=0; i