class_docstr: A circuit-cutting distribution policy for executing (large) circuits on available (comparably
  smaller) devices.
  
  .. note::
  
      This class is part of a work-in-progress feature to support automatic cut placement in the
      circuit cutting workflow. Currently only manual placement of cuts is supported,
      check out the :func:`qml.cut_circuit() <pennylane.cut_circuit>` transform for more details.
  
  Args:
      devices (Union[qml.Device, Sequence[qml.Device]]): Single, or Sequence of, device(s).
          Optional only when ``max_free_wires`` is provided.
      max_free_wires (int): Number of wires for the largest available device. Optional only when
          ``devices`` is provided where it defaults to the maximum number of wires among
          ``devices``.
      min_free_wires (int): Number of wires for the smallest available device, or, equivalently,
          the smallest max fragment-wire-size that the partitioning is allowed to explore.
          When provided, this parameter will be used to derive an upper-bound to the range of
          explored number of fragments.  Optional, defaults to 2 which corresponds to attempting
          the most granular partitioning of max 2-wire fragments.
      num_fragments_probed (Union[int, Sequence[int]]): Single, or 2-Sequence of, number(s)
          specifying the potential (range of) number of fragments for the partitioner to attempt.
          Optional, defaults to probing all valid strategies derivable from the circuit and
          devices. When provided, has precedence over all other arguments affecting partitioning
          exploration, such as ``max_free_wires``, ``min_free_wires``, or ``exhaustive``.
      max_free_gates (int): Maximum allowed circuit depth for the deepest available device.
          Optional, defaults to unlimited depth.
      min_free_gates (int): Maximum allowed circuit depth for the shallowest available device.
          Optional, defaults to ``max_free_gates``.
      imbalance_tolerance (float): The global maximum allowed imbalance for all partition trials.
          Optional, defaults to unlimited imbalance. Used only if there's a known hard balancing
          constraint on the partitioning problem.
      trials_per_probe (int): Number of repeated partitioning trials for a random automatic
          cutting method to attempt per set of partitioning parameters. For a deterministic
          cutting method, this can be set to 1. Defaults to 4.
  
  **Example**
  
  The following cut strategy specifies that a circuit should be cut into between
  ``2`` to ``5`` fragments, with each fragment having at most ``6`` wires and
  at least ``4`` wires:
  
  >>> cut_strategy = qml.transforms.CutStrategy(
  ...     max_free_wires=6,
  ...     min_free_wires=4,
  ...     num_fragments_probed=(2, 5),
  ... )
class_docstr_tok: ["A","circuit-cutting","distribution","policy","for","executing","(","large",")","circuits","on","available","(","comparably","smaller",")","devices",".","..","note",":",":","This","class","is","part","of","a","work-in-progress","feature","to","support","automatic","cut","placement","in","the","circuit","cutting","workflow",".","Currently","only","manual","placement","of","cuts","is","supported",",","check","out","the",":","func",":","`","qml.cut_circuit","(",")","<","pennylane.cut_circuit",">","`","transform","for","more","details",".","Args",":","devices","(","Union","[","qml.Device",",","Sequence","[","qml.Device","]","]",")",":","Single",",","or","Sequence","of",",","device","(","s",")",".","Optional","only","when","``","max_free_wires","``","is","provided",".","max_free_wires","(","int",")",":","Number","of","wires","for","the","largest","available","device",".","Optional","only","when","``","devices","``","is","provided","where","it","defaults","to","the","maximum","number","of","wires","among","``","devices","``",".","min_free_wires","(","int",")",":","Number","of","wires","for","the","smallest","available","device",",","or",",","equivalently",",","the","smallest","max","fragment-wire-size","that","the","partitioning","is","allowed","to","explore",".","When","provided",",","this","parameter","will","be","used","to","derive","an","upper-bound","to","the","range","of","explored","number","of","fragments",".","Optional",",","defaults","to","2","which","corresponds","to","attempting","the","most","granular","partitioning","of","max","2-wire","fragments",".","num_fragments_probed","(","Union","[","int",",","Sequence","[","int","]","]",")",":","Single",",","or","2-Sequence","of",",","number","(","s",")","specifying","the","potential","(","range","of",")","number","of","fragments","for","the","partitioner","to","attempt",".","Optional",",","defaults","to","probing","all","valid","strategies","derivable","from","the","circuit","and","devices",".","When","provided",",","has","precedence","over","all","other","arguments","affecting","partitioning","exploration",",","such","as","``","max_free_wires","``",",","``","min_free_wires","``",",","or","``","exhaustive","``",".","max_free_gates","(","int",")",":","Maximum","allowed","circuit","depth","for","the","deepest","available","device",".","Optional",",","defaults","to","unlimited","depth",".","min_free_gates","(","int",")",":","Maximum","allowed","circuit","depth","for","the","shallowest","available","device",".","Optional",",","defaults","to","``","max_free_gates","``",".","imbalance_tolerance","(","float",")",":","The","global","maximum","allowed","imbalance","for","all","partition","trials",".","Optional",",","defaults","to","unlimited","imbalance",".","Used","only","if","there","'s","a","known","hard","balancing","constraint","on","the","partitioning","problem",".","trials_per_probe","(","int",")",":","Number","of","repeated","partitioning","trials","for","a","random","automatic","cutting","method","to","attempt","per","set","of","partitioning","parameters",".","For","a","deterministic","cutting","method",",","this","can","be","set","to","1",".","Defaults","to","4",".","*","*","Example","*","*","The","following","cut","strategy","specifies","that","a","circuit","should","be","cut","into","between","``","2","``","to","``","5","``","fragments",",","with","each","fragment","having","at","most","``","6","``","wires","and","at","least","``","4","``","wires",":",">",">",">","cut_strategy","=","qml.transforms.CutStrategy","(","...","max_free_wires=6",",","...","min_free_wires=4",",","...","num_fragments_probed=","(","2",",","5",")",",","...",")"]
docstr: Helper function for deriving the minimal set of best default partitioning constraints
  for the graph partitioner.
  
  Args:
      num_tape_wires (int): Number of wires in the circuit tape to be partitioned.
      num_tape_gates (int): Number of gates in the circuit tape to be partitioned.
      max_wires_by_fragment (Sequence[int]): User-predetermined list of wire limits by
          fragment. If supplied, the number of fragments will be derived from it and
          exploration of other choices will not be made.
      max_gates_by_fragment (Sequence[int]): User-predetermined list of gate limits by
          fragment. If supplied, the number of fragments will be derived from it and
          exploration of other choices will not be made.
      exhaustive (bool): Toggle for an exhaustive search which will attempt all potentially
          valid numbers of fragments into which the circuit is partitioned. If ``True``,
          ``num_tape_gates - 1`` attempts will be made with ``num_fragments`` ranging from
          [2, ``num_tape_gates``], i.e. from bi-partitioning to complete partitioning where
          each fragment has exactly a single gate. Defaults to ``True``.
  
  Returns:
      List[Dict[str, Any]]: A list of minimal set of kwargs being passed to a graph
          partitioner method.
docstr_tok: ["Helper","function","for","deriving","the","minimal","set","of","best","default","partitioning","constraints","for","the","graph","partitioner",".","Args",":","num_tape_wires","(","int",")",":","Number","of","wires","in","the","circuit","tape","to","be","partitioned",".","num_tape_gates","(","int",")",":","Number","of","gates","in","the","circuit","tape","to","be","partitioned",".","max_wires_by_fragment","(","Sequence","[","int","]",")",":","User-predetermined","list","of","wire","limits","by","fragment",".","If","supplied",",","the","number","of","fragments","will","be","derived","from","it","and","exploration","of","other","choices","will","not","be","made",".","max_gates_by_fragment","(","Sequence","[","int","]",")",":","User-predetermined","list","of","gate","limits","by","fragment",".","If","supplied",",","the","number","of","fragments","will","be","derived","from","it","and","exploration","of","other","choices","will","not","be","made",".","exhaustive","(","bool",")",":","Toggle","for","an","exhaustive","search","which","will","attempt","all","potentially","valid","numbers","of","fragments","into","which","the","circuit","is","partitioned",".","If","``","True","``",",","``","num_tape_gates","-","1","``","attempts","will","be","made","with","``","num_fragments","``","ranging","from","[","2",",","``","num_tape_gates","``","]",",","i.e",".","from","bi-partitioning","to","complete","partitioning","where","each","fragment","has","exactly","a","single","gate",".","Defaults","to","``","True","``",".","Returns",":","List","[","Dict","[","str",",","Any","]","]",":","A","list","of","minimal","set","of","kwargs","being","passed","to","a","graph","partitioner","method","."]
code: def _infer_probed_cuts(
      self,
      wire_depths,
      max_wires_by_fragment=None,
      max_gates_by_fragment=None,
      exhaustive=True,
  ) -> List[Dict[str, Any]]:
      """
      Helper function for deriving the minimal set of best default partitioning constraints
      for the graph partitioner.
  
      Args:
          num_tape_wires (int): Number of wires in the circuit tape to be partitioned.
          num_tape_gates (int): Number of gates in the circuit tape to be partitioned.
          max_wires_by_fragment (Sequence[int]): User-predetermined list of wire limits by
              fragment. If supplied, the number of fragments will be derived from it and
              exploration of other choices will not be made.
          max_gates_by_fragment (Sequence[int]): User-predetermined list of gate limits by
              fragment. If supplied, the number of fragments will be derived from it and
              exploration of other choices will not be made.
          exhaustive (bool): Toggle for an exhaustive search which will attempt all potentially
              valid numbers of fragments into which the circuit is partitioned. If ``True``,
              ``num_tape_gates - 1`` attempts will be made with ``num_fragments`` ranging from
              [2, ``num_tape_gates``], i.e. from bi-partitioning to complete partitioning where
              each fragment has exactly a single gate. Defaults to ``True``.
  
      Returns:
          List[Dict[str, Any]]: A list of minimal set of kwargs being passed to a graph
              partitioner method.
      """
  
      num_tape_wires = len(wire_depths)
      num_tape_gates = int(sum(wire_depths.values()))
  
      # Assumes unlimited width/depth if not supplied.
      max_free_wires = self.max_free_wires or num_tape_wires
      max_free_gates = self.max_free_gates or num_tape_gates
  
      # Assumes same number of wires/gates across all devices if min_free_* not provided.
      min_free_wires = self.min_free_wires or max_free_wires
      min_free_gates = self.min_free_gates or max_free_gates
  
      # The lower bound of k corresponds to executing each fragment on the largest available
      # device.
      k_lb = 1 + max(
          (num_tape_wires - 1) // max_free_wires,  # wire limited
          (num_tape_gates - 1) // max_free_gates,  # gate limited
      )
      # The upper bound of k corresponds to executing each fragment on the smallest available
      # device.
      k_ub = 1 + max(
          (num_tape_wires - 1) // min_free_wires,  # wire limited
          (num_tape_gates - 1) // min_free_gates,  # gate limited
      )
  
      if exhaustive:
          k_lb = max(2, k_lb)
          k_ub = num_tape_gates
  
      # The global imbalance tolerance, if not given, defaults to a very loose upper bound:
      imbalance_tolerance = (
          k_ub
          if self.imbalance_tolerance is None
          else self.imbalance_tolerance
      )
  
      probed_cuts = []
  
      if (
          max_gates_by_fragment is None
          and max_wires_by_fragment is None
      ):
          # k_lower, when supplied by a user, can be higher than k_lb if the the desired k is known:
          k_lower = self.k_lower if self.k_lower is not None else k_lb
          # k_upper, when supplied by a user, can be higher than k_ub to encourage exploration:
          k_upper = self.k_upper if self.k_upper is not None else k_ub
  
          if k_lower < k_lb:
              warnings.warn(
                  f"The provided `k_lower={k_lower}` is less than the lowest allowed value, "
                  f"will override and set `k_lower={k_lb}`."
              )
              k_lower = k_lb
  
          if k_lower > self.HIGH_NUM_FRAGMENTS:
              warnings.warn(
                  f"The attempted number of fragments seems high with lower bound at {k_lower}."
              )
  
          # Prepare the list of ks to explore:
          ks = list(range(k_lower, k_upper + 1))
  
          if len(ks) > self.HIGH_PARTITION_ATTEMPTS:
              warnings.warn(
                  f"The numer of partition attempts seems high ({len(ks)})."
              )
      else:
          # When the by-fragment wire and/or gate limits are supplied, derive k and imbalance and
          # return a single partition config.
          ks = [len(max_wires_by_fragment or max_gates_by_fragment)]
  
      for k in ks:
          imbalance = self._infer_imbalance(
              k,
              wire_depths,
              max_free_wires
              if max_wires_by_fragment is None
              else max(max_wires_by_fragment),
              max_free_gates
              if max_gates_by_fragment is None
              else max(max_gates_by_fragment),
              imbalance_tolerance,
          )
          cut_kwargs = {
              "num_fragments": k,
              "imbalance": imbalance,
          }
          if max_wires_by_fragment is not None:
              cut_kwargs[
                  "max_wires_by_fragment"
              ] = max_wires_by_fragment
          if max_gates_by_fragment is not None:
              cut_kwargs[
                  "max_gates_by_fragment"
              ] = max_gates_by_fragment
  
          probed_cuts.append(cut_kwargs)
  
      return probed_cuts
  
file_path: pennylane/pennylane/qcut/cutstrategy.py
imports: import warnings
  from collections.abc import Sequence
  from dataclasses import InitVar, dataclass
  from typing import Any, ClassVar, Dict, List, Sequence, Union
  from networkx import MultiDiGraph
  import pennylane
  from pennylane.ops.meta import WireCut
label_desc: Use image node_id 5 for calling the CutStrategy obj's underlying member method code with example usage: obj._infer_probed_cuts(wire_depths, max_wires_by_fragment, max_gates_by_fragment, exhaustive) and returns: probed_cuts