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 <cmath>
|
||||
|
||||
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);
|
||||
}
|
|
@ -9,6 +9,8 @@ public:
|
|||
|
||||
double getImaginary() const;
|
||||
|
||||
double getMagnitude() const;
|
||||
|
||||
void setReal(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)
|
||||
|
||||
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 )
|
|
@ -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
|
||||
{
|
||||
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
|
||||
{
|
||||
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;
|
||||
|
|
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
|
||||
TestBlochSphereNode.cpp
|
||||
TestQuantumCircuitParsing.cpp
|
||||
)
|
||||
|
||||
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)
|
||||
{
|
||||
if (c == '}')
|
||||
|
@ -175,13 +195,13 @@ void LatexMathExpression::onFinishedTagName()
|
|||
|
||||
if (*lookup == LatexMathSymbol::Tag::FRAC)
|
||||
{
|
||||
mWorkingType = Type::FRACTION;
|
||||
auto expression = std::make_unique<LatexMathExpression>(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<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()
|
||||
{
|
||||
if (mWorkingType == Type::LEAF)
|
||||
{
|
||||
MLOG_INFO("onCloseExpression LEAF");
|
||||
if (!mWorkingSymbols.empty())
|
||||
{
|
||||
MLOG_INFO("Has working symbols");
|
||||
auto expression = std::make_unique<LatexMathExpression>(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();
|
||||
|
|
|
@ -17,6 +17,7 @@ public:
|
|||
LINEAR,
|
||||
LEAF,
|
||||
FRACTION,
|
||||
ENCLOSING,
|
||||
SUBSCRIPT,
|
||||
SUPERSCRIPT
|
||||
};
|
||||
|
@ -39,8 +40,16 @@ public:
|
|||
|
||||
const std::vector<LatexMathExpressionPtr>& 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<LatexMathSymbol>& 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<LatexMathSymbol> mWorkingSymbols;
|
||||
|
||||
LatexMathSymbol mLeftSymbol;
|
||||
LatexMathSymbol mRightSymbol;
|
||||
|
||||
std::vector<LatexMathSymbol> mSymbols;
|
||||
std::vector<LatexMathExpressionPtr> mExpressions;
|
||||
};
|
|
@ -7,14 +7,51 @@ std::unordered_map<std::string, std::wstring> 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<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 = {
|
||||
{"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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (auto iter = mSymbols.find(tag); iter != mSymbols.end())
|
||||
|
|
|
@ -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<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::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<LatexMathSymbol::Tag> 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<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, LatexMathSymbol::Tag> mTags;
|
||||
|
|
|
@ -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<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)
|
||||
|
|
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")
|
||||
{
|
||||
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));
|
||||
equation_node->setContent(expression.get());
|
||||
|
|
Loading…
Reference in a new issue