{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://cambridgequantum.com/schemas/tket/compiler_pass_v1.json",
  "type": "object",
  "description": "Serialization of a pytket compiler pass v1",
  "properties": {
    "pass_class": {
      "enum": [
        "StandardPass",
        "SequencePass",
        "RepeatPass",
        "RepeatWithMetricPass",
        "RepeatUntilSatisfiedPass"
      ],
      "description": "The subclass of \"BasePass\" implemented, defining whether this is an elementary pass or some recursive combination of passes."
    },
    "StandardPass": {
      "$ref": "#/definitions/StandardPass"
    },
    "SequencePass": {
      "$ref": "#/definitions/SequencePass"
    },
    "RepeatPass": {
      "$ref": "#/definitions/RepeatPass"
    },
    "RepeatWithMetricPass": {
      "$ref": "#/definitions/RepeatWithMetricPass"
    },
    "RepeatUntilSatisfiedPass": {
      "$ref": "#/definitions/RepeatUntilSatisfiedPass"
    }
  },
  "required": [
    "pass_class"
  ],
  "allOf": [
    {
      "if": {
        "properties": {
          "pass_class": {
            "const": "StandardPass"
          }
        }
      },
      "then": {
        "required": [
          "StandardPass"
        ]
      }
    },
    {
      "if": {
        "properties": {
          "pass_class": {
            "const": "SequencePass"
          }
        }
      },
      "then": {
        "required": [
          "SequencePass"
        ]
      }
    },
    {
      "if": {
        "properties": {
          "pass_class": {
            "const": "RepeatPass"
          }
        }
      },
      "then": {
        "required": [
          "RepeatPass"
        ]
      }
    },
    {
      "if": {
        "properties": {
          "pass_class": {
            "const": "RepeatWithMetricPass"
          }
        }
      },
      "then": {
        "required": [
          "RepeatWithMetricPass"
        ]
      }
    },
    {
      "if": {
        "properties": {
          "pass_class": {
            "const": "RepeatUntilSatisfiedPass"
          }
        }
      },
      "then": {
        "required": [
          "RepeatUntilSatisfiedPass"
        ]
      }
    }
  ],
  "definitions": {
    "StandardPass": {
      "type": "object",
      "description": "Additional content to describe an elementary compiler pass.",
      "properties": {
        "name": {
          "type": "string",
          "enum": [
            "RebaseCustom",
            "RebaseCustomViaTK2",
            "AutoRebase",
            "CommuteThroughMultis",
            "DecomposeArbitrarilyControlledGates",
            "DecomposeBoxes",
            "DecomposeMultiQubitsCX",
            "DecomposeSingleQubitsTK1",
            "PeepholeOptimise2Q",
            "RebaseTket",
            "RebaseUFR",
            "RemoveRedundancies",
            "SynthesiseTK",
            "SynthesiseTket",
            "SynthesiseOQC",
            "SquashTK1",
            "SquashRzPhasedX",
            "AutoSquash",
            "FlattenRegisters",
            "DelayMeasures",
            "ZZPhaseToRz",
            "RemoveDiscarded",
            "SimplifyMeasured",
            "RemoveBarriers",
            "RemovePhaseOps",
            "DecomposeBridges",
            "KAKDecomposition",
            "ThreeQubitSquash",
            "FullPeepholeOptimise",
            "ComposePhasePolyBoxes",
            "EulerAngleReduction",
            "RoutingPass",
            "PlacementPass",
            "NaivePlacementPass",
            "RenameQubitsPass",
            "CliffordSimp",
            "DecomposeSwapsToCXs",
            "DecomposeSwapsToCircuit",
            "OptimisePhaseGadgets",
            "OptimisePairwiseGadgets",
            "PauliSimp",
            "PauliExponentials",
            "GuidedPauliSimp",
            "SimplifyInitial",
            "FullMappingPass",
            "DefaultMappingPass",
            "CXMappingPass",
            "PauliSquash",
            "ContextSimp",
            "DecomposeTK2",
            "CnXPairwiseDecomposition",
            "RemoveImplicitQubitPermutation",
            "NormaliseTK2",
            "RoundAngles",
            "GreedyPauliSimp",
            "RxFromSX"
          ],
          "description": "The name of the compiler pass. Matches the name of the pytket method used to generate it. List all the passes as enum."
        },
        "basis_allowed": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "OpTypes of supported gates. Used in \"RebaseCustom\" and \"AutoRebase\"."
        },
        "basis_singleqs": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "OpTypes of supported single qubit gates. Used in \"SquashCustom\" and \"AutoSquash\""
        },
        "basis_cx_replacement": {
          "$ref": "circuit_v1.json#",
          "description": "A circuit implementing a CX gate in a target gate set. Used in \"RebaseCustom\"."
        },
        "basis_tk1_replacement": {
          "type": "string",
          "description": "A method for generating optimised single-qubit unitary circuits in a target gate set. This string should be interpreted by Python \"dill\" into a function. Used in \"RebaseCustom\" and \"SquashCustom\"."
        },
        "always_squash_symbols": {
          "type": "boolean",
          "description": "Whether to always squash symbolic gates regardless of the complexity blow-up. Used in \"SquashCustom\"."
        },
        "euler_p": {
          "type": "string",
          "description": "The choice of P rotation for \"EulerAngleReduction\" for P-Q-P and Q-P-Q triples.",
          "enum": [
            "Rx",
            "Ry",
            "Rz"
          ]
        },
        "euler_q": {
          "type": "string",
          "description": "The choice of Q rotation for \"EulerAngleReduction\" for P-Q-P and Q-P-Q triples.",
          "enum": [
            "Rx",
            "Ry",
            "Rz"
          ]
        },
        "euler_strict": {
          "type": "boolean",
          "description": "False allows context-dependent reduction to just P-Q or Q-P by commuting the third rotation through the subsequent gate. Used in \"EulerAngleReduction\"."
        },
        "allow_swaps": {
          "type": "boolean",
          "description": "Permit Clifford simplifications that introduce implicit swaps. Used in \"CliffordSimp\"."
        },
        "qubit_map": {
          "type": "array",
          "description": "Map for renaming qubits in \"RenameQubitsPass\".",
          "items": {
            "type": "array",
            "items": [
              {
                "$ref": "circuit_v1.json#/definitions/unitid"
              },
              {
                "$ref": "circuit_v1.json#/definitions/unitid"
              }
            ]
          }
        },
        "placement": {
          "$ref": "placement_v1.json#"
        },
        "architecture": {
          "$ref": "architecture_v1.json#"
        },
        "directed": {
          "type": "boolean",
          "description": "Whether to consider directedness of the architecture for CXs in \"DecomposeSwapsToCXs\"."
        },
        "swap_replacement": {
          "$ref": "circuit_v1.json#"
        },
        "fidelity": {
          "type": "number",
          "definition": "If <1, \"KAKDecomposition\" may not preserve semantics in order to optimise for the given CX fidelity.",
          "minimum": 0,
          "maximum": 1
        },
        "cx_config": {
          "type": "string",
          "enum": [
            "Snake",
            "Tree",
            "Star"
          ],
          "definition": "A preference of CX configuration for building parities. Used in \"OptimisePhaseGadgets\", \"PauliSimp\", \"GuidedPauliSimp\", and \"PauliSquash\"."
        },
        "pauli_synth_strat": {
          "type": "string",
          "enum": [
            "Individual",
            "Pairwise",
            "Sets"
          ],
          "definition": "Whether to synthesise Pauli gadget sequences as individual rotations, pairwise, or in sets of commuting operations. Used in \"PauliSimp\", \"GuidedPauliSimp\", and \"PauliSquash\"."
        },
        "allow_classical": {
          "type": "boolean",
          "description": "Whether to allow measurements on known states to be removed during \"SimplifyInitial\" and \"ContextSimp\"."
        },
        "create_all_qubits": {
          "type": "boolean",
          "description": "Whether to automatically annotate all qubits as initialised to the zero state for \"SimplifyInitial\"."
        },
        "x_circuit": {
          "$ref": "circuit_v1.json#"
        },
        "delay_measures": {
          "type": "boolean",
          "description": "Whether to include a \"DelayMeasures\" pass in a \"CXMappingPass\"."
        },
        "allow_partial": {
          "type": "boolean",
          "description": "Whether to allow partial delays in \"DelayMeasures\" when the circuit has non-commutable operations after the measure."
        },
        "target_2qb_gate": {
          "type": "string",
          "enum": [
            "CX",
            "TK2"
          ]
        },
        "min_size": {
          "type": "integer",
          "description": "Minimal number of CX gates in each phase in \"ComposePhasePolyBoxes\"."
        },
        "routing_config": {
          "$ref": "#/definitions/routing_config"
        },
        "fidelities": {
          "type": "object",
          "description": "Gate fidelities in \"DecomposeTK2\".",
          "properties": {
            "CX": {
              "type": ["number", "null"],
              "minimum": 0,
              "maximum": 1
            },
            "ZZMax": {
              "type": ["number", "null"],
              "minimum": 0,
              "maximum": 1
            },
            "ZZPhase": {
              "type": ["number", "null"],
              "minimum": 0,
              "maximum": 1
            }
          }
        },
        "n": {
          "type": "integer",
          "description": "Level of precision applied in \"RoundAngles\"."
        },
        "only_zeros": {
          "type": "boolean",
          "description": "Whether to restrict \"RoundAngles\" to rounding to zero."
        },
        "excluded_types": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "OpTypes excluded in \"DecomposeBoxes\""
        },
        "excluded_opgroups": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "opgroups excluded in \"DecomposeBoxes\""
        },
        "included_types": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "OpTypes included in \"DecomposeBoxes\"; optional field"
        },
        "included_opgroups": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "opgroups included in \"DecomposeBoxes\"; optional field"
        },
        "discount_rate": {
          "type": "number",
          "definition": "parameter controlling cost discount in \"GreedyPauliSimp\""
        },
        "depth_weight": {
          "type": "number",
          "definition": "parameter controlling the degree of depth optimisation in \"GreedyPauliSimp\""
        },
        "max_lookahead": {
          "type": "number",
          "definition": "parameter controlling the lookahead when evaluating candidates in \"GreedyPauliSimp\""
        },
        "max_tqe_candidates": {
          "type": "number",
          "definition": "parameter controlling the number of candidates to evaluate in \"GreedyPauliSimp\""
        },
        "seed": {
          "type": "number",
          "definition": "parameter controlling the random sampling and tie breaking in \"GreedyPauliSimp\""
        },
        "allow_zzphase": {
          "type": "boolean",
          "definition": "parameter controlling the use of ZZPhase gates in \"GreedyPauliSimp\""
        },
        "thread_timeout": {
          "type": "number",
          "definition": "parameter controlling the maximum runtime of a single thread in \"GreedyPauliSimp\""
        },
        "only_reduce": {
          "type": "boolean",
          "definition": "parameter controlling whether \"GreedyPauliSimp\" can return circuits with more two qubit gates"
        },
        "trials": {
          "type": "number",
          "definition": "parameter controlling the number of random solutions found when calling \"GreedyPauliSimp\""
        }
      },
      "required": [
        "name"
      ],
      "allOf": [
        {
          "if": {
            "properties": {
              "name": {
                "const": "RebaseCustom"
              }
            }
          },
          "then": {
            "required": [
              "basis_allowed",
              "basis_cx_replacement",
              "basis_tk1_replacement"
            ],
            "maxProperties": 4
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "AutoRebase"
              }
            }
          },
          "then": {
            "required": [
              "basis_allowed",
              "allow_swaps"
            ],
            "maxProperties": 3
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "SquashCustom"
              }
            }
          },
          "then": {
            "required": [
              "basis_singleqs",
              "basis_tk1_replacement",
              "always_squash_symbols"
            ],
            "maxProperties": 4
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "AutoSquash"
              }
            }
          },
          "then": {
            "required": [
              "basis_singleqs"
            ],
            "maxProperties": 2
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "EulerAngleReduction"
              }
            }
          },
          "then": {
            "required": [
              "euler_p",
              "euler_q",
              "euler_strict"
            ],
            "maxProperties": 4
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "KAKDecomposition"
              }
            }
          },
          "then": {
            "required": [
              "fidelity",
              "allow_swaps",
              "target_2qb_gate"
            ],
            "maxProperties": 4
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "FullPeepholeOptimise"
              }
            }
          },
          "then": {
            "required": [
              "allow_swaps",
              "target_2qb_gate"
            ],
            "maxProperties": 3
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "PeepholeOptimise2Q"
              }
            }
          },
          "then": {
            "required": [
              "allow_swaps"
            ],
            "maxProperties": 2
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "ComposePhasePolyBoxes"
              }
            }
          },
          "then": {
            "required": [
              "min_size"
            ],
            "maxProperties": 2
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "CliffordSimp"
              }
            }
          },
          "then": {
            "required": [
              "allow_swaps",
              "target_2qb_gate"
            ],
            "maxProperties": 3
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "ThreeQubitSquash"
              }
            }
          },
          "then": {
            "required": [
              "allow_swaps"
            ],
            "maxProperties": 2
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "OptimisePhaseGadgets"
              }
            }
          },
          "then": {
            "required": [
              "cx_config"
            ],
            "maxProperties": 2
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "PauliSimp"
              }
            }
          },
          "then": {
            "required": [
              "pauli_synth_strat",
              "cx_config"
            ],
            "maxProperties": 3
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "PauliExponentials"
              }
            }
          },
          "then": {
            "required": [
              "pauli_synth_strat",
              "cx_config"
            ],
            "maxProperties": 3
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "GuidedPauliSimp"
              }
            }
          },
          "then": {
            "required": [
              "pauli_synth_strat",
              "cx_config"
            ],
            "maxProperties": 3
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "SimplifyInitial"
              }
            }
          },
          "then": {
            "required": [
              "allow_classical",
              "create_all_qubits"
            ],
            "$comment": "TODO We need to make sure that the optional parameter must be x_circuit",
            "maxProperties": 4
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "FlattenRelabelRegistersPass"
              }
            }
          },
          "then": {
            "required": [
              "label",
              "relabel_classical_registers"
            ],
            "maxProperties": 3
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "RenameQubitsPass"
              }
            }
          },
          "then": {
            "required": [
              "qubit_map"
            ],
            "maxProperties": 2
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "PlacementPass"
              }
            }
          },
          "then": {
            "required": [
              "placement"
            ],
            "maxProperties": 2
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "NaivePlacementPass"
              }
            }
          },
          "then": {
            "required": [
              "architecture"
            ],
            "maxProperties": 2
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "CustomRoutingPass"
              }
            }
          },
          "then": {
            "required": [
              "architecture",
              "routing_config"
            ],
            "maxProperties": 3
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "RoutingPass"
              }
            }
          },
          "then": {
            "required": [
              "architecture",
              "routing_config"
            ],
            "maxProperties": 3
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "DecomposeSwapsToCXs"
              }
            }
          },
          "then": {
            "required": [
              "architecture",
              "directed"
            ],
            "maxProperties": 3
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "DecomposeSwapsToCircuit"
              }
            }
          },
          "then": {
            "required": [
              "swap_replacement"
            ],
            "maxProperties": 2
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "FullMappingPass"
              }
            }
          },
          "then": {
            "required": [
              "architecture",
              "placement",
              "routing_config"
            ],
            "maxProperties": 4
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "DefaultMappingPass"
              }
            }
          },
          "then": {
            "required": [
              "architecture",
              "delay_measures"
            ],
            "maxProperties": 3
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "CXMappingPass"
              }
            }
          },
          "then": {
            "required": [
              "architecture",
              "placement",
              "routing_config",
              "directed",
              "delay_measures"
            ],
            "maxProperties": 6
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "PauliSquash"
              }
            }
          },
          "then": {
            "required": [
              "pauli_synth_strat",
              "cx_config"
            ],
            "maxProperties": 3
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "ContextSimp"
              }
            }
          },
          "then": {
            "required": [
              "allow_classical",
              "x_circuit"
            ],
            "maxProperties": 3
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "DelayMeasures"
              }
            }
          },
          "then": {
            "required": [
              "allow_partial"
            ],
            "maxProperties": 2
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "RoundAngles"
              }
            }
          },
          "then": {
            "required": [
              "n",
              "only_zeros"
            ],
            "maxProperties": 3
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "DecomposeBoxes"
              }
            }
          },
          "then": {
            "required": [
              "excluded_types",
              "excluded_opgroups"
            ],
            "maxProperties": 3
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "const": "GreedyPauliSimp"
              }
            }
          },
          "then": {
            "required": [
              "discount_rate",
              "depth_weight",
              "max_lookahead",
              "max_tqe_candidates",
              "seed",
              "allow_zzphase",
              "thread_timeout",
              "only_reduce",
              "trials"
            ],
            "maxProperties": 10
          }
        },
        {
          "if": {
            "properties": {
              "name": {
                "$comment": "List all non-parametrized passes",
                "enum": [
                  "CommuteThroughMultis",
                  "DecomposeArbitrarilyControlledGates",
                  "DecomposeMultiQubitsCX",
                  "DecomposeSingleQubitsTK1",
                  "RebaseTket",
                  "RebaseUFR",
                  "RemoveRedundancies",
                  "SynthesiseTK",
                  "SynthesiseTket",
                  "SynthesiseOQC",
                  "SquashTK1",
                  "SquashRzPhasedX",
                  "FlattenRegisters",
                  "ZZPhaseToRz",
                  "RemoveDiscarded",
                  "SimplifyMeasured",
                  "RemoveBarriers",
                  "RemovePhaseOps",
                  "DecomposeBridges",
                  "RxFromSX"
                ]
              }
            }
          },
          "then": {
            "maxProperties": 1
          }
        }
      ],
      "additionalProperties": false
    },
    "SequencePass": {
      "type": "object",
      "description": "Additional content to describe a compiler pass that executes as a sequence of passes in order.",
      "properties": {
        "sequence": {
          "type": "array",
          "items": {
            "$ref": "#"
          },
          "description": "The passes to be executed in order."
        }
      },
      "required": [
        "sequence"
      ],
      "additionalProperties": false
    },
    "RepeatPass": {
      "type": "object",
      "description": "Additional content to describe a compiler pass that iterates another to a fixpoint.",
      "properties": {
        "body": {
          "$ref": "#",
          "description": "The body of the loop, to be iterated until no further change."
        }
      },
      "required": [
        "body"
      ],
      "additionalProperties": false
    },
    "RepeatWithMetricPass": {
      "type": "object",
      "description": "Additional content to describe a compiler pass that iterates another whilst some metric decreases.",
      "properties": {
        "body": {
          "$ref": "#",
          "description": "The body of the loop."
        },
        "metric": {
          "type": "string",
          "description": "The metric that conditions the loop, stored as a dill string of the python function."
        }
      },
      "required": [
        "body",
        "metric"
      ],
      "additionalProperties": false
    },
    "RepeatUntilSatisfiedPass": {
      "type": "object",
      "description": "Additional content to describe a compiler pass that iterates another until some predicate is satisfied.",
      "properties": {
        "body": {
          "$ref": "#",
          "description": "The body of the loop."
        },
        "predicate": {
          "$ref": "predicate_v1.json#",
          "description": "The predicate that conditions the loop. The loop is terminated when this predicate returns True."
        }
      },
      "required": [
        "body",
        "predicate"
      ],
      "additionalProperties": false
    },
    "routingmethod": {
      "type": "object",
      "description": "A method used during circuit mapping.",
      "properties": {
        "name": {
          "type": "string",
          "description": "Name of method."
        }
      }
    },
    "routing_config": {
      "type": "array",
      "description": "A configuration for routing defined by an array of RoutingMethod.",
      "items": {
        "$ref": "#/definitions/routingmethod"
      }
    }
  }
}
