Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 41 additions & 19 deletions quest/src/core/printer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -679,16 +679,20 @@ void printPerRowIndent(string baseIndent, size_t row, string indentPerRow) {

void printRowInTwoQuadrants(
vector<string> leftRow, vector<size_t> leftColWidths,
vector<string> rightRow, vector<size_t> rightColWidths
vector<string> rightRow, vector<size_t> rightColWidths,
bool isHorizontallyTruncated
) {
// print left portion of row
for (size_t c=0; c<leftRow.size(); c++)
cout << left << setw(leftColWidths[c] + MIN_SPACE_BETWEEN_DENSE_MATRIX_COLS) << setfill(MATRIX_SPACE_CHAR)
<< leftRow[c];

// finish without printing trailing newline if there is no right portion
if (rightRow.empty())
if (rightRow.empty()) {
if (isHorizontallyTruncated)
cout << HDOTS_CHAR;
return;
}

// draw ellipsis; left-spacer already applied by previous amp
string spacer = string(MIN_SPACE_BETWEEN_DENSE_MATRIX_COLS, MATRIX_SPACE_CHAR);
Expand All @@ -707,13 +711,19 @@ void printContiguousRowsInTwoQuadrants(
stringmatr left, vector<size_t> leftColWidths,
stringmatr right, vector<size_t> rightColWidths,
vector<string> rowLabels,
string indent, string indentPerRow, size_t rowOffsetForIndent
string indent, string indentPerRow, size_t rowOffsetForIndent,
bool isHorizontallyTruncated
) {
for (size_t r=0; r<left.size(); r++) {
printPerRowIndent(indent, r + rowOffsetForIndent, indentPerRow);

auto rightRow = (right.empty())? vector<string>{} : 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]);
Expand All @@ -727,20 +737,21 @@ void printMatrixInFourQuadrants(
qcompmatr lowerLeft, qcompmatr lowerRight,
vector<string> leftColLabels, vector<string> rightColLabels, // shown above the first row
vector<string> upperRowLabels, vector<string> 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
// used to print truncated (or non-truncated) non-square matrices, horizontal and
// 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;
Expand Down Expand Up @@ -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;
}

Expand All @@ -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
}


Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
}


Expand Down Expand Up @@ -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);
}


Expand Down Expand Up @@ -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);
}


Expand Down
71 changes: 67 additions & 4 deletions tests/unit/debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
}
}
}

Expand All @@ -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<std::string> 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<std::string> 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<outputs.size(); i++) {
CAPTURE( i );
// omit the header, whose byte counts depend on precision
auto headerEnd = outputs[i].find('\n');
REQUIRE( headerEnd != std::string::npos );
REQUIRE( outputs[i].substr(headerEnd + 1) == refs[i] );
}
}
}
}


TEST_CASE( "setQuESTNumReportedNewlines", TEST_CATEGORY ) {

SECTION( LABEL_CORRECTNESS ) {
Expand All @@ -129,8 +190,10 @@ TEST_CASE( "setQuESTNumReportedNewlines", TEST_CATEGORY ) {

std::string ref = "x" + std::string(numNewlines, '\n');

CAPTURE( numNewlines, ref );
REQUIRE( out == ref );
if (getQuESTEnv().rank == 0) {
CAPTURE( numNewlines, ref );
REQUIRE( out == ref );
}
}
}

Expand Down
Loading