
    AVhwO                        d Z ddlZddlZddlZddlmZmZmZmZ ddl	Z
ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ dd	lmZ d
ZdZdZ edg       j3                  ed        edg       j3                  ed        ej6                  dddg      Zdee   dee   fdZ edg        G d dej>                               Zej@                  Z  edg        G d dejB                               Z!y)z+Python definitions for `Mesh` and `Layout`.    N)ListDictOptionalUnion)
layout_pb2)_pywrap_dtensor_device)device)ops)tensor)	tf_export	unshardedmatchFzexperimental.dtensor.UNSHARDED)v1	UNSHARDEDzexperimental.dtensor.MATCHMATCHMeshDimensionnamesizeshapereturnc                     dg}t        t        | dd              D ]  \  }}|j                  ||   |z          |j                          |S )N   )	enumeratereversedappendreverse)r   stridesidxdim_sizes       P/home/dcms/DCMS/lib/python3.12/site-packages/tensorflow/dtensor/python/layout.py_compute_mesh_stridesr!   -   sP    C' %)!45 ,mc8NN73<(*+,	//	.    zexperimental.dtensor.Meshc                   6    e Zd ZdZddefdee   dej                  dee	   dee
ej                  ef      ded	eee
ej                  ef         d
ef fdZe fd       Zdej                  f fdZdedefdZd ZdefdZd Zde	dej2                  fdZedej8                  dd fd       Zededd fd       Zededd fd       Zede jB                  fd       Z"e#jH                  d# fd       Z%d#dZ&dee'ee	f      fd Z(e)dee	   fd!       Z*d" Z+ xZ,S )$Mesha  Represents a Mesh configuration over a certain list of Mesh Dimensions.

  A mesh consists of named dimensions with sizes, which describe how a set of
  devices are arranged. Defining tensor layouts in terms of mesh dimensions
  allows us to efficiently determine the communication required when computing
  an operation with tensors of different layouts.

  A mesh provides information not only about the placement of the tensors but
  also the topology of the underlying devices. For example, we can group 8 TPUs
  as a 1-D array for data parallelism or a `2x4` grid for (2-way) data
  parallelism and (4-way) model parallelism.

  Refer to [DTensor Concepts](https://www.tensorflow.org/guide/dtensor_overview)
  for in depth discussion and examples.

  Note: the utilities `dtensor.create_mesh` and
  `dtensor.create_distributed_mesh` provide a simpler API to create meshes for
  single- or multi-client use cases.
   N	dim_namesglobal_device_idslocal_device_idslocal_devices	mesh_nameglobal_devicesuse_xla_spmdc           
         t        |t        j                        st        d      |j                  dk(  rt        d      |j                         }|d   t        fdt        |      D              rt        d|z        t        |      |j                  k7  rt        d      t        |t              st        d      t        |t              st        d      |rt        |t              st        d	      |s|st        d
      |j                         }	|j                  }
dt        fd}dt        j                  fd}|D cg c]
  } ||       }}|D cg c]
  } ||       }}|sg }|D cg c]
  } ||       }}|D cg c]
  } ||       }}t        |      }t        |      dk(  xr t        |      d   j                   dk(  }|sHt        |      t        |      k7  r1t        d|D cg c]  }|j#                  |      dkD  s| c}z        t        |      t        |      k7  rt        d      t        |      t        t        j$                  |            kD  rt        d      t        |D cg c]  }|j                    c}      }|s#t        |D cg c]  }|j                    c}      }d|v rt        d      t        |      dkD  rt        d|z        |j'                         }|r|dk7  rt        d|z        t(        | U  |||
