diff --git a/plugins/math/ComplexNumber.cpp b/plugins/math/ComplexNumber.cpp index 98c60ab..f4889b2 100644 --- a/plugins/math/ComplexNumber.cpp +++ b/plugins/math/ComplexNumber.cpp @@ -1,5 +1,7 @@ #include "ComplexNumber.h" +#include + ComplexNumber::ComplexNumber(double real, double imaginary) : mReal(real), mImaginary(imaginary) @@ -25,4 +27,9 @@ void ComplexNumber::setReal(double value) void ComplexNumber::setImaginary(double value) { mImaginary = value; +} + +double ComplexNumber::getMagnitude() const +{ + return std::sqrt(mReal * mReal + mImaginary * mImaginary); } \ No newline at end of file diff --git a/plugins/math/ComplexNumber.h b/plugins/math/ComplexNumber.h index 9b0ee5b..ee83a5b 100644 --- a/plugins/math/ComplexNumber.h +++ b/plugins/math/ComplexNumber.h @@ -9,6 +9,8 @@ public: double getImaginary() const; + double getMagnitude() const; + void setReal(double value); void setImaginary(double value); diff --git a/plugins/quantum_computing/src/BasicQuantumGates.cpp b/plugins/quantum_computing/src/BasicQuantumGates.cpp new file mode 100644 index 0000000..e69de29 diff --git a/plugins/quantum_computing/src/BasicQuantumGates.h b/plugins/quantum_computing/src/BasicQuantumGates.h new file mode 100644 index 0000000..1c9f1b0 --- /dev/null +++ b/plugins/quantum_computing/src/BasicQuantumGates.h @@ -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; + } +}; \ No newline at end of file diff --git a/plugins/quantum_computing/src/CMakeLists.txt b/plugins/quantum_computing/src/CMakeLists.txt index 99014bd..535a722 100644 --- a/plugins/quantum_computing/src/CMakeLists.txt +++ b/plugins/quantum_computing/src/CMakeLists.txt @@ -1,31 +1,50 @@ set(PLUGIN_NAME quantum_computing) -list(APPEND quantum_computing_HEADERS +list(APPEND HEADERS QuantumCircuit.h BlochSphere.h QuantumState.h Qubit.h QuantumGate.h QuantumOperator.h + QuantumCircuitReader.h + QuantumCircuitElement.h + QuantumWire.h + QuantumTerminal.h + BasicQuantumGates.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 BlochSphere.cpp QuantumState.cpp Qubit.cpp QuantumGate.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 ) -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 ${CMAKE_CURRENT_SOURCE_DIR} ${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_target_properties( ${PLUGIN_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON ) \ No newline at end of file diff --git a/plugins/quantum_computing/src/QuantumCircuit.cpp b/plugins/quantum_computing/src/QuantumCircuit.cpp index e69de29..7edbbd2 100644 --- a/plugins/quantum_computing/src/QuantumCircuit.cpp +++ b/plugins/quantum_computing/src/QuantumCircuit.cpp @@ -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& QuantumCircuit::getInputTerminals() const +{ + return mInputTerminals; +} + +const std::vector& QuantumCircuit::getOutputTerminals() const +{ + return mOutputTerminals; +} + +const std::vector& QuantumCircuit::getLogicGates() const +{ + return mGates; +} + +const std::vector& QuantumCircuit::getQuantumWires() const +{ + return mWires; +} \ No newline at end of file diff --git a/plugins/quantum_computing/src/QuantumCircuit.h b/plugins/quantum_computing/src/QuantumCircuit.h index e69de29..f707f98 100644 --- a/plugins/quantum_computing/src/QuantumCircuit.h +++ b/plugins/quantum_computing/src/QuantumCircuit.h @@ -0,0 +1,37 @@ +#pragma once + +#include "QuantumCircuitElement.h" +#include "QuantumGate.h" +#include "QuantumTerminal.h" +#include "QuantumWire.h" + +#include + +class QuantumCircuit +{ +public: + void addInputTerminal(QuantumTerminalPtr terminal); + + void addOutputTerminal(QuantumTerminalPtr terminal); + + void addQuantumWire(QuantumWirePtr wire); + + void addLogicGate(QuantumGatePtr gate); + + const std::vector& getInputTerminals() const; + + const std::vector& getOutputTerminals() const; + + const std::vector& getLogicGates() const; + + const std::vector& getQuantumWires() const; + +private: + std::vector mInputTerminals; + std::vector mOutputTerminals; + + std::vector mWires; + std::vector mGates; + + std::vector > mElements; +}; \ No newline at end of file diff --git a/plugins/quantum_computing/src/QuantumCircuitElement.cpp b/plugins/quantum_computing/src/QuantumCircuitElement.cpp new file mode 100644 index 0000000..e69de29 diff --git a/plugins/quantum_computing/src/QuantumCircuitElement.h b/plugins/quantum_computing/src/QuantumCircuitElement.h new file mode 100644 index 0000000..41a08b5 --- /dev/null +++ b/plugins/quantum_computing/src/QuantumCircuitElement.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +class QuantumCircuitElement +{ +public: + enum class Type + { + INPUT_TERMINAL, + OUTPUT_TERMINAL, + WIRE, + GATE, + UNKNOWN + }; + + virtual ~QuantumCircuitElement() = default; + + virtual QuantumCircuitElement::Type getType() const = 0; +}; \ No newline at end of file diff --git a/plugins/quantum_computing/src/QuantumCircuitReader.cpp b/plugins/quantum_computing/src/QuantumCircuitReader.cpp new file mode 100644 index 0000000..df843d6 --- /dev/null +++ b/plugins/quantum_computing/src/QuantumCircuitReader.cpp @@ -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 QuantumCircuitReader::read(const Path& path) +{ + File file(path); + return read(file.readText()); +} + +std::unique_ptr QuantumCircuitReader::read(const std::string& content) +{ + auto circuit = std::make_unique(); + 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::TerminalType::OUTPUT); + + auto wire = std::make_unique(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(); + } + else if (value == "Z") + { + gate = std::make_unique(); + } + + if (gate) + { + auto wire = std::make_unique(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::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) +{ + +} \ No newline at end of file diff --git a/plugins/quantum_computing/src/QuantumCircuitReader.h b/plugins/quantum_computing/src/QuantumCircuitReader.h new file mode 100644 index 0000000..11148a2 --- /dev/null +++ b/plugins/quantum_computing/src/QuantumCircuitReader.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +using Path = std::filesystem::path; + +class QuantumCircuit; +class QuantumCircuitElement; + +class QuantumCircuitReader +{ +public: + std::unique_ptr read(const Path& path); + + std::unique_ptr read(const std::string& content); + +private: + using Location = std::pair; + + 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 }; +}; \ No newline at end of file diff --git a/plugins/quantum_computing/src/QuantumGate.cpp b/plugins/quantum_computing/src/QuantumGate.cpp index e69de29..8ac8dbc 100644 --- a/plugins/quantum_computing/src/QuantumGate.cpp +++ b/plugins/quantum_computing/src/QuantumGate.cpp @@ -0,0 +1,112 @@ +#include "QuantumGate.h" + +NInMOutQuantumGate::NInMOutQuantumGate(std::size_t numIn, std::size_t numOut, std::vector inputs, std::vector outputs) + : QuantumGate(), + mNumIn(numIn), + mNumOut(numOut) +{ + if (inputs.size() == mNumIn) + { + mInputs = inputs; + } + else + { + mInputs = std::vector(numIn, nullptr); + } + + if (outputs.size() == mNumOut) + { + mOutputs = outputs; + } + else + { + mOutputs = std::vector(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); +} \ No newline at end of file diff --git a/plugins/quantum_computing/src/QuantumGate.h b/plugins/quantum_computing/src/QuantumGate.h index e69de29..768e9db 100644 --- a/plugins/quantum_computing/src/QuantumGate.h +++ b/plugins/quantum_computing/src/QuantumGate.h @@ -0,0 +1,87 @@ +#pragma once + +#include "QuantumCircuitElement.h" + +#include "QuantumWire.h" +#include + +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; + + +class NInMOutQuantumGate : public QuantumGate +{ +public: + NInMOutQuantumGate(std::size_t numIn, std::size_t numOut, std::vector inputs = {}, std::vector 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 mInputs; + std::vector 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); +}; \ No newline at end of file diff --git a/plugins/quantum_computing/src/QuantumState.cpp b/plugins/quantum_computing/src/QuantumState.cpp index e69de29..d3500bc 100644 --- a/plugins/quantum_computing/src/QuantumState.cpp +++ b/plugins/quantum_computing/src/QuantumState.cpp @@ -0,0 +1,6 @@ +#include "QuantumState.h" + +const std::vector& QuantumState::getData() const +{ + return mState; +} \ No newline at end of file diff --git a/plugins/quantum_computing/src/QuantumState.h b/plugins/quantum_computing/src/QuantumState.h index e69de29..44c20e4 100644 --- a/plugins/quantum_computing/src/QuantumState.h +++ b/plugins/quantum_computing/src/QuantumState.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Qubit.h" + +#include + +class QuantumState +{ + const std::vector& getData() const; + +private: + std::vector mState; +}; \ No newline at end of file diff --git a/plugins/quantum_computing/src/QuantumTerminal.cpp b/plugins/quantum_computing/src/QuantumTerminal.cpp new file mode 100644 index 0000000..0cf2f02 --- /dev/null +++ b/plugins/quantum_computing/src/QuantumTerminal.cpp @@ -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; +} diff --git a/plugins/quantum_computing/src/QuantumTerminal.h b/plugins/quantum_computing/src/QuantumTerminal.h new file mode 100644 index 0000000..aa73d55 --- /dev/null +++ b/plugins/quantum_computing/src/QuantumTerminal.h @@ -0,0 +1,38 @@ +#pragma once + +#include "QuantumCircuitElement.h" +#include "Qubit.h" + +#include +#include + +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; diff --git a/plugins/quantum_computing/src/QuantumWire.cpp b/plugins/quantum_computing/src/QuantumWire.cpp new file mode 100644 index 0000000..f9894ea --- /dev/null +++ b/plugins/quantum_computing/src/QuantumWire.cpp @@ -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; +} \ No newline at end of file diff --git a/plugins/quantum_computing/src/QuantumWire.h b/plugins/quantum_computing/src/QuantumWire.h new file mode 100644 index 0000000..3f5b8ac --- /dev/null +++ b/plugins/quantum_computing/src/QuantumWire.h @@ -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; + +class ClassicalWire : public AbstractQuantumWire +{ +public: + WireType getWireType() const override + { + return WireType::CLASSICAL; + } +}; \ No newline at end of file diff --git a/plugins/quantum_computing/src/Qubit.cpp b/plugins/quantum_computing/src/Qubit.cpp index 3d7ae1f..2845a0c 100644 --- a/plugins/quantum_computing/src/Qubit.cpp +++ b/plugins/quantum_computing/src/Qubit.cpp @@ -15,4 +15,14 @@ const ComplexNumber& Qubit::getAlpha() const const ComplexNumber& Qubit::getBeta() const { 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; } \ No newline at end of file diff --git a/plugins/quantum_computing/src/Qubit.h b/plugins/quantum_computing/src/Qubit.h index 4211dda..c10438f 100644 --- a/plugins/quantum_computing/src/Qubit.h +++ b/plugins/quantum_computing/src/Qubit.h @@ -5,11 +5,15 @@ class Qubit { 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& getBeta() const; + + bool isIn0State() const; + + bool isIn1State() const; private: ComplexNumber mAlpha; ComplexNumber mBeta; diff --git a/plugins/quantum_computing/src/visuals/QuantumCircuitNode.cpp b/plugins/quantum_computing/src/visuals/QuantumCircuitNode.cpp new file mode 100644 index 0000000..8bec131 --- /dev/null +++ b/plugins/quantum_computing/src/visuals/QuantumCircuitNode.cpp @@ -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(Transform(loc)); + + terminal_node->setContent(terminal); + + addChild(terminal_node.get()); + + mInputTerminalNodes.push_back(std::move(terminal_node)); + terminal_y += terminal_vertical_spacing; + } +} \ No newline at end of file diff --git a/plugins/quantum_computing/src/visuals/QuantumCircuitNode.h b/plugins/quantum_computing/src/visuals/QuantumCircuitNode.h new file mode 100644 index 0000000..c9fe7d7 --- /dev/null +++ b/plugins/quantum_computing/src/visuals/QuantumCircuitNode.h @@ -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 > mInputTerminalNodes; +}; \ No newline at end of file diff --git a/plugins/quantum_computing/src/visuals/QuantumGateNode.cpp b/plugins/quantum_computing/src/visuals/QuantumGateNode.cpp new file mode 100644 index 0000000..e69de29 diff --git a/plugins/quantum_computing/src/visuals/QuantumGateNode.h b/plugins/quantum_computing/src/visuals/QuantumGateNode.h new file mode 100644 index 0000000..e69de29 diff --git a/plugins/quantum_computing/src/visuals/QuantumTerminalNode.cpp b/plugins/quantum_computing/src/visuals/QuantumTerminalNode.cpp new file mode 100644 index 0000000..a399aae --- /dev/null +++ b/plugins/quantum_computing/src/visuals/QuantumTerminalNode.cpp @@ -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(label); + mLabel = std::make_unique(); + mLabel->setContent(mLabelExpression.get()); + + addChild(mLabel.get()); + } +} \ No newline at end of file diff --git a/plugins/quantum_computing/src/visuals/QuantumTerminalNode.h b/plugins/quantum_computing/src/visuals/QuantumTerminalNode.h new file mode 100644 index 0000000..bc261de --- /dev/null +++ b/plugins/quantum_computing/src/visuals/QuantumTerminalNode.h @@ -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 mLabelExpression; + std::unique_ptr mLabel; +}; \ No newline at end of file diff --git a/plugins/quantum_computing/src/visuals/QuantumWireNode.cpp b/plugins/quantum_computing/src/visuals/QuantumWireNode.cpp new file mode 100644 index 0000000..e69de29 diff --git a/plugins/quantum_computing/src/visuals/QuantumWireNode.h b/plugins/quantum_computing/src/visuals/QuantumWireNode.h new file mode 100644 index 0000000..e69de29 diff --git a/plugins/quantum_computing/test/CMakeLists.txt b/plugins/quantum_computing/test/CMakeLists.txt index 2d117c6..68e34a7 100644 --- a/plugins/quantum_computing/test/CMakeLists.txt +++ b/plugins/quantum_computing/test/CMakeLists.txt @@ -1,6 +1,7 @@ list(APPEND UNIT_TEST_FILES TestBlochSphereNode.cpp + TestQuantumCircuitParsing.cpp ) add_executable(quantum_computing_unit_tests ${CMAKE_SOURCE_DIR}/test/test_runner.cpp ${UNIT_TEST_FILES}) diff --git a/plugins/quantum_computing/test/TestQuantumCircuitParsing.cpp b/plugins/quantum_computing/test/TestQuantumCircuitParsing.cpp new file mode 100644 index 0000000..315f857 --- /dev/null +++ b/plugins/quantum_computing/test/TestQuantumCircuitParsing.cpp @@ -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(Point(10, 10)); + + node->setContent(circuit.get()); + + renderer.getScene()->addNode(node.get()); + renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "circuit.svg"); +} \ No newline at end of file diff --git a/src/publishing/latex/LatexMathExpression.cpp b/src/publishing/latex/LatexMathExpression.cpp index 78e2bb9..949bf60 100644 --- a/src/publishing/latex/LatexMathExpression.cpp +++ b/src/publishing/latex/LatexMathExpression.cpp @@ -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) { if (c == '}') @@ -175,13 +195,13 @@ void LatexMathExpression::onFinishedTagName() if (*lookup == LatexMathSymbol::Tag::FRAC) { - mWorkingType = Type::FRACTION; - auto expression = std::make_unique(mWorkingType); - mWorkingExpression = expression.get(); - mExpressions.push_back(std::move(expression)); + onFracTag(); mWorkingString.clear(); } - + else if (auto tag_type = LatexSymbolLookup::getTagType(*lookup); tag_type == LatexMathSymbol::Type::ENCLOSING_TAG) + { + onEnclosingTag(*lookup); + } mLineState = LineState::IN_TAG_BODY; } } @@ -193,12 +213,39 @@ void LatexMathExpression::onFinishedTagName() } } +void LatexMathExpression::onFracTag() +{ + mWorkingType = Type::FRACTION; + auto expression = std::make_unique(mWorkingType); + mWorkingExpression = expression.get(); + mExpressions.push_back(std::move(expression)); +} + +void LatexMathExpression::onEnclosingTag(LatexMathSymbol::Tag tag) +{ + mWorkingType = Type::ENCLOSING; + auto expression = std::make_unique(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() { if (mWorkingType == Type::LEAF) { + MLOG_INFO("onCloseExpression LEAF"); if (!mWorkingSymbols.empty()) { + MLOG_INFO("Has working symbols"); auto expression = std::make_unique(mWorkingType); expression->setContent(mWorkingSymbols); mExpressions.push_back(std::move(expression)); @@ -206,6 +253,7 @@ void LatexMathExpression::onCloseExpression() } else if (mWorkingType == Type::FRACTION) { + MLOG_INFO("onCloseExpression FRACTION"); mWorkingExpression->setRawContent(mWorkingString); if (mWorkingExpression->getExpressions().size() == 2) @@ -219,6 +267,20 @@ void LatexMathExpression::onCloseExpression() 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(); mWorkingSymbols.clear(); diff --git a/src/publishing/latex/LatexMathExpression.h b/src/publishing/latex/LatexMathExpression.h index 9ed0bca..b1525d4 100644 --- a/src/publishing/latex/LatexMathExpression.h +++ b/src/publishing/latex/LatexMathExpression.h @@ -17,6 +17,7 @@ public: LINEAR, LEAF, FRACTION, + ENCLOSING, SUBSCRIPT, SUPERSCRIPT }; @@ -39,8 +40,16 @@ public: const std::vector& getExpressions() const; + const LatexMathSymbol& getLeftSymbol() const; + + const LatexMathSymbol& getRightSymbol() const; + const Type getType() const; + void setLeftSymbol(const LatexMathSymbol& symbol); + + void setRightSymbol(const LatexMathSymbol& symbol); + void setContent(std::vector& symbols); void setRawContent(const std::string& content); @@ -67,6 +76,10 @@ public: void onCloseExpression(); + void onFracTag(); + + void onEnclosingTag(LatexMathSymbol::Tag tag); + void parse(); private: @@ -81,6 +94,9 @@ private: Type mType{ Type::LEAF }; std::vector mWorkingSymbols; + LatexMathSymbol mLeftSymbol; + LatexMathSymbol mRightSymbol; + std::vector mSymbols; std::vector mExpressions; }; \ No newline at end of file diff --git a/src/publishing/latex/LatexSymbols.cpp b/src/publishing/latex/LatexSymbols.cpp index fb7e8d1..e513600 100644 --- a/src/publishing/latex/LatexSymbols.cpp +++ b/src/publishing/latex/LatexSymbols.cpp @@ -7,14 +7,51 @@ std::unordered_map LatexSymbolLookup::mSymbols = { {"alpha", L"\u03B1"}, {"beta", L"\u03B2"}, {"gamma", L"\u03B3"}, - {"psi", L"\u03C8"} + {"psi", L"\u03C8"}, + {"langle", L"\u27E8"}, + {"rangle", L"\u27E9"}, }; +std::unordered_map LatexSymbolLookup::mLeftSymbols = { + {LatexMathSymbol::Tag::BRA, L"\u27E8"}, + {LatexMathSymbol::Tag::KET, L"\u007C"} +}; + +std::unordered_map LatexSymbolLookup::mRightSymbols = { + {LatexMathSymbol::Tag::BRA, L"\u007C"}, + {LatexMathSymbol::Tag::KET, L"\u27E9"} +}; std::unordered_map LatexSymbolLookup::mTags = { {"frac", LatexMathSymbol::Tag::FRAC}, + {"bra", LatexMathSymbol::Tag::BRA}, + {"ket", LatexMathSymbol::Tag::KET}, }; +std::optional LatexSymbolLookup::getLeftSymbolUtf8(LatexMathSymbol::Tag tag) +{ + if (auto entry = getLeftSymbolUtf16(tag); entry) + { + return UnicodeUtils::utf16ToUtf8String(*entry); + } + else + { + return std::nullopt; + } +} + +std::optional LatexSymbolLookup::getRightSymbolUtf8(LatexMathSymbol::Tag tag) +{ + if (auto entry = getRightSymbolUtf16(tag); entry) + { + return UnicodeUtils::utf16ToUtf8String(*entry); + } + else + { + return std::nullopt; + } +} + std::optional LatexSymbolLookup::getSymbolUtf8(const std::string& tag) { if (auto entry = getSymbolUtf16(tag); entry) @@ -27,6 +64,31 @@ std::optional LatexSymbolLookup::getSymbolUtf8(const std::string& t } } +std::optional LatexSymbolLookup::getLeftSymbolUtf16(LatexMathSymbol::Tag tag) +{ + if (auto iter = mLeftSymbols.find(tag); iter != mLeftSymbols.end()) + { + return iter->second; + } + else + { + return std::nullopt; + } +} + +std::optional LatexSymbolLookup::getRightSymbolUtf16(LatexMathSymbol::Tag tag) +{ + if (auto iter = mRightSymbols.find(tag); iter != mRightSymbols.end()) + { + return iter->second; + } + else + { + return std::nullopt; + } + +} + std::optional LatexSymbolLookup::getSymbolUtf16(const std::string& tag) { if (auto iter = mSymbols.find(tag); iter != mSymbols.end()) diff --git a/src/publishing/latex/LatexSymbols.h b/src/publishing/latex/LatexSymbols.h index a080dc3..45d6435 100644 --- a/src/publishing/latex/LatexSymbols.h +++ b/src/publishing/latex/LatexSymbols.h @@ -19,10 +19,12 @@ struct LatexMathSymbol enum class Tag { 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), mName(name), mUnicode(unicode) @@ -38,8 +40,16 @@ struct LatexMathSymbol class LatexSymbolLookup { public: + static std::optional getLeftSymbolUtf8(LatexMathSymbol::Tag tag); + + static std::optional getRightSymbolUtf8(LatexMathSymbol::Tag tag); + static std::optional getSymbolUtf8(const std::string& tag); + static std::optional getLeftSymbolUtf16(LatexMathSymbol::Tag tag); + + static std::optional getRightSymbolUtf16(LatexMathSymbol::Tag tag); + static std::optional getSymbolUtf16(const std::string& tag); static std::optional getKnownTag(const std::string& tag); @@ -50,12 +60,32 @@ public: { case LatexMathSymbol::Tag::FRAC: return 2; + case LatexMathSymbol::Tag::BRA: + case LatexMathSymbol::Tag::KET: + return 1; default: 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: + static std::unordered_map mLeftSymbols; + static std::unordered_map mRightSymbols; + static std::unordered_map mSymbols; static std::unordered_map mTags; diff --git a/src/publishing/plotting/EquationNode.cpp b/src/publishing/plotting/EquationNode.cpp index 2b1e63f..155089f 100644 --- a/src/publishing/plotting/EquationNode.cpp +++ b/src/publishing/plotting/EquationNode.cpp @@ -85,6 +85,33 @@ void EquationNode::addExpression(SceneInfo* sceneInfo, const LatexMathExpression 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(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(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) diff --git a/test/data/quantum_circuit.dat b/test/data/quantum_circuit.dat new file mode 100644 index 0000000..ffa8750 --- /dev/null +++ b/test/data/quantum_circuit.dat @@ -0,0 +1,2 @@ +|0>---X--- +|1>---Z--- \ No newline at end of file diff --git a/test/publishing/TestLatexConverter.cpp b/test/publishing/TestLatexConverter.cpp index 70e1085..4282980 100644 --- a/test/publishing/TestLatexConverter.cpp +++ b/test/publishing/TestLatexConverter.cpp @@ -10,7 +10,7 @@ TEST_CASE(TestLatexConverter, "publishing") { - auto expression = std::make_unique("\\psi = \\frac{\\alpha + \\beta}{c + d} + e"); + auto expression = std::make_unique("\\psi = \\frac{\\alpha + \\beta}{c + d} + \\ket{e}"); auto equation_node = std::make_unique(Point(10, 10)); equation_node->setContent(expression.get());