Quantum Phenomena Explorer 7.9.8
Interactive quantum-phenomena Explorer Tutor — source documentation
Loading...
Searching...
No Matches
quantumloschmidtplotwidget.cpp
Go to the documentation of this file.
1/**
2 * @file quantumloschmidtplotwidget.cpp
3 * @brief Implements the quantumloschmidtplotwidget visualization component used by QPE.
4 * @ingroup qpe_graphics
5 *
6 * Source: @c graphics/renderer/quantumloschmidtplotwidget.cpp. This file is part of Quantum Phenomena Explorer (QPE),
7 * maintained by Officina Turini. See LICENSE_IT.txt / LICENSE.txt for the
8 * QPE freeware source-available terms and THIRD_PARTY_NOTICES.txt for
9 * third-party components.
10 */
11
13
14#include <QPaintEvent>
15#include <QPainter>
16#include <QPainterPath>
17
18#include <algorithm>
19#include <cmath>
20#include <limits>
21
22namespace {
23
24/**
25 * @brief Performs frame.
26 * @param p The p value used by the operation.
27 * @param r The r value used by the operation.
28 */
29void frame(QPainter &p, const QRectF &r)
30{
31 p.setBrush(Qt::NoBrush);
32 p.setPen(QPen(QColor(70, 79, 91), 1.0));
33 p.drawRect(r);
34}
35
36/**
37 * @brief Performs clamp01.
38 * @param v The v value used by the operation.
39 */
40double clamp01(double v)
41{
42 return std::max(0.0, std::min(1.0, v));
43}
44
45} // namespace
46
48 : QWidget(parent)
49{
50 setMinimumHeight(390);
51 setAutoFillBackground(false);
52}
53
55{
56 history_ = &history;
57 update();
58}
59
61{
62 history_ = nullptr;
63 update();
64}
65
67{
68 return QSize(680, 410);
69}
70
72{
73 Q_UNUSED(event);
74 QPainter p(this);
75 p.setRenderHint(QPainter::Antialiasing, true);
76 p.setRenderHint(QPainter::TextAntialiasing, true);
77 p.fillRect(rect(), QColor(14, 17, 22));
78
79 const double marginL = 58.0;
80 const double marginR = 42.0;
81 const double top = 34.0;
82 const double gap = 42.0;
83 const double bottom = 42.0;
84 const double available = std::max(180.0, height() - top - gap - bottom);
85 const double upperH = available * 0.48;
86 const QRectF pathRect(marginL, top, std::max(100.0, width() - marginL - marginR), upperH);
87 const QRectF echoRect(marginL, pathRect.bottom() + gap, pathRect.width(), available - upperH);
88 frame(p, pathRect);
89 frame(p, echoRect);
90
91 p.setPen(QColor(226, 232, 240));
92 p.drawText(QRectF(pathRect.left(), 5.0, pathRect.width(), 22.0), Qt::AlignCenter,
93 QStringLiteral("Loschmidt echo — centroid path before and after time reversal"));
94 p.drawText(QRectF(echoRect.left(), pathRect.bottom() + 10.0, echoRect.width(), 22.0), Qt::AlignCenter,
95 QStringLiteral("Density echo vs coherent time-reversed-state fidelity"));
96
97 if (!history_ || !history_->configured() || history_->empty()) {
98 p.setPen(QColor(205, 214, 224));
99 p.drawText(pathRect, Qt::AlignCenter,
100 QStringLiteral("Load Loschmidt Echo / Quantum Time Reversal and press Play"));
101 p.drawText(echoRect, Qt::AlignCenter,
102 QStringLiteral("At t = 2T a perfect reversal should reconstruct the initial density"));
103 return;
104 }
105
106 const std::vector<qpe::QuantumLoschmidtSample2D> &samples = history_->samples();
107 const double reversalTime = history_->config().reversalTime;
108
109 double minX = std::numeric_limits<double>::infinity();
110 double maxX = -std::numeric_limits<double>::infinity();
111 double minY = std::numeric_limits<double>::infinity();
112 double maxY = -std::numeric_limits<double>::infinity();
113 for (const qpe::QuantumLoschmidtSample2D &s : samples) {
114 minX = std::min(minX, s.meanX);
115 maxX = std::max(maxX, s.meanX);
116 minY = std::min(minY, s.meanY);
117 maxY = std::max(maxY, s.meanY);
118 }
119 if (!(maxX > minX)) { minX -= 1.0; maxX += 1.0; }
120 if (!(maxY > minY)) { minY -= 1.0; maxY += 1.0; }
121 const double padX = 0.12 * std::max(1.0, maxX - minX);
122 const double padY = 0.12 * std::max(1.0, maxY - minY);
123 minX -= padX; maxX += padX; minY -= padY; maxY += padY;
124
125 const auto mxPath = [&](double x) {
126 return pathRect.left() + (x - minX) / (maxX - minX) * pathRect.width();
127 };
128 const auto myPath = [&](double y) {
129 return pathRect.bottom() - (y - minY) / (maxY - minY) * pathRect.height();
130 };
131
132 QPainterPath outbound;
133 QPainterPath returning;
134 bool outFirst = true;
135 bool retFirst = true;
136 QPointF reversalPoint;
137 bool haveReversalPoint = false;
138 for (const qpe::QuantumLoschmidtSample2D &s : samples) {
139 const QPointF pt(mxPath(s.meanX), myPath(s.meanY));
140 if (s.time <= reversalTime + 1.0e-9 && !s.reversalApplied) {
141 if (outFirst) { outbound.moveTo(pt); outFirst = false; }
142 else outbound.lineTo(pt);
143 reversalPoint = pt;
144 } else {
145 if (!haveReversalPoint) {
146 if (!outFirst) returning.moveTo(reversalPoint);
147 else returning.moveTo(pt);
148 retFirst = false;
149 haveReversalPoint = true;
150 }
151 if (retFirst) { returning.moveTo(pt); retFirst = false; }
152 else returning.lineTo(pt);
153 }
154 }
155
156 p.setPen(QPen(QColor(79, 220, 255), 2.2));
157 p.drawPath(outbound);
158 p.setPen(QPen(QColor(255, 190, 79), 2.2));
159 p.drawPath(returning);
160
161 const qpe::QuantumLoschmidtSample2D &first = samples.front();
162 const qpe::QuantumLoschmidtSample2D &last = samples.back();
163 const QPointF startPt(mxPath(first.meanX), myPath(first.meanY));
164 const QPointF currentPt(mxPath(last.meanX), myPath(last.meanY));
165 p.setPen(Qt::NoPen);
166 p.setBrush(QColor(103, 232, 153));
167 p.drawEllipse(startPt, 5.5, 5.5);
168 if (haveReversalPoint) {
169 p.setBrush(QColor(236, 112, 255));
170 p.drawEllipse(reversalPoint, 6.0, 6.0);
171 }
172 p.setBrush(QColor(244, 247, 251));
173 p.drawEllipse(currentPt, 4.5, 4.5);
174
175 p.setPen(QColor(79, 220, 255));
176 p.drawText(QRectF(pathRect.left() + 8.0, pathRect.top() + 5.0, 180.0, 20.0), Qt::AlignLeft,
177 QStringLiteral("cyan: outbound"));
178 p.setPen(QColor(255, 190, 79));
179 p.drawText(QRectF(pathRect.left() + 142.0, pathRect.top() + 5.0, 180.0, 20.0), Qt::AlignLeft,
180 QStringLiteral("gold: return"));
181 p.setPen(QColor(202, 211, 221));
182 p.drawText(QRectF(pathRect.right() - 320.0, pathRect.top() + 5.0, 310.0, 20.0), Qt::AlignRight,
183 QStringLiteral("t=%1 samples=%2")
184 .arg(last.time, 0, 'f', 2)
185 .arg(static_cast<qulonglong>(samples.size())));
186
187 const double t0 = 0.0;
188 const double tMax = std::max(2.0 * reversalTime, std::max(reversalTime, last.time));
189 const auto mx = [&](double t) {
190 return echoRect.left() + (t - t0) / std::max(1.0e-12, tMax - t0) * echoRect.width();
191 };
192 const auto my = [&](double f) {
193 return echoRect.bottom() - clamp01(f) * echoRect.height();
194 };
195
196 p.setPen(QPen(QColor(65, 72, 82), 1.0));
197 for (int i = 1; i < 4; ++i) {
198 const double yy = echoRect.bottom() - echoRect.height() * static_cast<double>(i) / 4.0;
199 p.drawLine(QPointF(echoRect.left(), yy), QPointF(echoRect.right(), yy));
200 }
201 p.setPen(QPen(QColor(236, 112, 255), 1.2, Qt::DashLine));
202 p.drawLine(QPointF(mx(reversalTime), echoRect.top()), QPointF(mx(reversalTime), echoRect.bottom()));
203 p.setPen(QPen(QColor(103, 232, 153), 1.2, Qt::DashLine));
204 p.drawLine(QPointF(mx(2.0 * reversalTime), echoRect.top()), QPointF(mx(2.0 * reversalTime), echoRect.bottom()));
205
206 QPainterPath densityPath;
207 QPainterPath statePath;
208 bool firstDensity = true;
209 bool firstState = true;
210 for (const qpe::QuantumLoschmidtSample2D &s : samples) {
211 const QPointF pd(mx(s.time), my(s.densityEcho));
212 const QPointF ps(mx(s.time), my(s.stateEcho));
213 if (firstDensity) { densityPath.moveTo(pd); firstDensity = false; }
214 else densityPath.lineTo(pd);
215 if (firstState) { statePath.moveTo(ps); firstState = false; }
216 else statePath.lineTo(ps);
217 }
218 p.setPen(QPen(QColor(79, 220, 255), 2.0));
219 p.drawPath(densityPath);
220 p.setPen(QPen(QColor(255, 190, 79), 2.0));
221 p.drawPath(statePath);
222
223 p.setPen(QColor(79, 220, 255));
224 p.drawText(QRectF(echoRect.left() + 8.0, echoRect.top() + 5.0, 210.0, 20.0), Qt::AlignLeft,
225 QStringLiteral("cyan: density echo"));
226 p.setPen(QColor(255, 190, 79));
227 p.drawText(QRectF(echoRect.left() + 165.0, echoRect.top() + 5.0, 300.0, 20.0), Qt::AlignLeft,
228 QStringLiteral("gold: coherent state echo"));
229
230 p.setPen(QColor(202, 211, 221));
231 p.drawText(QRectF(4.0, echoRect.top() - 8.0, 48.0, 20.0), Qt::AlignRight, QStringLiteral("1"));
232 p.drawText(QRectF(4.0, echoRect.bottom() - 10.0, 48.0, 20.0), Qt::AlignRight, QStringLiteral("0"));
233 p.drawText(QRectF(echoRect.left(), echoRect.bottom() + 5.0, 70.0, 20.0), Qt::AlignLeft,
234 QStringLiteral("0"));
235 p.drawText(QRectF(mx(reversalTime) - 70.0, echoRect.bottom() + 5.0, 140.0, 20.0), Qt::AlignCenter,
236 QStringLiteral("T = %1").arg(reversalTime, 0, 'f', 2));
237 p.drawText(QRectF(mx(2.0 * reversalTime) - 75.0, echoRect.bottom() + 5.0, 150.0, 20.0), Qt::AlignCenter,
238 QStringLiteral("2T = %1").arg(2.0 * reversalTime, 0, 'f', 2));
239
240 p.setPen(QColor(215, 223, 232));
241 p.drawText(QRectF(echoRect.right() - 390.0, echoRect.bottom() - 27.0, 380.0, 20.0), Qt::AlignRight,
242 QStringLiteral("current: density=%1 state=%2 norm=%3")
243 .arg(last.densityEcho, 0, 'f', 4)
244 .arg(last.stateEcho, 0, 'f', 4)
245 .arg(last.norm, 0, 'f', 5));
246}
QSize minimumSizeHint() const override
Performs minimum size hint.
void setData(const qpe::QuantumLoschmidtHistory2D &history)
Sets data.
void paintEvent(QPaintEvent *event) override
Paints event.
const qpe::QuantumLoschmidtHistory2D * history_
QuantumLoschmidtPlotWidget(QWidget *parent=nullptr)
Performs quantum loschmidt plot widget.
Implements the Quantum Loschmidt History2D component.
const std::vector< QuantumLoschmidtSample2D > & samples() const noexcept
Samples s.
bool configured() const noexcept
Returns configured.
bool empty() const noexcept
Returns whether the object contains no data.
const QuantumLoschmidt2DConfig & config() const noexcept
Returns config.
void frame(QPainter &p, const QRectF &r)
Performs frame.
Declares the quantumloschmidtplotwidget visualization component used by QPE.
Data structure used by the Quantum Loschmidt Sample2D component.