|	||||       yc c}w c c}w c c}w c c}w c c}w c c}w c c}w )ay  Builds a Mesh.

    The `dim_names` and `global_device_ids` arguments describe the dimension
    names and shape for the mesh.

    For example,

    ```python
      dim_names = ('x', 'y'),
      global_device_ids = [[0, 1],
                           [2, 3],
                           [4, 5]]
    ```

    defines a 2D mesh of shape 3x2. A reduction over the 'x' dimension will
    reduce across columns (0, 2, 4) and (1, 3, 5), and a reduction over the 'y'
    dimension reduces across rows.

    Note: the utilities `dtensor.create_mesh` and
    `dtensor.create_distributed_mesh` provide a simpler API to create meshes for
    single- or multi-client use cases.

    Args:
      dim_names: A list of strings indicating dimension names.
      global_device_ids: An ndarray of global device IDs is used to compose
        DeviceSpecs describing the mesh. The shape of this array determines the
        size of each mesh dimension. Values in this array should increment
        sequentially from 0. This argument is the same for every DTensor client.
      local_device_ids: A list of local device IDs equal to a subset of values
        in global_device_ids. They indicate the position of local devices in the
        global mesh. Different DTensor clients must contain distinct
        local_device_ids contents. All local_device_ids from all DTensor clients
        must cover every element in global_device_ids.
      local_devices: The list of devices hosted locally. The elements correspond
        1:1 to those of local_device_ids.
      mesh_name: The name of the mesh. Currently, this is rarely used, and is
        mostly used to indicate whether it is a CPU, GPU, or TPU-based mesh.
      global_devices (optional): The list of global devices. Set when multiple
        device meshes are in use.
      use_xla_spmd (optional): Boolean when True, will use XLA SPMD instead of
        DTensor SPMD.
    z.Variable global_device_ids must be an ndarray.r   z-Variable global_device_ids must be non-empty.c              3   4   K   | ]  \  }}||z
  k7    y wN ).0igiddistances      r    	<genexpr>z Mesh.__init__.<locals>.<genexpr>   s%      O"(!SqH	Os   z0global_device_ids must sequentially increase: %szCNumber of mesh dimensions does not match number of dimension names.z5Variable local_device_ids must be a list of integers.z5Variable local_devices must be a list of DeviceSpecs.z6Variable global_devices must be a list of DeviceSpecs.z"Empty list of devices not allowed.r   c                 Z    t        | t        j                        r| j                         S | S r/   )
isinstance	tf_device
DeviceSpec	to_stringds    r    to_strzMesh.__init__.<locals>.to_str   s#    	Ay++	,{{}hr"   c                 x    t        | t        j                        st        j                  j                  |       S | S r/   )r7   r8   r9   from_stringr;   s    r    to_speczMesh.__init__.<locals>.to_spec   s.    9//0##//22hr"   r   CPUz1Duplicate devices found in mesh specification %s.zCVariable local_device_ids does not have same size as local_devices.z-Cannot have more local than gobal device IDs.Nzdevice_type is requiredz-Devices containing multiple device_types : %sTPUz4XLA SPMD is not currently not supported for %s mesh.)r7   npndarray
ValueErrorr   flattenanyr   lenndimlistr   strr8   r9   setdevice_typecountravelpopsuper__init__)selfr&   r'   r(   r)   r*   r+   r,   flat_global_device_idsglobal_device_ids_flattenglobal_device_ids_shaper=   r@   r<   local_devices_strlocal_devices_specglobal_devices_strglobal_devices_speclocal_devices_set#local_device_only_contains_host_cpur	   device_typesrM   r4   	__class__s                          @r    rR   zMesh.__init__K   s~   j '4GHH"FGG.668 &a(H
 O,56L,MO OI() * * 9~*///
OQ Q &-NOOmT*NOOj>OPP;<< !2 9 9 ;/55S 
i** 
 -::q::.;<'!*<<n-;<&)<</=>!71:>>./!# 	8"..%7 ( /3}3EJ 4J#0OaM4G4G4JQ4NOP Q Q M 22
OQ Q s288,=#>??FGG9KLv**LML;NO&,,OPl|011
<1F#$ % %""$Ku,M"# $ $ 
G!	I ;< => P MOs0   LL$3L)L.2L3
L3
9L8L=c                 l    t         j                  j                  |       }t        |   |g|i | |S r/   )r   r$   __new__rQ   rR   clsargskwargsrS   r^   s       r    _new_objectzMesh._new_object   s7     "&&..s3D	GT+D+F+Kr"   r   c                     t        j                  t        |          t         j                        j                  | j                               S )z)Returns a global device list as an array.)dtype)rC   arrayrQ   r'   int64reshaper   rS   r^   s    r    r'   zMesh.global_device_ids   s6    88EG-/rxx@HH

 r"   dim_namec                 :    t        || j                  |            S )N)r   r   )r   r   )rS   rl   s     r    __getitem__zMesh.__getitem__   s    hT]]8-DEEr"   c                 T    t        | j                         j                  d            S NT)deterministichashas_protoSerializeToStringrS   s    r    __hash__zMesh.__hash__   !    111EFFr"   c                 *    d| j                          dS )NzMesh.from_string()r:   rv   s    r    __repr__zMesh.__repr__   s    t~~/022r"   c                 D    t         j                  | j                         ffS r/   )r$   r?   r:   rv   s    r    
