Initial quantum circuit.
This commit is contained in:
parent
77ce58c612
commit
20c13c1cdf
38 changed files with 1153 additions and 14 deletions
|
@ -1,5 +1,7 @@
|
||||||
#include "ComplexNumber.h"
|
#include "ComplexNumber.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
ComplexNumber::ComplexNumber(double real, double imaginary)
|
ComplexNumber::ComplexNumber(double real, double imaginary)
|
||||||
: mReal(real),
|
: mReal(real),
|
||||||
mImaginary(imaginary)
|
mImaginary(imaginary)
|
||||||
|
@ -25,4 +27,9 @@ void ComplexNumber::setReal(double value)
|
||||||
void ComplexNumber::setImaginary(double value)
|
void ComplexNumber::setImaginary(double value)
|
||||||
{
|
{
|
||||||
mImaginary = value;
|
mImaginary = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ComplexNumber::getMagnitude() const
|
||||||
|
{
|
||||||
|
return std::sqrt(mReal * mReal + mImaginary * mImaginary);
|
||||||
}
|
}
|
|
@ -9,6 +9,8 @@ public:
|
||||||
|
|
||||||
double getImaginary() const;
|
double getImaginary() const;
|
||||||
|
|
||||||
|
double getMagnitude() const;
|
||||||
|
|
||||||
void setReal(double value);
|
void setReal(double value);
|
||||||
|
|
||||||
void setImaginary(double value);
|
void setImaginary(double value);
|
||||||
|
|
0
plugins/quantum_computing/src/BasicQuantumGates.cpp
Normal file
0
plugins/quantum_computing/src/BasicQuantumGates.cpp
Normal file
21
plugins/quantum_computing/src/BasicQuantumGates.h
Normal file
21
plugins/quantum_computing/src/BasicQuantumGates.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "QuantumGate.h"
|
||||||
|
|
||||||
|
class XQuantumGate : public OneInOneOutQuantumGate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GateType getGateType() const override
|
||||||
|
{
|
||||||
|
return GateType::X;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ZQuantumGate : public OneInOneOutQuantumGate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GateType getGateType() const override
|
||||||
|
{
|
||||||
|
return GateType::Z;
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,31 +1,50 @@
|
||||||
set(PLUGIN_NAME quantum_computing)
|
set(PLUGIN_NAME quantum_computing)
|
||||||
|
|
||||||
list(APPEND quantum_computing_HEADERS
|
list(APPEND HEADERS
|
||||||
QuantumCircuit.h
|
QuantumCircuit.h
|
||||||
BlochSphere.h
|
BlochSphere.h
|
||||||
QuantumState.h
|
QuantumState.h
|
||||||
Qubit.h
|
Qubit.h
|
||||||
QuantumGate.h
|
QuantumGate.h
|
||||||
QuantumOperator.h
|
QuantumOperator.h
|
||||||
|
QuantumCircuitReader.h
|
||||||
|
QuantumCircuitElement.h
|
||||||
|
QuantumWire.h
|
||||||
|
QuantumTerminal.h
|
||||||
|
BasicQuantumGates.h
|
||||||
visuals/BlochSphereNode.h
|
visuals/BlochSphereNode.h
|
||||||
|
visuals/QuantumCircuitNode.h
|
||||||
|
visuals/QuantumGateNode.h
|
||||||
|
visuals/QuantumWireNode.h
|
||||||
|
visuals/QuantumTerminalNode.h
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND quantum_computing_LIB_INCLUDES
|
list(APPEND SOURCES
|
||||||
QuantumCircuit.cpp
|
QuantumCircuit.cpp
|
||||||
BlochSphere.cpp
|
BlochSphere.cpp
|
||||||
QuantumState.cpp
|
QuantumState.cpp
|
||||||
Qubit.cpp
|
Qubit.cpp
|
||||||
QuantumGate.cpp
|
QuantumGate.cpp
|
||||||
QuantumOperator.cpp
|
QuantumOperator.cpp
|
||||||
|
QuantumCircuitReader.cpp
|
||||||
|
QuantumCircuitElement.cpp
|
||||||
|
QuantumWire.cpp
|
||||||
|
QuantumTerminal.cpp
|
||||||
|
BasicQuantumGates.cpp
|
||||||
|
visuals/BlochSphereNode.cpp
|
||||||
|
visuals/QuantumCircuitNode.cpp
|
||||||
|
visuals/QuantumGateNode.cpp
|
||||||
|
visuals/QuantumWireNode.cpp
|
||||||
|
visuals/QuantumTerminalNode.cpp
|
||||||
visuals/BlochSphereNode.cpp
|
visuals/BlochSphereNode.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(${PLUGIN_NAME} SHARED ${quantum_computing_LIB_INCLUDES} ${quantum_computing_HEADERS})
|
add_library(${PLUGIN_NAME} SHARED ${SOURCES} ${HEADERS})
|
||||||
|
|
||||||
target_include_directories(${PLUGIN_NAME} PUBLIC
|
target_include_directories(${PLUGIN_NAME} PUBLIC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/visuals
|
${CMAKE_CURRENT_SOURCE_DIR}/visuals
|
||||||
)
|
)
|
||||||
target_link_libraries(${PLUGIN_NAME} PUBLIC core visual_elements ntk_math)
|
target_link_libraries(${PLUGIN_NAME} PUBLIC core visual_elements ntk_math publishing)
|
||||||
set_property(TARGET ${PLUGIN_NAME} PROPERTY FOLDER plugins)
|
set_property(TARGET ${PLUGIN_NAME} PROPERTY FOLDER plugins)
|
||||||
set_target_properties( ${PLUGIN_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
set_target_properties( ${PLUGIN_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
|
@ -0,0 +1,47 @@
|
||||||
|
#include "QuantumCircuit.h"
|
||||||
|
|
||||||
|
#include "QuantumGate.h"
|
||||||
|
|
||||||
|
void QuantumCircuit::addInputTerminal(QuantumTerminalPtr terminal)
|
||||||
|
{
|
||||||
|
mInputTerminals.push_back(terminal.get());
|
||||||
|
mElements.push_back(std::move(terminal));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuantumCircuit::addOutputTerminal(QuantumTerminalPtr terminal)
|
||||||
|
{
|
||||||
|
mOutputTerminals.push_back(terminal.get());
|
||||||
|
mElements.push_back(std::move(terminal));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuantumCircuit::addQuantumWire(QuantumWirePtr wire)
|
||||||
|
{
|
||||||
|
mWires.push_back(wire.get());
|
||||||
|
mElements.push_back(std::move(wire));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuantumCircuit::addLogicGate(QuantumGatePtr gate)
|
||||||
|
{
|
||||||
|
mGates.push_back(gate.get());
|
||||||
|
mElements.push_back(std::move(gate));
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<QuantumTerminal*>& QuantumCircuit::getInputTerminals() const
|
||||||
|
{
|
||||||
|
return mInputTerminals;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<QuantumTerminal*>& QuantumCircuit::getOutputTerminals() const
|
||||||
|
{
|
||||||
|
return mOutputTerminals;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<QuantumGate*>& QuantumCircuit::getLogicGates() const
|
||||||
|
{
|
||||||
|
return mGates;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<QuantumWire*>& QuantumCircuit::getQuantumWires() const
|
||||||
|
{
|
||||||
|
return mWires;
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "QuantumCircuitElement.h"
|
||||||
|
#include "QuantumGate.h"
|
||||||
|
#include "QuantumTerminal.h"
|
||||||
|
#include "QuantumWire.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class QuantumCircuit
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void addInputTerminal(QuantumTerminalPtr terminal);
|
||||||
|
|
||||||
|
void addOutputTerminal(QuantumTerminalPtr terminal);
|
||||||
|
|
||||||
|
void addQuantumWire(QuantumWirePtr wire);
|
||||||
|
|
||||||
|
void addLogicGate(QuantumGatePtr gate);
|
||||||
|
|
||||||
|
const std::vector<QuantumTerminal*>& getInputTerminals() const;
|
||||||
|
|
||||||
|
const std::vector<QuantumTerminal*>& getOutputTerminals() const;
|
||||||
|
|
||||||
|
const std::vector<QuantumGate*>& getLogicGates() const;
|
||||||
|
|
||||||
|
const std::vector<QuantumWire*>& getQuantumWires() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<QuantumTerminal*> mInputTerminals;
|
||||||
|
std::vector<QuantumTerminal*> mOutputTerminals;
|
||||||
|
|
||||||
|
std::vector<QuantumWire*> mWires;
|
||||||
|
std::vector<QuantumGate*> mGates;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<QuantumCircuitElement> > mElements;
|
||||||
|
};
|
0
plugins/quantum_computing/src/QuantumCircuitElement.cpp
Normal file
0
plugins/quantum_computing/src/QuantumCircuitElement.cpp
Normal file
20
plugins/quantum_computing/src/QuantumCircuitElement.h
Normal file
20
plugins/quantum_computing/src/QuantumCircuitElement.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class QuantumCircuitElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
INPUT_TERMINAL,
|
||||||
|
OUTPUT_TERMINAL,
|
||||||
|
WIRE,
|
||||||
|
GATE,
|
||||||
|
UNKNOWN
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~QuantumCircuitElement() = default;
|
||||||
|
|
||||||
|
virtual QuantumCircuitElement::Type getType() const = 0;
|
||||||
|
};
|
204
plugins/quantum_computing/src/QuantumCircuitReader.cpp
Normal file
204
plugins/quantum_computing/src/QuantumCircuitReader.cpp
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
#include "QuantumCircuitReader.h"
|
||||||
|
|
||||||
|
#include "QuantumCircuit.h"
|
||||||
|
#include "Qubit.h"
|
||||||
|
#include "QuantumTerminal.h"
|
||||||
|
#include "BasicQuantumGates.h"
|
||||||
|
#include "QuantumWire.h"
|
||||||
|
|
||||||
|
#include "File.h"
|
||||||
|
#include "StringUtils.h"
|
||||||
|
#include "FileLogger.h"
|
||||||
|
|
||||||
|
std::unique_ptr<QuantumCircuit> QuantumCircuitReader::read(const Path& path)
|
||||||
|
{
|
||||||
|
File file(path);
|
||||||
|
return read(file.readText());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<QuantumCircuit> QuantumCircuitReader::read(const std::string& content)
|
||||||
|
{
|
||||||
|
auto circuit = std::make_unique<QuantumCircuit>();
|
||||||
|
mWorkingCircuit = circuit.get();
|
||||||
|
|
||||||
|
std::size_t cursor = 0;
|
||||||
|
for (const auto& line : StringUtils::toLines(content))
|
||||||
|
{
|
||||||
|
onLine(line, cursor);
|
||||||
|
cursor++;
|
||||||
|
}
|
||||||
|
return circuit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuantumCircuitReader::onLine(const std::string& line, std::size_t jdx)
|
||||||
|
{
|
||||||
|
mWorkingString.clear();
|
||||||
|
std::size_t cursor = 0;
|
||||||
|
|
||||||
|
while (cursor < line.size())
|
||||||
|
{
|
||||||
|
const auto c = line[cursor];
|
||||||
|
MLOG_INFO("Working char: " << std::string(1, c));
|
||||||
|
|
||||||
|
if (c == '|')
|
||||||
|
{
|
||||||
|
if (cursor + 1 < line.size())
|
||||||
|
{
|
||||||
|
if (line[cursor + 1] == '-')
|
||||||
|
{
|
||||||
|
onVertialQuantumWire({ cursor, jdx });
|
||||||
|
}
|
||||||
|
else if (auto ket = checkForKet(line.substr(cursor + 1, line.size() - cursor)); !ket.empty())
|
||||||
|
{
|
||||||
|
onKet({ cursor, jdx }, ket);
|
||||||
|
cursor += ket.size() + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mWorkingString += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == '-')
|
||||||
|
{
|
||||||
|
if (cursor + 1 < line.size())
|
||||||
|
{
|
||||||
|
const auto end_id = getWireEnd(line.substr(cursor, line.size() - cursor));
|
||||||
|
MLOG_INFO("Wire: " << cursor << " with length " << end_id);
|
||||||
|
cursor += end_id - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mWorkingString += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (cursor + 1 < line.size())
|
||||||
|
{
|
||||||
|
auto gate = checkForGate(line.substr(cursor, line.size() - cursor));
|
||||||
|
onGate({ cursor, jdx }, gate);
|
||||||
|
cursor += gate.size() - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mWorkingString += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor++;
|
||||||
|
}
|
||||||
|
onLineEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuantumCircuitReader::onLineEnd()
|
||||||
|
{
|
||||||
|
auto output_terminal = std::make_unique<QuantumTerminal>(QuantumTerminal::TerminalType::OUTPUT);
|
||||||
|
|
||||||
|
auto wire = std::make_unique<QuantumWire>(mWorkingElement, output_terminal.get());
|
||||||
|
mWorkingCircuit->addQuantumWire(std::move(wire));
|
||||||
|
|
||||||
|
mWorkingCircuit->addOutputTerminal(std::move(output_terminal));
|
||||||
|
|
||||||
|
mWorkingElement = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuantumCircuitReader::onGate(Location loc, const std::string value)
|
||||||
|
{
|
||||||
|
MLOG_INFO("Got gate: " << value);
|
||||||
|
|
||||||
|
QuantumGatePtr gate;
|
||||||
|
|
||||||
|
if (value == "X")
|
||||||
|
{
|
||||||
|
gate = std::make_unique<XQuantumGate>();
|
||||||
|
}
|
||||||
|
else if (value == "Z")
|
||||||
|
{
|
||||||
|
gate = std::make_unique<ZQuantumGate>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gate)
|
||||||
|
{
|
||||||
|
auto wire = std::make_unique<QuantumWire>(mWorkingElement, gate.get());
|
||||||
|
mWorkingCircuit->addQuantumWire(std::move(wire));
|
||||||
|
|
||||||
|
mWorkingElement = gate.get();
|
||||||
|
mWorkingCircuit->addLogicGate(std::move(gate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string QuantumCircuitReader::checkForGate(const std::string& segment)
|
||||||
|
{
|
||||||
|
std::string working_string;
|
||||||
|
for (const auto c : segment)
|
||||||
|
{
|
||||||
|
if (c == '-')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
working_string += c;
|
||||||
|
}
|
||||||
|
return working_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuantumCircuitReader::onKet(Location loc, const std::string value)
|
||||||
|
{
|
||||||
|
MLOG_INFO("Got input state: " << value);
|
||||||
|
Qubit qubit;
|
||||||
|
if (value == "1")
|
||||||
|
{
|
||||||
|
qubit = Qubit({ 0.0, 0.0 }, { 1.0, 0.0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
auto input_terminal = std::make_unique<QuantumTerminal>(QuantumTerminal::TerminalType::INPUT);
|
||||||
|
|
||||||
|
mWorkingElement = input_terminal.get();
|
||||||
|
mWorkingCircuit->addInputTerminal(std::move(input_terminal));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t QuantumCircuitReader::getWireEnd(const std::string& segment)
|
||||||
|
{
|
||||||
|
std::size_t idx = 0;
|
||||||
|
for (const auto c : segment)
|
||||||
|
{
|
||||||
|
if (c != '-')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string QuantumCircuitReader::checkForKet(const std::string& segment)
|
||||||
|
{
|
||||||
|
std::string working_string;
|
||||||
|
bool found{ false };
|
||||||
|
|
||||||
|
for (const auto c : segment)
|
||||||
|
{
|
||||||
|
if (c == '>')
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
working_string += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
return working_string;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuantumCircuitReader::onVertialQuantumWire(Location loc)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
40
plugins/quantum_computing/src/QuantumCircuitReader.h
Normal file
40
plugins/quantum_computing/src/QuantumCircuitReader.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using Path = std::filesystem::path;
|
||||||
|
|
||||||
|
class QuantumCircuit;
|
||||||
|
class QuantumCircuitElement;
|
||||||
|
|
||||||
|
class QuantumCircuitReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::unique_ptr<QuantumCircuit> read(const Path& path);
|
||||||
|
|
||||||
|
std::unique_ptr<QuantumCircuit> read(const std::string& content);
|
||||||
|
|
||||||
|
private:
|
||||||
|
using Location = std::pair<std::size_t, std::size_t>;
|
||||||
|
|
||||||
|
void onLine(const std::string& line, std::size_t jdx);
|
||||||
|
|
||||||
|
std::string checkForKet(const std::string& segment);
|
||||||
|
|
||||||
|
std::string checkForGate(const std::string& segment);
|
||||||
|
|
||||||
|
std::size_t getWireEnd(const std::string& segment);
|
||||||
|
|
||||||
|
void onGate(Location loc, const std::string value);
|
||||||
|
|
||||||
|
void onKet(Location loc, const std::string value);
|
||||||
|
|
||||||
|
void onLineEnd();
|
||||||
|
|
||||||
|
void onVertialQuantumWire(Location loc);
|
||||||
|
|
||||||
|
std::string mWorkingString;
|
||||||
|
QuantumCircuitElement* mWorkingElement{ nullptr };
|
||||||
|
QuantumCircuit* mWorkingCircuit{ nullptr };
|
||||||
|
};
|
|
@ -0,0 +1,112 @@
|
||||||
|
#include "QuantumGate.h"
|
||||||
|
|
||||||
|
NInMOutQuantumGate::NInMOutQuantumGate(std::size_t numIn, std::size_t numOut, std::vector<AbstractQuantumWire*> inputs, std::vector<AbstractQuantumWire*> outputs)
|
||||||
|
: QuantumGate(),
|
||||||
|
mNumIn(numIn),
|
||||||
|
mNumOut(numOut)
|
||||||
|
{
|
||||||
|
if (inputs.size() == mNumIn)
|
||||||
|
{
|
||||||
|
mInputs = inputs;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mInputs = std::vector<AbstractQuantumWire*>(numIn, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outputs.size() == mNumOut)
|
||||||
|
{
|
||||||
|
mOutputs = outputs;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mOutputs = std::vector<AbstractQuantumWire*>(numOut, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t NInMOutQuantumGate::getNumInputs() const
|
||||||
|
{
|
||||||
|
return mNumIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t NInMOutQuantumGate::getNumOutputs() const
|
||||||
|
{
|
||||||
|
return mNumOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractQuantumWire* NInMOutQuantumGate::getInput(std::size_t idx) const
|
||||||
|
{
|
||||||
|
if (idx < mNumIn)
|
||||||
|
{
|
||||||
|
return mInputs[idx];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractQuantumWire* NInMOutQuantumGate::getOutput(std::size_t idx) const
|
||||||
|
{
|
||||||
|
if (idx < mNumOut)
|
||||||
|
{
|
||||||
|
return mOutputs[idx];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NInMOutQuantumGate::setAtInput(std::size_t idx, AbstractQuantumWire* value)
|
||||||
|
{
|
||||||
|
if (idx < mInputs.size())
|
||||||
|
{
|
||||||
|
mInputs[idx] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NInMOutQuantumGate::setAtOutput(std::size_t idx, AbstractQuantumWire* value)
|
||||||
|
{
|
||||||
|
if (idx < mOutputs.size())
|
||||||
|
{
|
||||||
|
mOutputs[idx] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TwoInOneOutQuantumGate::TwoInOneOutQuantumGate(AbstractQuantumWire* input0, AbstractQuantumWire* input1, AbstractQuantumWire* output)
|
||||||
|
: NInMOutQuantumGate(2, 1, { input0, input1 }, { output })
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TwoInOneOutQuantumGate::setInput0(AbstractQuantumWire* input)
|
||||||
|
{
|
||||||
|
setAtInput(0, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TwoInOneOutQuantumGate::setInput1(AbstractQuantumWire* input)
|
||||||
|
{
|
||||||
|
setAtInput(1, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TwoInOneOutQuantumGate::setOutput(AbstractQuantumWire* output)
|
||||||
|
{
|
||||||
|
setAtOutput(0, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
OneInOneOutQuantumGate::OneInOneOutQuantumGate(AbstractQuantumWire* input, AbstractQuantumWire* output)
|
||||||
|
: NInMOutQuantumGate(1, 1, { input }, { output })
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void OneInOneOutQuantumGate::setInput(AbstractQuantumWire* input)
|
||||||
|
{
|
||||||
|
setAtInput(0, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OneInOneOutQuantumGate::setOutput(AbstractQuantumWire* output)
|
||||||
|
{
|
||||||
|
setAtOutput(0, output);
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "QuantumCircuitElement.h"
|
||||||
|
|
||||||
|
#include "QuantumWire.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class QuantumGate : public QuantumCircuitElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class GateType
|
||||||
|
{
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
Z,
|
||||||
|
H,
|
||||||
|
CNOT,
|
||||||
|
CUSTOM
|
||||||
|
};
|
||||||
|
virtual ~QuantumGate() = default;
|
||||||
|
|
||||||
|
virtual std::size_t getNumInputs() const = 0;
|
||||||
|
|
||||||
|
virtual std::size_t getNumOutputs() const = 0;
|
||||||
|
|
||||||
|
virtual AbstractQuantumWire* getInput(std::size_t idx) const = 0;
|
||||||
|
|
||||||
|
virtual AbstractQuantumWire* getOutput(std::size_t idx) const = 0;
|
||||||
|
|
||||||
|
virtual GateType getGateType() const = 0;
|
||||||
|
|
||||||
|
Type getType() const override
|
||||||
|
{
|
||||||
|
return Type::GATE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
using QuantumGatePtr = std::unique_ptr<QuantumGate>;
|
||||||
|
|
||||||
|
|
||||||
|
class NInMOutQuantumGate : public QuantumGate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NInMOutQuantumGate(std::size_t numIn, std::size_t numOut, std::vector<AbstractQuantumWire*> inputs = {}, std::vector<AbstractQuantumWire*> outputs = {});
|
||||||
|
|
||||||
|
virtual ~NInMOutQuantumGate() = default;
|
||||||
|
|
||||||
|
std::size_t getNumInputs() const override;
|
||||||
|
|
||||||
|
std::size_t getNumOutputs() const override;
|
||||||
|
|
||||||
|
AbstractQuantumWire* getInput(std::size_t idx) const override;
|
||||||
|
|
||||||
|
AbstractQuantumWire* getOutput(std::size_t idx) const override;
|
||||||
|
|
||||||
|
void setAtInput(std::size_t idx, AbstractQuantumWire* value);
|
||||||
|
|
||||||
|
void setAtOutput(std::size_t idx, AbstractQuantumWire* value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::size_t mNumIn{ 1 };
|
||||||
|
std::size_t mNumOut{ 1 };
|
||||||
|
|
||||||
|
std::vector<AbstractQuantumWire*> mInputs;
|
||||||
|
std::vector<AbstractQuantumWire*> mOutputs;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TwoInOneOutQuantumGate : public NInMOutQuantumGate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TwoInOneOutQuantumGate(AbstractQuantumWire* input0 = nullptr, AbstractQuantumWire* input1 = nullptr, AbstractQuantumWire* output = nullptr);
|
||||||
|
|
||||||
|
void setInput0(AbstractQuantumWire* input);
|
||||||
|
|
||||||
|
void setInput1(AbstractQuantumWire* input);
|
||||||
|
|
||||||
|
void setOutput(AbstractQuantumWire* output);
|
||||||
|
};
|
||||||
|
|
||||||
|
class OneInOneOutQuantumGate : public NInMOutQuantumGate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OneInOneOutQuantumGate(AbstractQuantumWire* input = nullptr, AbstractQuantumWire* output = nullptr);
|
||||||
|
|
||||||
|
void setInput(AbstractQuantumWire* input);
|
||||||
|
|
||||||
|
void setOutput(AbstractQuantumWire* output);
|
||||||
|
};
|
|
@ -0,0 +1,6 @@
|
||||||
|
#include "QuantumState.h"
|
||||||
|
|
||||||
|
const std::vector<Qubit>& QuantumState::getData() const
|
||||||
|
{
|
||||||
|
return mState;
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Qubit.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class QuantumState
|
||||||
|
{
|
||||||
|
const std::vector<Qubit>& getData() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<Qubit> mState;
|
||||||
|
};
|
33
plugins/quantum_computing/src/QuantumTerminal.cpp
Normal file
33
plugins/quantum_computing/src/QuantumTerminal.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include "QuantumTerminal.h"
|
||||||
|
|
||||||
|
QuantumTerminal::QuantumTerminal(TerminalType type, const std::string& label)
|
||||||
|
: mLabel(label),
|
||||||
|
mType(type)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QuantumTerminal::Type QuantumTerminal::getType() const
|
||||||
|
{
|
||||||
|
return mType == TerminalType::INPUT ? Type::INPUT_TERMINAL : Type::OUTPUT_TERMINAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Qubit& QuantumTerminal::getValue() const
|
||||||
|
{
|
||||||
|
return mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QuantumWire* QuantumTerminal::getConnection() const
|
||||||
|
{
|
||||||
|
return mConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuantumTerminal::setConnection(QuantumWire* connection)
|
||||||
|
{
|
||||||
|
mConnection = connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuantumTerminal::setValue(const Qubit& value)
|
||||||
|
{
|
||||||
|
mValue = value;
|
||||||
|
}
|
38
plugins/quantum_computing/src/QuantumTerminal.h
Normal file
38
plugins/quantum_computing/src/QuantumTerminal.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "QuantumCircuitElement.h"
|
||||||
|
#include "Qubit.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class QuantumWire;
|
||||||
|
|
||||||
|
class QuantumTerminal : public QuantumCircuitElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class TerminalType
|
||||||
|
{
|
||||||
|
INPUT,
|
||||||
|
OUTPUT
|
||||||
|
};
|
||||||
|
|
||||||
|
QuantumTerminal(TerminalType type, const std::string& label = {});
|
||||||
|
|
||||||
|
QuantumWire* getConnection() const;
|
||||||
|
|
||||||
|
Type getType() const override;
|
||||||
|
|
||||||
|
const Qubit& getValue() const;
|
||||||
|
|
||||||
|
void setConnection(QuantumWire* connection);
|
||||||
|
|
||||||
|
void setValue(const Qubit& value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mLabel;
|
||||||
|
TerminalType mType;
|
||||||
|
Qubit mValue;
|
||||||
|
QuantumWire* mConnection{ nullptr };
|
||||||
|
};
|
||||||
|
using QuantumTerminalPtr = std::unique_ptr<QuantumTerminal>;
|
28
plugins/quantum_computing/src/QuantumWire.cpp
Normal file
28
plugins/quantum_computing/src/QuantumWire.cpp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#include "QuantumWire.h"
|
||||||
|
|
||||||
|
QuantumWire::QuantumWire(QuantumCircuitElement* input, QuantumCircuitElement* output)
|
||||||
|
: mInput(input),
|
||||||
|
mOutput(output)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QuantumCircuitElement* QuantumWire::getInput() const
|
||||||
|
{
|
||||||
|
return mInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
QuantumCircuitElement* QuantumWire::getOutput() const
|
||||||
|
{
|
||||||
|
return mOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
QuantumWire::Type QuantumWire::getType() const
|
||||||
|
{
|
||||||
|
return Type::WIRE;
|
||||||
|
}
|
||||||
|
|
||||||
|
QuantumWire::WireType QuantumWire::getWireType() const
|
||||||
|
{
|
||||||
|
return WireType::QUANTUM;
|
||||||
|
}
|
42
plugins/quantum_computing/src/QuantumWire.h
Normal file
42
plugins/quantum_computing/src/QuantumWire.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "QuantumCircuitElement.h"
|
||||||
|
|
||||||
|
class AbstractQuantumWire : public QuantumCircuitElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class WireType
|
||||||
|
{
|
||||||
|
QUANTUM,
|
||||||
|
CLASSICAL
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~AbstractQuantumWire() = default;
|
||||||
|
|
||||||
|
virtual WireType getWireType() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class QuantumWire : public AbstractQuantumWire
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QuantumWire(QuantumCircuitElement* input, QuantumCircuitElement* output);
|
||||||
|
|
||||||
|
QuantumCircuitElement* getInput() const;
|
||||||
|
QuantumCircuitElement* getOutput() const;
|
||||||
|
|
||||||
|
Type getType() const override;
|
||||||
|
WireType getWireType() const override;
|
||||||
|
private:
|
||||||
|
QuantumCircuitElement* mInput{ nullptr };
|
||||||
|
QuantumCircuitElement* mOutput{ nullptr };
|
||||||
|
};
|
||||||
|
using QuantumWirePtr = std::unique_ptr<QuantumWire>;
|
||||||
|
|
||||||
|
class ClassicalWire : public AbstractQuantumWire
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WireType getWireType() const override
|
||||||
|
{
|
||||||
|
return WireType::CLASSICAL;
|
||||||
|
}
|
||||||
|
};
|
|
@ -15,4 +15,14 @@ const ComplexNumber& Qubit::getAlpha() const
|
||||||
const ComplexNumber& Qubit::getBeta() const
|
const ComplexNumber& Qubit::getBeta() const
|
||||||
{
|
{
|
||||||
return mBeta;
|
return mBeta;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Qubit::isIn0State() const
|
||||||
|
{
|
||||||
|
return mAlpha.getReal() == 1.0 && mBeta.getMagnitude() == 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Qubit::isIn1State() const
|
||||||
|
{
|
||||||
|
return mBeta.getReal() == 1.0 && mAlpha.getMagnitude() == 0.0;
|
||||||
}
|
}
|
|
@ -5,11 +5,15 @@
|
||||||
class Qubit
|
class Qubit
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Qubit(const ComplexNumber& alpha, const ComplexNumber& beta);
|
Qubit(const ComplexNumber& alpha = {1.0, 0.0}, const ComplexNumber& beta = { 0.0, 0.0 });
|
||||||
|
|
||||||
const ComplexNumber& getAlpha() const;
|
const ComplexNumber& getAlpha() const;
|
||||||
|
|
||||||
const ComplexNumber& getBeta() const;
|
const ComplexNumber& getBeta() const;
|
||||||
|
|
||||||
|
bool isIn0State() const;
|
||||||
|
|
||||||
|
bool isIn1State() const;
|
||||||
private:
|
private:
|
||||||
ComplexNumber mAlpha;
|
ComplexNumber mAlpha;
|
||||||
ComplexNumber mBeta;
|
ComplexNumber mBeta;
|
||||||
|
|
44
plugins/quantum_computing/src/visuals/QuantumCircuitNode.cpp
Normal file
44
plugins/quantum_computing/src/visuals/QuantumCircuitNode.cpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#include "QuantumCircuitNode.h"
|
||||||
|
|
||||||
|
#include "QuantumCircuit.h"
|
||||||
|
#include "QuantumTerminalNode.h"
|
||||||
|
|
||||||
|
QuantumCircuitNode::QuantumCircuitNode(const Transform& t)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuantumCircuitNode::setContent(QuantumCircuit* circuit)
|
||||||
|
{
|
||||||
|
mContent = circuit;
|
||||||
|
mContentDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuantumCircuitNode::update(SceneInfo* sceneInfo)
|
||||||
|
{
|
||||||
|
if (mContentDirty)
|
||||||
|
{
|
||||||
|
createOrUpdateGeometry(sceneInfo);
|
||||||
|
mContentDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuantumCircuitNode::createOrUpdateGeometry(SceneInfo*)
|
||||||
|
{
|
||||||
|
double terminal_vertical_spacing = 100;
|
||||||
|
double terminal_left_margin = 10;
|
||||||
|
|
||||||
|
double terminal_y = 10;
|
||||||
|
for (auto terminal : mContent->getInputTerminals())
|
||||||
|
{
|
||||||
|
Point loc{ terminal_left_margin, terminal_y };
|
||||||
|
auto terminal_node = std::make_unique<QuantumTerminalNode>(Transform(loc));
|
||||||
|
|
||||||
|
terminal_node->setContent(terminal);
|
||||||
|
|
||||||
|
addChild(terminal_node.get());
|
||||||
|
|
||||||
|
mInputTerminalNodes.push_back(std::move(terminal_node));
|
||||||
|
terminal_y += terminal_vertical_spacing;
|
||||||
|
}
|
||||||
|
}
|
23
plugins/quantum_computing/src/visuals/QuantumCircuitNode.h
Normal file
23
plugins/quantum_computing/src/visuals/QuantumCircuitNode.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AbstractVisualNode.h"
|
||||||
|
|
||||||
|
class QuantumCircuit;
|
||||||
|
class QuantumTerminalNode;
|
||||||
|
|
||||||
|
class QuantumCircuitNode : public AbstractVisualNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QuantumCircuitNode(const Transform& t = {});
|
||||||
|
|
||||||
|
void setContent(QuantumCircuit* circuit);
|
||||||
|
|
||||||
|
void update(SceneInfo* sceneInfo);
|
||||||
|
private:
|
||||||
|
void createOrUpdateGeometry(SceneInfo* sceneInfo);
|
||||||
|
|
||||||
|
bool mContentDirty{ true };
|
||||||
|
QuantumCircuit* mContent{ nullptr };
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<QuantumTerminalNode> > mInputTerminalNodes;
|
||||||
|
};
|
0
plugins/quantum_computing/src/visuals/QuantumGateNode.h
Normal file
0
plugins/quantum_computing/src/visuals/QuantumGateNode.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#include "QuantumTerminalNode.h"
|
||||||
|
|
||||||
|
#include "QuantumTerminal.h"
|
||||||
|
#include "EquationNode.h"
|
||||||
|
#include "LatexMathExpression.h"
|
||||||
|
|
||||||
|
QuantumTerminalNode::QuantumTerminalNode(const Transform& transform)
|
||||||
|
: AbstractVisualNode(transform)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuantumTerminalNode::setContent(QuantumTerminal* terminal)
|
||||||
|
{
|
||||||
|
mContent = terminal;
|
||||||
|
mContentDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuantumTerminalNode::update(SceneInfo* sceneInfo)
|
||||||
|
{
|
||||||
|
if (mContentDirty)
|
||||||
|
{
|
||||||
|
createOrUpdateGeometry(sceneInfo);
|
||||||
|
mContentDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuantumTerminalNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
|
||||||
|
{
|
||||||
|
if (!mLabel)
|
||||||
|
{
|
||||||
|
const auto value = mContent->getValue();
|
||||||
|
std::string label;
|
||||||
|
if (value.isIn0State())
|
||||||
|
{
|
||||||
|
label = "\\ket{0}";
|
||||||
|
}
|
||||||
|
else if(value.isIn1State())
|
||||||
|
{
|
||||||
|
label = "\\ket{1}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
label = "\\Psi";
|
||||||
|
}
|
||||||
|
|
||||||
|
mLabelExpression = std::make_unique<LatexMathExpression>(label);
|
||||||
|
mLabel = std::make_unique<EquationNode>();
|
||||||
|
mLabel->setContent(mLabelExpression.get());
|
||||||
|
|
||||||
|
addChild(mLabel.get());
|
||||||
|
}
|
||||||
|
}
|
25
plugins/quantum_computing/src/visuals/QuantumTerminalNode.h
Normal file
25
plugins/quantum_computing/src/visuals/QuantumTerminalNode.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AbstractVisualNode.h"
|
||||||
|
|
||||||
|
class QuantumTerminal;
|
||||||
|
class EquationNode;
|
||||||
|
class LatexMathExpression;
|
||||||
|
|
||||||
|
class QuantumTerminalNode : public AbstractVisualNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QuantumTerminalNode(const Transform& transform);
|
||||||
|
|
||||||
|
void setContent(QuantumTerminal* terminal);
|
||||||
|
|
||||||
|
void update(SceneInfo* sceneInfo);
|
||||||
|
private:
|
||||||
|
void createOrUpdateGeometry(SceneInfo* sceneInfo);
|
||||||
|
|
||||||
|
QuantumTerminal* mContent{ nullptr };
|
||||||
|
bool mContentDirty{ true };
|
||||||
|
|
||||||
|
std::unique_ptr<LatexMathExpression> mLabelExpression;
|
||||||
|
std::unique_ptr<EquationNode> mLabel;
|
||||||
|
};
|
0
plugins/quantum_computing/src/visuals/QuantumWireNode.h
Normal file
0
plugins/quantum_computing/src/visuals/QuantumWireNode.h
Normal file
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
list(APPEND UNIT_TEST_FILES
|
list(APPEND UNIT_TEST_FILES
|
||||||
TestBlochSphereNode.cpp
|
TestBlochSphereNode.cpp
|
||||||
|
TestQuantumCircuitParsing.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(quantum_computing_unit_tests ${CMAKE_SOURCE_DIR}/test/test_runner.cpp ${UNIT_TEST_FILES})
|
add_executable(quantum_computing_unit_tests ${CMAKE_SOURCE_DIR}/test/test_runner.cpp ${UNIT_TEST_FILES})
|
||||||
|
|
24
plugins/quantum_computing/test/TestQuantumCircuitParsing.cpp
Normal file
24
plugins/quantum_computing/test/TestQuantumCircuitParsing.cpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#include "TestFramework.h"
|
||||||
|
#include "TestUtils.h"
|
||||||
|
#include "TestRenderUtils.h"
|
||||||
|
|
||||||
|
#include "QuantumCircuitReader.h"
|
||||||
|
#include "QuantumCircuitNode.h"
|
||||||
|
#include "QuantumCircuit.h"
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE(TestQuantumCircuitParsing, "quantum_computing")
|
||||||
|
{
|
||||||
|
QuantumCircuitReader reader;
|
||||||
|
|
||||||
|
auto circuit = reader.read(TestUtils::getTestDataDir() / "quantum_circuit.dat");
|
||||||
|
|
||||||
|
TestRenderer renderer(100, 100);
|
||||||
|
|
||||||
|
auto node = std::make_unique<QuantumCircuitNode>(Point(10, 10));
|
||||||
|
|
||||||
|
node->setContent(circuit.get());
|
||||||
|
|
||||||
|
renderer.getScene()->addNode(node.get());
|
||||||
|
renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "circuit.svg");
|
||||||
|
}
|
|
@ -21,6 +21,26 @@ LatexMathExpression::~LatexMathExpression()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const LatexMathSymbol& LatexMathExpression::getLeftSymbol() const
|
||||||
|
{
|
||||||
|
return mLeftSymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LatexMathSymbol& LatexMathExpression::getRightSymbol() const
|
||||||
|
{
|
||||||
|
return mRightSymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LatexMathExpression::setLeftSymbol(const LatexMathSymbol& symbol)
|
||||||
|
{
|
||||||
|
mLeftSymbol = symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LatexMathExpression::setRightSymbol(const LatexMathSymbol& symbol)
|
||||||
|
{
|
||||||
|
mRightSymbol = symbol;
|
||||||
|
}
|
||||||
|
|
||||||
void LatexMathExpression::onTagBodyChar(char c)
|
void LatexMathExpression::onTagBodyChar(char c)
|
||||||
{
|
{
|
||||||
if (c == '}')
|
if (c == '}')
|
||||||
|
@ -175,13 +195,13 @@ void LatexMathExpression::onFinishedTagName()
|
||||||
|
|
||||||
if (*lookup == LatexMathSymbol::Tag::FRAC)
|
if (*lookup == LatexMathSymbol::Tag::FRAC)
|
||||||
{
|
{
|
||||||
mWorkingType = Type::FRACTION;
|
onFracTag();
|
||||||
auto expression = std::make_unique<LatexMathExpression>(mWorkingType);
|
|
||||||
mWorkingExpression = expression.get();
|
|
||||||
mExpressions.push_back(std::move(expression));
|
|
||||||
mWorkingString.clear();
|
mWorkingString.clear();
|
||||||
}
|
}
|
||||||
|
else if (auto tag_type = LatexSymbolLookup::getTagType(*lookup); tag_type == LatexMathSymbol::Type::ENCLOSING_TAG)
|
||||||
|
{
|
||||||
|
onEnclosingTag(*lookup);
|
||||||
|
}
|
||||||
mLineState = LineState::IN_TAG_BODY;
|
mLineState = LineState::IN_TAG_BODY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,12 +213,39 @@ void LatexMathExpression::onFinishedTagName()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LatexMathExpression::onFracTag()
|
||||||
|
{
|
||||||
|
mWorkingType = Type::FRACTION;
|
||||||
|
auto expression = std::make_unique<LatexMathExpression>(mWorkingType);
|
||||||
|
mWorkingExpression = expression.get();
|
||||||
|
mExpressions.push_back(std::move(expression));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LatexMathExpression::onEnclosingTag(LatexMathSymbol::Tag tag)
|
||||||
|
{
|
||||||
|
mWorkingType = Type::ENCLOSING;
|
||||||
|
auto expression = std::make_unique<LatexMathExpression>(mWorkingType);
|
||||||
|
|
||||||
|
auto left_symbol_value = LatexSymbolLookup::getLeftSymbolUtf8(tag);
|
||||||
|
auto right_symbol_value = LatexSymbolLookup::getRightSymbolUtf8(tag);
|
||||||
|
|
||||||
|
MLOG_INFO("Adding enclosing tag");
|
||||||
|
|
||||||
|
expression->setLeftSymbol({ LatexMathSymbol::Type::ENCLOSING_TAG, "left", *left_symbol_value });
|
||||||
|
expression->setRightSymbol({ LatexMathSymbol::Type::ENCLOSING_TAG, "right", *right_symbol_value });
|
||||||
|
|
||||||
|
mWorkingExpression = expression.get();
|
||||||
|
mExpressions.push_back(std::move(expression));
|
||||||
|
}
|
||||||
|
|
||||||
void LatexMathExpression::onCloseExpression()
|
void LatexMathExpression::onCloseExpression()
|
||||||
{
|
{
|
||||||
if (mWorkingType == Type::LEAF)
|
if (mWorkingType == Type::LEAF)
|
||||||
{
|
{
|
||||||
|
MLOG_INFO("onCloseExpression LEAF");
|
||||||
if (!mWorkingSymbols.empty())
|
if (!mWorkingSymbols.empty())
|
||||||
{
|
{
|
||||||
|
MLOG_INFO("Has working symbols");
|
||||||
auto expression = std::make_unique<LatexMathExpression>(mWorkingType);
|
auto expression = std::make_unique<LatexMathExpression>(mWorkingType);
|
||||||
expression->setContent(mWorkingSymbols);
|
expression->setContent(mWorkingSymbols);
|
||||||
mExpressions.push_back(std::move(expression));
|
mExpressions.push_back(std::move(expression));
|
||||||
|
@ -206,6 +253,7 @@ void LatexMathExpression::onCloseExpression()
|
||||||
}
|
}
|
||||||
else if (mWorkingType == Type::FRACTION)
|
else if (mWorkingType == Type::FRACTION)
|
||||||
{
|
{
|
||||||
|
MLOG_INFO("onCloseExpression FRACTION");
|
||||||
mWorkingExpression->setRawContent(mWorkingString);
|
mWorkingExpression->setRawContent(mWorkingString);
|
||||||
|
|
||||||
if (mWorkingExpression->getExpressions().size() == 2)
|
if (mWorkingExpression->getExpressions().size() == 2)
|
||||||
|
@ -219,6 +267,20 @@ void LatexMathExpression::onCloseExpression()
|
||||||
mOpenBraceCount = 0;
|
mOpenBraceCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (mWorkingType == Type::ENCLOSING)
|
||||||
|
{
|
||||||
|
MLOG_INFO("onCloseExpression ENCLOSING");
|
||||||
|
if (!mWorkingString.empty())
|
||||||
|
{
|
||||||
|
mWorkingExpression->setRawContent(mWorkingString);
|
||||||
|
|
||||||
|
if (mWorkingExpression->getExpressions().size() == 1)
|
||||||
|
{
|
||||||
|
mWorkingType = Type::LEAF;
|
||||||
|
mLineState = LineState::NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mWorkingString.clear();
|
mWorkingString.clear();
|
||||||
mWorkingSymbols.clear();
|
mWorkingSymbols.clear();
|
||||||
|
|
|
@ -17,6 +17,7 @@ public:
|
||||||
LINEAR,
|
LINEAR,
|
||||||
LEAF,
|
LEAF,
|
||||||
FRACTION,
|
FRACTION,
|
||||||
|
ENCLOSING,
|
||||||
SUBSCRIPT,
|
SUBSCRIPT,
|
||||||
SUPERSCRIPT
|
SUPERSCRIPT
|
||||||
};
|
};
|
||||||
|
@ -39,8 +40,16 @@ public:
|
||||||
|
|
||||||
const std::vector<LatexMathExpressionPtr>& getExpressions() const;
|
const std::vector<LatexMathExpressionPtr>& getExpressions() const;
|
||||||
|
|
||||||
|
const LatexMathSymbol& getLeftSymbol() const;
|
||||||
|
|
||||||
|
const LatexMathSymbol& getRightSymbol() const;
|
||||||
|
|
||||||
const Type getType() const;
|
const Type getType() const;
|
||||||
|
|
||||||
|
void setLeftSymbol(const LatexMathSymbol& symbol);
|
||||||
|
|
||||||
|
void setRightSymbol(const LatexMathSymbol& symbol);
|
||||||
|
|
||||||
void setContent(std::vector<LatexMathSymbol>& symbols);
|
void setContent(std::vector<LatexMathSymbol>& symbols);
|
||||||
|
|
||||||
void setRawContent(const std::string& content);
|
void setRawContent(const std::string& content);
|
||||||
|
@ -67,6 +76,10 @@ public:
|
||||||
|
|
||||||
void onCloseExpression();
|
void onCloseExpression();
|
||||||
|
|
||||||
|
void onFracTag();
|
||||||
|
|
||||||
|
void onEnclosingTag(LatexMathSymbol::Tag tag);
|
||||||
|
|
||||||
void parse();
|
void parse();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -81,6 +94,9 @@ private:
|
||||||
Type mType{ Type::LEAF };
|
Type mType{ Type::LEAF };
|
||||||
std::vector<LatexMathSymbol> mWorkingSymbols;
|
std::vector<LatexMathSymbol> mWorkingSymbols;
|
||||||
|
|
||||||
|
LatexMathSymbol mLeftSymbol;
|
||||||
|
LatexMathSymbol mRightSymbol;
|
||||||
|
|
||||||
std::vector<LatexMathSymbol> mSymbols;
|
std::vector<LatexMathSymbol> mSymbols;
|
||||||
std::vector<LatexMathExpressionPtr> mExpressions;
|
std::vector<LatexMathExpressionPtr> mExpressions;
|
||||||
};
|
};
|
|
@ -7,14 +7,51 @@ std::unordered_map<std::string, std::wstring> LatexSymbolLookup::mSymbols = {
|
||||||
{"alpha", L"\u03B1"},
|
{"alpha", L"\u03B1"},
|
||||||
{"beta", L"\u03B2"},
|
{"beta", L"\u03B2"},
|
||||||
{"gamma", L"\u03B3"},
|
{"gamma", L"\u03B3"},
|
||||||
{"psi", L"\u03C8"}
|
{"psi", L"\u03C8"},
|
||||||
|
{"langle", L"\u27E8"},
|
||||||
|
{"rangle", L"\u27E9"},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::unordered_map<LatexMathSymbol::Tag, std::wstring> LatexSymbolLookup::mLeftSymbols = {
|
||||||
|
{LatexMathSymbol::Tag::BRA, L"\u27E8"},
|
||||||
|
{LatexMathSymbol::Tag::KET, L"\u007C"}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<LatexMathSymbol::Tag, std::wstring> LatexSymbolLookup::mRightSymbols = {
|
||||||
|
{LatexMathSymbol::Tag::BRA, L"\u007C"},
|
||||||
|
{LatexMathSymbol::Tag::KET, L"\u27E9"}
|
||||||
|
};
|
||||||
|
|
||||||
std::unordered_map<std::string, LatexMathSymbol::Tag> LatexSymbolLookup::mTags = {
|
std::unordered_map<std::string, LatexMathSymbol::Tag> LatexSymbolLookup::mTags = {
|
||||||
{"frac", LatexMathSymbol::Tag::FRAC},
|
{"frac", LatexMathSymbol::Tag::FRAC},
|
||||||
|
{"bra", LatexMathSymbol::Tag::BRA},
|
||||||
|
{"ket", LatexMathSymbol::Tag::KET},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::optional<std::string> LatexSymbolLookup::getLeftSymbolUtf8(LatexMathSymbol::Tag tag)
|
||||||
|
{
|
||||||
|
if (auto entry = getLeftSymbolUtf16(tag); entry)
|
||||||
|
{
|
||||||
|
return UnicodeUtils::utf16ToUtf8String(*entry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> LatexSymbolLookup::getRightSymbolUtf8(LatexMathSymbol::Tag tag)
|
||||||
|
{
|
||||||
|
if (auto entry = getRightSymbolUtf16(tag); entry)
|
||||||
|
{
|
||||||
|
return UnicodeUtils::utf16ToUtf8String(*entry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<std::string> LatexSymbolLookup::getSymbolUtf8(const std::string& tag)
|
std::optional<std::string> LatexSymbolLookup::getSymbolUtf8(const std::string& tag)
|
||||||
{
|
{
|
||||||
if (auto entry = getSymbolUtf16(tag); entry)
|
if (auto entry = getSymbolUtf16(tag); entry)
|
||||||
|
@ -27,6 +64,31 @@ std::optional<std::string> LatexSymbolLookup::getSymbolUtf8(const std::string& t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::wstring> LatexSymbolLookup::getLeftSymbolUtf16(LatexMathSymbol::Tag tag)
|
||||||
|
{
|
||||||
|
if (auto iter = mLeftSymbols.find(tag); iter != mLeftSymbols.end())
|
||||||
|
{
|
||||||
|
return iter->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::wstring> LatexSymbolLookup::getRightSymbolUtf16(LatexMathSymbol::Tag tag)
|
||||||
|
{
|
||||||
|
if (auto iter = mRightSymbols.find(tag); iter != mRightSymbols.end())
|
||||||
|
{
|
||||||
|
return iter->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<std::wstring> LatexSymbolLookup::getSymbolUtf16(const std::string& tag)
|
std::optional<std::wstring> LatexSymbolLookup::getSymbolUtf16(const std::string& tag)
|
||||||
{
|
{
|
||||||
if (auto iter = mSymbols.find(tag); iter != mSymbols.end())
|
if (auto iter = mSymbols.find(tag); iter != mSymbols.end())
|
||||||
|
|
|
@ -19,10 +19,12 @@ struct LatexMathSymbol
|
||||||
enum class Tag
|
enum class Tag
|
||||||
{
|
{
|
||||||
NONE,
|
NONE,
|
||||||
FRAC
|
FRAC,
|
||||||
|
BRA,
|
||||||
|
KET
|
||||||
};
|
};
|
||||||
|
|
||||||
LatexMathSymbol(Type type, const std::string& name, const std::string& unicode)
|
LatexMathSymbol(Type type = Type::RAW, const std::string& name = {}, const std::string& unicode = {})
|
||||||
: mType(type),
|
: mType(type),
|
||||||
mName(name),
|
mName(name),
|
||||||
mUnicode(unicode)
|
mUnicode(unicode)
|
||||||
|
@ -38,8 +40,16 @@ struct LatexMathSymbol
|
||||||
class LatexSymbolLookup
|
class LatexSymbolLookup
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static std::optional<std::string> getLeftSymbolUtf8(LatexMathSymbol::Tag tag);
|
||||||
|
|
||||||
|
static std::optional<std::string> getRightSymbolUtf8(LatexMathSymbol::Tag tag);
|
||||||
|
|
||||||
static std::optional<std::string> getSymbolUtf8(const std::string& tag);
|
static std::optional<std::string> getSymbolUtf8(const std::string& tag);
|
||||||
|
|
||||||
|
static std::optional<std::wstring> getLeftSymbolUtf16(LatexMathSymbol::Tag tag);
|
||||||
|
|
||||||
|
static std::optional<std::wstring> getRightSymbolUtf16(LatexMathSymbol::Tag tag);
|
||||||
|
|
||||||
static std::optional<std::wstring> getSymbolUtf16(const std::string& tag);
|
static std::optional<std::wstring> getSymbolUtf16(const std::string& tag);
|
||||||
|
|
||||||
static std::optional<LatexMathSymbol::Tag> getKnownTag(const std::string& tag);
|
static std::optional<LatexMathSymbol::Tag> getKnownTag(const std::string& tag);
|
||||||
|
@ -50,12 +60,32 @@ public:
|
||||||
{
|
{
|
||||||
case LatexMathSymbol::Tag::FRAC:
|
case LatexMathSymbol::Tag::FRAC:
|
||||||
return 2;
|
return 2;
|
||||||
|
case LatexMathSymbol::Tag::BRA:
|
||||||
|
case LatexMathSymbol::Tag::KET:
|
||||||
|
return 1;
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LatexMathSymbol::Type getTagType(LatexMathSymbol::Tag tag)
|
||||||
|
{
|
||||||
|
switch (tag)
|
||||||
|
{
|
||||||
|
case LatexMathSymbol::Tag::FRAC:
|
||||||
|
return LatexMathSymbol::Type::TAG;
|
||||||
|
case LatexMathSymbol::Tag::BRA:
|
||||||
|
case LatexMathSymbol::Tag::KET:
|
||||||
|
return LatexMathSymbol::Type::ENCLOSING_TAG;
|
||||||
|
default:
|
||||||
|
return LatexMathSymbol::Type::TAG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static std::unordered_map<LatexMathSymbol::Tag, std::wstring> mLeftSymbols;
|
||||||
|
static std::unordered_map<LatexMathSymbol::Tag, std::wstring> mRightSymbols;
|
||||||
|
|
||||||
static std::unordered_map<std::string, std::wstring> mSymbols;
|
static std::unordered_map<std::string, std::wstring> mSymbols;
|
||||||
|
|
||||||
static std::unordered_map<std::string, LatexMathSymbol::Tag> mTags;
|
static std::unordered_map<std::string, LatexMathSymbol::Tag> mTags;
|
||||||
|
|
|
@ -85,6 +85,33 @@ void EquationNode::addExpression(SceneInfo* sceneInfo, const LatexMathExpression
|
||||||
mTextCursor.move(0.0, -9.0);
|
mTextCursor.move(0.0, -9.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (expression->getType() == LatexMathExpression::Type::ENCLOSING)
|
||||||
|
{
|
||||||
|
MLOG_INFO("Processing enclosing expr");
|
||||||
|
if (expression->getExpressions().size() == 1)
|
||||||
|
{
|
||||||
|
auto left_content = expression->getLeftSymbol().mUnicode;
|
||||||
|
|
||||||
|
auto left_node = std::make_unique<TextNode>(left_content, Transform(mTextCursor));
|
||||||
|
left_node->setFont(mDefaultFont);
|
||||||
|
addChild(left_node.get());
|
||||||
|
|
||||||
|
mTextCursor.move(left_node->getContentWidth(sceneInfo), 0.0);
|
||||||
|
mText.push_back(std::move(left_node));
|
||||||
|
|
||||||
|
addExpression(sceneInfo, expression->getExpressions()[0].get());
|
||||||
|
|
||||||
|
auto right_content = expression->getRightSymbol().mUnicode;
|
||||||
|
|
||||||
|
auto right_node = std::make_unique<TextNode>(right_content, Transform(mTextCursor));
|
||||||
|
right_node->setFont(mDefaultFont);
|
||||||
|
addChild(right_node.get());
|
||||||
|
|
||||||
|
mTextCursor.move(right_node->getContentWidth(sceneInfo), 0.0);
|
||||||
|
|
||||||
|
mText.push_back(std::move(right_node));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EquationNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
|
void EquationNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
|
||||||
|
|
2
test/data/quantum_circuit.dat
Normal file
2
test/data/quantum_circuit.dat
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
|0>---X---
|
||||||
|
|1>---Z---
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
TEST_CASE(TestLatexConverter, "publishing")
|
TEST_CASE(TestLatexConverter, "publishing")
|
||||||
{
|
{
|
||||||
auto expression = std::make_unique<LatexMathExpression>("\\psi = \\frac{\\alpha + \\beta}{c + d} + e");
|
auto expression = std::make_unique<LatexMathExpression>("\\psi = \\frac{\\alpha + \\beta}{c + d} + \\ket{e}");
|
||||||
|
|
||||||
auto equation_node = std::make_unique<EquationNode>(Point(10, 10));
|
auto equation_node = std::make_unique<EquationNode>(Point(10, 10));
|
||||||
equation_node->setContent(expression.get());
|
equation_node->setContent(expression.get());
|
||||||
|
|
Loading…
Reference in a new issue