{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# QOperation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "np.set_printoptions(linewidth=200)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## QOperation\n",
    "This notebook describes the concept of QOperation in Quara and the related classes.\n",
    "\n",
    "Quara supports operations such as State, Gate, Povm, etc.\n",
    "These operations is called objects in Quara.\n",
    "Two methods to generate objects.\n",
    "- The typical objects can be generated from a module called `xxx_typical`. (\"xxx\" is a object name.)\n",
    "- Users can also generate objects directly.\n",
    "\n",
    "QOperation is the base class of these operations and has common properties and functions."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### common properties\n",
    "The common properties are as follows:\n",
    "\n",
    "- `is_physicality_required` - If this is True, this object must satisfy the physicality.\n",
    "- `is_estimation_object` - If this is True, this object is for estimation.\n",
    "- `on_para_eq_constraint` - If this is True, functions and algorithms work on the assumption that the parameters of this object satisfy the equality constraint. \n",
    "- `on_algo_eq_constraint` - If this is True, estimation algorithms use equality constraint. \n",
    "- `on_algo_ineq_constraint` - If this is True, estimation algorithms use inequality constraint. \n",
    "- `mode_proj_order` - the order in which the projection are performed, by default \"eq_ineq\".\n",
    "   - \"eq_ineq\" - The projection are performed in the order of equality constraints, followed by inequality constraints.\n",
    "   - \"ineq_eq\" - The projection are performed in the order of inequality constraints, followed by equality constraints.\n",
    "- `eps_proj_physical` - Epsiron that is projection algorithm error threshold for being physical.\n",
    "- `eps_truncate_imaginary_part` - The threshold to truncate imaginary part."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "is_physicality_required: True\n",
      "is_estimation_object: True\n",
      "on_para_eq_constraint: True\n",
      "on_algo_eq_constraint: True\n",
      "on_algo_ineq_constraint: True\n",
      "mode_proj_order: eq_ineq\n",
      "eps_proj_physical: 1e-14\n",
      "eps_truncate_imaginary_part: None\n"
     ]
    }
   ],
   "source": [
    "from quara.objects.composite_system_typical import generate_composite_system\n",
    "from quara.objects.qoperation import QOperation\n",
    "\n",
    "c_sys = generate_composite_system(\"qubit\", 1)\n",
    "qoperation = QOperation(c_sys)\n",
    "\n",
    "print(f\"is_physicality_required: {qoperation.is_physicality_required}\")\n",
    "print(f\"is_estimation_object: {qoperation.is_estimation_object}\")\n",
    "print(f\"on_para_eq_constraint: {qoperation.on_para_eq_constraint}\")\n",
    "print(f\"on_algo_eq_constraint: {qoperation.on_algo_eq_constraint}\")\n",
    "print(f\"on_algo_ineq_constraint: {qoperation.on_algo_ineq_constraint}\")\n",
    "print(f\"mode_proj_order: {qoperation.mode_proj_order}\")\n",
    "print(f\"eps_proj_physical: {qoperation.eps_proj_physical}\")\n",
    "print(f\"eps_truncate_imaginary_part: {qoperation.eps_truncate_imaginary_part}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### functions to check constraints\n",
    "QOperation has functions to check constraints.\n",
    "\n",
    "- `is_eq_constraint_satisfied()` - Whether the qoperation is satisfied equality constraints.\n",
    "- `is_ineq_constraint_satisfied()` - Whether the qoperation is satisfied inequality constraints.\n",
    "- `is_physical()` - Whether the qoperation is satisfied equality and inequality constraints.\n",
    "\n",
    "`is_eq_constraint_satisfied()` and `is_ineq_constraint_satisfied()` are abstract functions and are implemented in a subclasses."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### projection functions\n",
    "QOperation has projection functions.\n",
    "\n",
    "- `calc_proj_eq_constraint()` - Calculates the projection of QOperation on equal constraint.\n",
    "- `calc_proj_ineq_constraint()` - Calculates the projection of QOperation on inequal constraint.\n",
    "- `calc_proj_physical()` - Calculates the projection of QOperation on equal and inequal constraint.\n",
    "- `calc_proj_physical_with_var()` - Executes the algorithm of calc_proj_physical using variables. This functions is faster than calc_proj_physical.\n",
    "\n",
    "`calc_proj_physical()` and `calc_proj_physical_with_var()` calculate the projection in the order specified by `mode_proj_order`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### functions to transform parameters\n",
    "QOperation has functions to transform parameters.\n",
    "\n",
    "- `to_stacked_vector()` - Transforms all parameters to a one-dimensional vector (a numpy array).\n",
    "- `to_var()` - Transforms parameters except for the part of the equality constraint to a one-dimensional vector (a numpy array).\n",
    "\n",
    "These functions are abstract functions and are implemented in a subclasses."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### functions to generate special objects\n",
    "QOperation has functions to generate special objects.\n",
    "\n",
    "- `generate_zero_obj()` - Generates object with all parameters are zero.\n",
    "- `generate_origin_obj()` - Generates origin object.\n",
    "\n",
    "These functions are abstract functions and are implemented in a subclasses."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### supports arithmetic operations\n",
    "Quara supports arithmetic operations between same type of QOperations.\n",
    "\n",
    "- `__add__()` - Calculates `a + b` for Qoperation a, b.\n",
    "- `__sub__()` - Calculates `a - b` for Qoperation a, b.\n",
    "- `__mul__()` - Calculates `a * b` for Qoperation a and number b.\n",
    "- `__rmul__()` - Calculates `a * b` for number a and Qoperation b.\n",
    "- `__truediv__()` - Calculates `a / b` for Qoperation a and number b."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Notation\n",
    "$I$ is the identity matrix.  \n",
    "$X := \\begin{bmatrix} 0 & 1 \\\\ 1 & 0 \\\\ \\end{bmatrix}$, $Y := \\begin{bmatrix} 0 & -i \\\\ i & 0 \\\\ \\end{bmatrix}$, and $Z := \\begin{bmatrix} 1 & 0 \\\\ 0 & -1 \\\\ \\end{bmatrix}$ are Pauli matrices.  \n",
    "$B$ is a basis $\\{ I/\\sqrt{2}, X/\\sqrt{2}, Y/\\sqrt{2}, Z/\\sqrt{2} \\}$, which is normalized by Hilbert-Schmidt inner product $\\langle S, T\\rangle := \\text{Tr}[ST]$."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.7.7 64-bit ('quara': pipenv)",
   "metadata": {
    "interpreter": {
     "hash": "e0c99f005b0837bce79602fafa142c135e273dc311d0671484e4c834ee0e9c24"
    }
   },
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.7-final"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