__reduce__zMesh.__reduce__   s    dnn.000r"   
device_idxc                     t        j                  | j                        }t        j                  | j                               }||z  |z  S )z<Converts the device index into a tensor of mesh coordinates.)r
   convert_to_tensorr   r   )rS   r   r   r   s       r    coordszMesh.coords   s<    ##DLL1G!!$**,/E'!U**r"   protoc                 &    | j                  |      S )z-Construct a mesh instance from input `proto`.)
mesh_protore   )rb   r   s     r    
from_protozMesh.from_proto  s     ??e?,,r"   mesh_strc                 &    | j                  |      S )N)r   r   )rb   r   s     r    r?   zMesh.from_string  s    ??H?--r"   r	   c                 &    | j                  |      S )z5Constructs a single device mesh from a device string.)single_devicer   rb   r	   s     r    from_devicezMesh.from_device  s     ???00r"   meshc                 &    | j                  |      S )z3Creates a copy from an existing pywrap mesh object.r   r   rb   r   s     r    
_from_meshzMesh._from_mesh       ???%%r"   c                 F    t         j                  t        |                S r/   )r$   r   rQ   	host_meshrk   s    r    
_host_meshzMesh._host_mesh  s    ??57,.//r"   c                     | j                   S )zReturns a host mesh.)r   rv   s    r    r   zMesh.host_mesh  s     ??r"   c                 n    | j                         }| j                         D cg c]  }||   	 c}S c c}w )zReturns a list of local device locations.

    A device location is a dictionary from dimension names to indices on those
    dimensions.
    )unravel_indexr(   )rS   mapping	device_ids      r    local_device_locationszMesh.local_device_locations   s4       "G040E0E0GH9GIHHHs   2c                 4    t        | j                               S )aX  Returns the strides tensor array for this mesh.

    If the mesh shape is `[a, b, c, d]`, then the strides array can be computed
    as `[b*c*d, c*d, d, 1]`. This array can be useful in computing local device
    offsets given a device ID. Using the same example, the device coordinates of
    the mesh can be computed as:

    ```
    [(device_id / (b*c*d)) % a,
     (device_id / (c*d))   % b,
     (device_id / (d))     % c,
     (device_id)           % d]
    ```

    This is the same as `(device_id // mesh.strides) % mesh.shape`.

    Returns:
      The mesh strides as an integer tensor.
    )r!   r   rv   s    r    r   zMesh.strides*  s    * !..r"   c                    | j                   D cg c]  }t        | j                  |             }}t        j                  | }i }t        |      D ]/  \  }}i }t        | j                   |      D ]
  \  }}|||<    |||<   1 |S c c}w )a1  Returns a dictionary from device ID to {dim_name: dim_index}.

    For example, for a 3x2 mesh, return this:

    ```
      { 0: {'x': 0, 'y', 0},
        1: {'x': 0, 'y', 1},
        2: {'x': 1, 'y', 0},
        3: {'x': 1, 'y', 1},
        4: {'x': 2, 'y', 0},
        5: {'x': 2, 'y', 1} }
    ```
    )r&   ranger   	itertoolsproductr   zip)	rS   rl   
idx_rangesmesh_posr   r   
device_pos
device_loc	dim_indexs	            r    r   zMesh.unravel_indexB  s     BFPX%h/0PJP  *-HG!*8!4 &	:j!$T^^Z!@ )
(I(
8)%gi	&
 N Qs   !B)r   r$   )-__name__
__module____qualname____doc__USE_XLA_SPMDr   rK   rC   rD   intr   r8   r9   r   boolrR   classmethodre   r'   r   rn   rw   r|   r~   r   Tensorr   r   	MeshProtor   r?   r   r   r$   r   	functoolscached_propertyr   r   r   r   propertyr   r   __classcell__r^   s   @r    r$   r$   5   s   4 IM'ScS S S		S
 %	 4 4c 9:;S S tE)*>*>*C$DEFS Sj   F# F- FG3 31+s +v}} + -Z11 -f - - . . . . 1s 1v 1 1 &277 & & 0 0Id4S>&: I /tCy / /.r"   r$   zexperimental.dtensor.Layoutc                       e Zd ZdZdee   def fdZe fd       Z	defdZ
