namespace QPanda::Variational

namespace Variational {

// typedefs

typedef VariationalQuantumGate_H VQG_H;
typedef VariationalQuantumGate_X VQG_X;
typedef VariationalQuantumGate_X1 VQG_X1;
typedef VariationalQuantumGate_Y VQG_Y;
typedef VariationalQuantumGate_Y1 VQG_Y1;
typedef VariationalQuantumGate_Z VQG_Z;
typedef VariationalQuantumGate_Z1 VQG_Z1;
typedef VariationalQuantumGate_S VQG_S;
typedef VariationalQuantumGate_T VQG_T;
typedef VariationalQuantumGate_U1 VQG_U1;
typedef VariationalQuantumGate_RX VQG_RX;
typedef VariationalQuantumGate_RY VQG_RY;
typedef VariationalQuantumGate_RZ VQG_RZ;
typedef VariationalQuantumGate_U2 VQG_U2;
typedef VariationalQuantumGate_RPhi VQG_RPhi;
typedef VariationalQuantumGate_U3 VQG_U3;
typedef VariationalQuantumGate_U4 VQG_U4;
typedef VariationalQuantumGate_CNOT VQG_CNOT;
typedef VariationalQuantumGate_CZ VQG_CZ;
typedef VariationalQuantumGate_SWAP VQG_SWAP;
typedef VariationalQuantumGate_iSWAP VQG_iSWAP;
typedef VariationalQuantumGate_SqiSWAP VQG_SqiSWAP;
typedef VariationalQuantumGate_CR VQG_CR;
typedef VariationalQuantumGate_CU VQG_CU;
typedef VariationalQuantumGate_CRX VQG_CRX;
typedef VariationalQuantumGate_CRY VQG_CRY;
typedef VariationalQuantumGate_CRZ VQG_CRZ;
typedef VariationalQuantumGate VQG;
typedef VariationalQuantumCircuit VQC;

// enums

enum OptimizerMode;
enum back_flags;
enum op_type;

// structs

struct impl;
struct impl_qop_pmeasure;
struct impl_qop_pmeasure_real_chip;
struct impl_stack;
struct impl_subscript;
struct impl_vqp;
struct impl_vqp_real_chip;

// classes

class AdaGradOptimizer;
class AdamOptimizer;
class Double;
class MomentumOptimizer;
class Optimizer;
class RMSPropOptimizer;
class VanillaGradientDescentOptimizer;
class VariationalQuantumCircuit;
class VariationalQuantumGate;
class VariationalQuantumGate_CNOT;
class VariationalQuantumGate_CR;
class VariationalQuantumGate_CRX;
class VariationalQuantumGate_CRY;
class VariationalQuantumGate_CRZ;
class VariationalQuantumGate_CU;
class VariationalQuantumGate_CZ;
class VariationalQuantumGate_H;
class VariationalQuantumGate_RPhi;
class VariationalQuantumGate_RX;
class VariationalQuantumGate_RY;
class VariationalQuantumGate_RZ;
class VariationalQuantumGate_S;
class VariationalQuantumGate_SWAP;
class VariationalQuantumGate_SqiSWAP;
class VariationalQuantumGate_T;
class VariationalQuantumGate_U1;
class VariationalQuantumGate_U2;
class VariationalQuantumGate_U3;
class VariationalQuantumGate_U4;
class VariationalQuantumGate_X;
class VariationalQuantumGate_X1;
class VariationalQuantumGate_Y;
class VariationalQuantumGate_Y1;
class VariationalQuantumGate_Z;
class VariationalQuantumGate_Z1;
class VariationalQuantumGate_iSWAP;
class expression;
class var;

// global functions

MatrixXd eval(
    var v,
    bool iter
    );

void back(
    const var&,
    std::unordered_map<var, MatrixXd>&
    );

void back(
    expression&,
    std::unordered_map<var, MatrixXd>&
    );

void back(
    const var&,
    std::unordered_map<var, MatrixXd>&,
    const std::unordered_set<var>&
    );

void back(
    expression&,
    std::unordered_map<var, MatrixXd>&,
    const std::unordered_set<var>&
    );

int numOpArgs(op_type op);
VariationalQuantumCircuit& VariationalQuantumCircuit::insert< std::shared_ptr< VariationalQuantumGate > >(std::shared_ptr<VariationalQuantumGate> gate);

template <typename... V>
const var pack_expression(
    op_type op,
    V&... args
    );

template <typename... V>
const var pack_expression(
    op_type op,
    int axis,
    V&... args
    );

const var operator + (
    var lhs,
    var rhs
    );

const var operator - (
    var lhs,
    var rhs
    );

const var operator * (
    var lhs,
    var rhs
    );

const var operator/ (
    var lhs,
    var rhs
    );

const var exp(var v);
const var sigmoid(var v);
const var log(var v);

const var poly(
    var v,
    var power
    );

const var dot(
    var lhs,
    var rhs
    );

const var inverse(var v);
const var transpose(var v);
const var sum(var v);
const var softmax(var v);

const var crossEntropy(
    var lhs,
    var rhs
    );

const var dropout(
    var lhs,
    var rhs
    );

template <typename ... T>
const var stack(
    int axis,
    T&... v
    );

const var qop(
    VariationalQuantumCircuit& circuit,
    PauliOperator Hamiltonian,
    QuantumMachine* machine,
    std::vector<Qubit*> measure_qubits
    );

const var qop_real_chip(
    VariationalQuantumCircuit& circuit,
    PauliOperator Hamiltonian,
    QuantumMachine* machine,
    std::vector<Qubit*> measure_qubits,
    int shots
    );

const var qop(
    VariationalQuantumCircuit& circuit,
    PauliOperator Hamiltonian,
    QuantumMachine* machine,
    std::map<size_t, Qubit*> measure_qubits
    );

const var qop_pmeasure(
    VariationalQuantumCircuit& circuit,
    std::vector<size_t> components,
    QuantumMachine* machine,
    std::vector<Qubit*> measure_qubits
    );

const var qop_pmeasure_real_chip(
    VariationalQuantumCircuit& circuit,
    std::vector<size_t> components,
    QuantumMachine* machine,
    std::vector<Qubit*> measure_qubits,
    std::vector<ClassicalCondition> cbits,
    size_t shots
    );

bool _is_scalar(const var& v);
bool _is_matrix(const var& v);
bool _is_vector(const var& v);
double _sval(const var& v);
MatrixXd _mval(const var& v);
MatrixXd scalar(double num);
MatrixXd vector2mat(std::vector<double> data);
MatrixXd zeros_like(const MatrixXd& like);
MatrixXd zeros_like(const var& like);
MatrixXd ones_like(const MatrixXd& like);
MatrixXd ones_like(const var& like);

} // namespace Variational