# Path: fedjax/core/typing.py



import math
import jax
import jax.numpy as jnp
import scipy
from typing import Tuple, Union
from fedjax.core.typing import PRNGKey, Params
  hadamards = dict((d, hadamard_matrix(d, x.dtype)) for d in set(shape))

  # einsum on each dimension.
  for i, d in enumerate(shape):
    y_dims = ''.join(str(j) for j in range(num_dims))
    h_dims = f'{i}{num_dims + 1}'
    out_dims = y_dims.replace(str(i), str(num_dims + 1), 1)
    operands = f'{y_dims},{h_dims}->{out_dims}'
    y = jnp.einsum(operands, y, hadamards[d], precision=precision)
  return y.flatten()


def hadamard_matrix(n: int, dtype: jnp.dtype) -> jnp.ndarray:
  """Generates the Hadamard matrix.

  Because there are JAX dtypes not supported in numpy, the equivalent function
  in scipy can't be used directly.

  Args:
    n: Number of rows/columns of the Hadamard matrix. Must be a power of 2.
    dtype: Output dtype.

  Returns:
    The Hadamard matrix of the given size and type.
  """
  return jnp.array(scipy.linalg.hadamard(n), dtype)


@jax.jit
def structured_rotation(x: jnp.ndarray,

# Path: fedjax/core/typing.py



# Path: fedjax/aggregators/walsh_hadamard.py
import math
import jax
import jax.numpy as jnp
import scipy
from typing import Tuple, Union
from fedjax.core.typing import PRNGKey, Params

  hadamards = dict((d, hadamard_matrix(d, x.dtype)) for d in set(shape))

  # einsum on each dimension.
  for i, d in enumerate(shape):
    y_dims = ''.join(str(j) for j in range(num_dims))
    h_dims = f'{i}{num_dims + 1}'
    out_dims = y_dims.replace(str(i), str(num_dims + 1), 1)
    operands = f'{y_dims},{h_dims}->{out_dims}'
    y = jnp.einsum(operands, y, hadamards[d], precision=precision)
  return y.flatten()


def hadamard_matrix(n: int, dtype: jnp.dtype) -> jnp.ndarray:
  """Generates the Hadamard matrix.

  Because there are JAX dtypes not supported in numpy, the equivalent function
  in scipy can't be used directly.

  Args:
    n: Number of rows/columns of the Hadamard matrix. Must be a power of 2.
    dtype: Output dtype.

  Returns:
    The Hadamard matrix of the given size and type.
  """
  return jnp.array(scipy.linalg.hadamard(n), dtype)


@jax.jit
def structured_rotation(x: jnp.ndarray,

                        rng: PRNGKey) -> Tuple[jnp.ndarray, jnp.ndarray]: