diff --git a/quest/src/core/printer.cpp b/quest/src/core/printer.cpp index 863317c8f..d71db036f 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); + + // 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]); @@ -727,7 +737,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 +746,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 +787,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 +797,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 rows were 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 +841,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 +895,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 +1145,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 +1277,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 +1420,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..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 ); + } } } @@ -112,6 +114,65 @@ TEST_CASE( "setQuESTMaxNumReportedSigFigs", TEST_CATEGORY ) { } +TEST_CASE( "setQuESTMaxNumReportedItems", TEST_CATEGORY ) { + + SECTION( LABEL_CORRECTNESS ) { + + // restore stdout and the reporting defaults even if a reporter throws + struct ScopedReportCapture { + std::stringstream buffer; + std::streambuf* old = std::cout.rdbuf(buffer.rdbuf()); + + ~ScopedReportCapture() { + std::cout.rdbuf(old); + setQuESTMaxNumReportedItems(32, 4); + setQuESTNumReportedNewlines(2); + } + }; + + auto reportWithLimits = [&](qindex rows, qindex cols, auto report) { + ScopedReportCapture capture; + setQuESTMaxNumReportedItems(rows, cols); + setQuESTNumReportedNewlines(1); + report(); + return capture.buffer.str(); + }; + + 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" + }; + + if (getQuESTEnv().rank == 0) { + for (size_t i=0; i