d Zd	 Ze fd
       Zed        Ze	 ddededededd f
d       Zdee   dd fdZedej(                  dd fd       Zededd fd       Zd  fdZededededd fd       Zededd fd       Zededd fd       Zd Zd Zedededd fd       Z xZS )!Layouta  Represents the layout information of a DTensor.

  A layout describes how a distributed tensor is partitioned across a mesh (and
  thus across devices). For each axis of the tensor, the corresponding
  sharding spec indicates which dimension of the mesh it is sharded over. A
  special sharding spec `UNSHARDED` indicates that axis is replicated on
  all the devices of that mesh.

  Refer to [DTensor Concepts](https://www.tensorflow.org/guide/dtensor_overview)
  for in depth discussion and examples.

  For example, let's consider a 1-D mesh:

  ```
  Mesh(["TPU:0", "TPU:1", "TPU:2", "TPU:3", "TPU:4", "TPU:5"], [("x", 6)])
  ```

  This mesh arranges 6 TPU devices into a 1-D array. `Layout([UNSHARDED], mesh)`
  is a layout for rank-1 tensor which is replicated on the 6 devices.

  For another example, let's consider a 2-D mesh:

  ```
  Mesh(["TPU:0", "TPU:1", "TPU:2", "TPU:3", "TPU:4", "TPU:5"],
       [("x", 3), ("y", 2)])
  ```

  This mesh arranges 6 TPU devices into a `3x2` 2-D array.
  `Layout(["x", UNSHARDED], mesh)` is a layout for rank-2 tensor whose first
  axis is sharded on mesh dimension "x" and the second axis is replicated. If we
  place `np.arange(6).reshape((3, 2))` using this layout, the individual
  components tensors would look like:

  ```
  Device  |  Component
   TPU:0     [[0, 1]]
   TPU:1     [[0, 1]]
   TPU:2     [[2, 3]]
   TPU:3     [[2, 3]]
   TPU:4     [[4, 5]]
   TPU:5     [[4, 5]]
  ```
  sharding_specsr   c                 f   t        |t              st        d      t        |      D ]g  \  }}|t        k(  s	|t
        k(  r|j                  |      dkD  rt        dj                  ||            ||vsNt        dj                  |             t        | %  t        j                  ||       y)	a  Builds a Layout from a list of dimension names and a Mesh.

    Args:
      sharding_specs: List of sharding specifications, each corresponding to a
        tensor axis. Each specification (dim_sharding) can either be a mesh
        dimension or the special value UNSHARDED.
      mesh: A mesh configuration for the Tensor.

    Returns:
      A valid Layout built with given layout & mesh.
    z mesh is not a valid Mesh object.r   z~Mesh dimension {mesh_dim} was repeated in sharding specification {sharding_specs}. Mesh dimensions must be unique in a layout.)mesh_dimr   zX{dim_sharding}: A dimension sharding must either be a valid mesh dimension or UNSHARDED.)dim_sharding)typer   r   N)r7   r$   rE   r   r   r   rN   formatrQ   rR   
LayoutTypeSTATIC)rS   r   r   _r   r^   s        r    rR   zLayout.__init__  s     dD!9:: %^4 -<		"le&;			l	+a	/#V&~ $ GH 	H 
T	!2396* 4: 4,- 	--$ 
G~D  r"   c                 l    t         j                  j                  |       }t        |   |g|i | |S r/   )r   r   r`   rQ   rR   ra   s       r    re   zLayout._new_object  s7     "((005D	GT+D+F+Kr"   r   c                 *    d| j                          dS )NzLayout.from_string(rz   r{   rv   s    r    r|   zLayout.__repr__  s     !1 2!44r"   c                 T    t        | j                         j                  d            S rp   rr   rv   s    r    rw   zLayout.__hash__  rx   r"   c                 D    t         j                  | j                         ffS r/   )r   r?   r:   rv   s    r    r~   zLayout.__reduce__  s     0222r"   c                 @    t         j                  t        |         S )Nr   )r$   r   rQ   r   rk   s    r    r   zLayout.mesh  s    ???--r"   c                 6    | j                   j                         S r/   )r   r   rv   s    r    r   zLayout.shape  s    99??r"   	batch_dimrankaxisc                 ,    | j                  ||||      S )z,Returns a layout sharded on batch dimension.)r   r   r   r   r   )rb   r   r   r   r   s        r    batch_shardedzLayout.batch_sharded  s&    
 ??   r"   dimsc                     t        |t              s|g}t        | j                        D cg c]  \  }}||vs| }}}t	        || j
                        S c c}}w )z4Returns the layout with the give dimensions deleted.)r7   rJ   r   r   r   r   )rS   r   r2   spec	new_specss        r    deletezLayout.delete  sZ    dD!Vd%d&9&9:DatmI  )TYY''s
   AAlayout_protoc                 &    | j                  |      S )z'Creates an instance from a LayoutProto.)r   r   )rb   r   s     r    r   zLayout.from_proto  s     ???55r"   
layout_strc                 &    | j                  |      S )z1Creates an instance from a human-readable string.)r   r   )rb   r   s     r    r?   zLayout.from_string  s     ??j?11r"   c                 H    t         j                  t        |                S )zReturns a "parted" layout from a static layout.

    A parted layout contains axes that are treated as independent by most of
    SPMD expanders.

    FIXME(b/285905569): The exact semantics is still being investigated.
    )layout)r   re   rQ   	to_partedrk   s    r    r   zLayout.to_parted  s!     UW%6%899r"   	inner_dimc                 2    | j                  ||||dz
        S )z,Returns a layout sharded on inner dimension.r   )r   )r   )rb   r   r   r   s       r    inner_shardedzLayout.inner_sharded  s"     T9dBBr"   c                 &    | j                  |      S )<Constructs a single device layout from a single device mesh.r   r   r   s     r    from_single_device_meshzLayout.from_single_device_mesh  r   r"   r	   c                 J    | j                  t        j                  |            S )r   )r   r$   r   r   s     r    r   zLayout.from_device  s      &&t'7'7'?@@r"   c                 >   | j                   j                         }dg| j                   j                  z  }|j                         D ]U  \  }}g }| j                  D ]1  }|t
        k(  r|j                  d       |j                  ||          3 t        |      ||<   W |S )z7Mapping from offset in a flattened list to shard index.Nr   )r   r   r   itemsr   r   r   tuple)rS   r   	locationsoffsetmesh_loclocr   s          r    offset_to_shardzLayout.offset_to_shard	  s    II++-M'I)//1 %c-- -,9$
**Q-
**Xl+
,	-
  *i% r"   c                     d}t        |      D ]A  \  }}d}t        |dz   | j                        D ]  }|| j                  |      z  } |||z  z   }C |S )z.Mapping from offset to index in global tensor.r   r   )r   r   r   
num_shards)rS   offset_tupleindexr2   omxs          r    offset_tuple_to_global_indexz#Layout.offset_tuple_to_global_index  si    E,' 1
aQUDII& #!""#a!eme	
 Lr"   c                 (    | j                  ||      S )z+Returns a replicated layout of rank `rank`.)r   r   r   )rb   r   r   s      r    
replicatedzLayout.replicated#  s     ??4?00r"   )r   )r   r   )r   r   r   r   r   rK   r$   rR   r   re   r|   rw   r~   r   r   r   r   r   r   r   LayoutProtor   r?   r   r   r   r   r   r   r   r   r   s   @r    r   r   _  s   *X%T#Y %d %N  5 5G3 . .   >?

"%
-0
8;

 
(c (x ( 6J$:$: 6x 6 6 23 28 2 2: Ct C C3 C8 C C & &( & & As Ax A A
  1D 1 1 1 1r"   r   )"r   collectionsr   r   typingr   r   r   r   numpyrC   tensorflow.dtensor.protor   tensorflow.pythonr   tensorflow.python.frameworkr	   r8   r
   r    tensorflow.python.util.tf_exportr   r   r   r   export_constantr   
namedtupler   r   r!   r$   r   r   r0   r"   r    <module>r      s   2    . .  / 4 ; + . 6 	 	$	?8[1 	 R))87)K&&&8HIc tCy  &2.b!&& b /bJ	 $..
 (R0F1#** F1 1F1r"   