




'''simple docstring'''





import os
from dataclasses import dataclass, field
from io import BytesIO
from typing import TYPE_CHECKING, Any, ClassVar, Dict, Optional, Union

import numpy as np
import pyarrow as pa

from .. import config
from ..download.streaming_download_manager import xopen, xsplitext
from ..table import array_cast
from ..utils.py_utils import no_op_if_value_is_null, string_to_dict


if TYPE_CHECKING:
		from .features import FeatureType


_SCREAMING_SNAKE_CASE		, _SCREAMING_SNAKE_CASE		, _SCREAMING_SNAKE_CASE							:       List[Any]						=			False, False, False




@dataclass
class 			_snake_case		:
			lowerCAmelCase_					:				Optional[int]							=   None
			lowerCAmelCase_					:				bool							=   True
			lowerCAmelCase_					:				bool							=   True
			lowerCAmelCase_					:				Optional[str]							=   None
			# Automatically constructed
			lowerCAmelCase_					:				ClassVar[str]							=   "dict"
			lowerCAmelCase_					:				ClassVar[Any]							=   pa.struct({"bytes": pa.binary(), "path": pa.string()}							)
			lowerCAmelCase_					:				str							=   field(default="Audio"						,						init=lowercase_						,						repr=lowercase_							)




			def __call__( self							)    ->    Tuple:

										'''simple docstring'''




										return self.pa_type




			def        lowerCAmelCase__    ( self    ,							a__							)    ->    dict:

										'''simple docstring'''




										try:
																	import soundfile as sf  # soundfile is a dependency of librosa, needed to decode audio files.
										except ImportError as err:
																	raise ImportError("To support encoding audio data, please install 'soundfile'."							) from err
										if isinstance(a__    ,							a__							):
																	return {"bytes": None, "path": value}
										elif isinstance(a__    ,							a__							):
																	return {"bytes": value, "path": None}
										elif "array" in value:
																	# convert the audio array to wav bytes
																	snake_case_      =				BytesIO()
																	sf.write(a__    ,							value["array"]    ,							value["sampling_rate"]    ,							format="wav"							)
																	return {"bytes": buffer.getvalue(), "path": None}
										elif value.get("path"							) is not None and os.path.isfile(value["path"]							):
																	# we set "bytes": None to not duplicate the data if they're already available locally
																	if value["path"].endswith("pcm"							):
																								# "PCM" only has raw audio bytes
																								if value.get("sampling_rate"							) is None:
																															# At least, If you want to convert "PCM-byte" to "WAV-byte", you have to know sampling rate
																															raise KeyError("To use PCM files, please specify a 'sampling_rate' in Audio object"							)
																								if value.get("bytes"							):
																															# If we already had PCM-byte, we don`t have to make "read file, make bytes" (just use it!)
																															snake_case_      =				np.frombuffer(value["bytes"]    ,							dtype=np.intaa							).astype(np.floataa							) / 32_767
																								else:
																															snake_case_      =				np.memmap(value["path"]    ,							dtype="h"    ,							mode="r"							).astype(np.floataa							) / 32_767

																								snake_case_      =				BytesIO(bytes()							)
																								sf.write(a__    ,							a__    ,							value["sampling_rate"]    ,							format="wav"							)
																								return {"bytes": buffer.getvalue(), "path": None}
																	else:
																								return {"bytes": None, "path": value.get("path"							)}
										elif value.get("bytes"							) is not None or value.get("path"							) is not None:
																	# store the audio bytes, and path is used to infer the audio format using the file extension
																	return {"bytes": value.get("bytes"							), "path": value.get("path"							)}
										else:
																	raise ValueError(
																	    F'An audio sample should have one of \'path\' or \'bytes\' but they are missing or None in {value}.'							)




			def        lowerCAmelCase__    ( self    ,							a__    ,							a__ = None							)    ->    dict:

										'''simple docstring'''




										if not self.decode:
																	raise RuntimeError("Decoding is disabled for this feature. Please use Audio(decode=True) instead."							)

										snake_case_ ,				snake_case_      =				(value["path"], BytesIO(value["bytes"]							)) if value["bytes"] is not None else (value["path"], None)
										if path is None and file is None:
																	raise ValueError(F'An audio sample should have one of \'path\' or \'bytes\' but both are None in {value}.'							)

										try:
																	import librosa
																	import soundfile as sf
										except ImportError as err:
																	raise ImportError("To support decoding audio files, please install 'librosa' and 'soundfile'."							) from err

										snake_case_      =				xsplitext(a__							)[1][1:].lower() if path is not None else None
										if not config.IS_OPUS_SUPPORTED and audio_format == "opus":
																	raise RuntimeError(
																	    "Decoding 'opus' files requires system library 'libsndfile'>=1.0.31, "
																	    "You can try to update `soundfile` python library: `pip install \"soundfile>=0.12.1\"`. "							)
										elif not config.IS_MP3_SUPPORTED and audio_format == "mp3":
																	raise RuntimeError(
																	    "Decoding 'mp3' files requires system library 'libsndfile'>=1.1.0, "
																	    "You can try to update `soundfile` python library: `pip install \"soundfile>=0.12.1\"`. "							)

										if file is None:
																	snake_case_      =				token_per_repo_id or {}
																	snake_case_      =				path.split("::"							)[-1]
																	try:
																								snake_case_      =				string_to_dict(a__    ,							config.HUB_DATASETS_URL							)["repo_id"]
																								snake_case_      =				token_per_repo_id[repo_id]
																	except (ValueError, KeyError):
																								snake_case_      =				None

																	with xopen(a__    ,							"rb"    ,							use_auth_token=a__							) as f:
																								snake_case_ ,				snake_case_      =				sf.read(a__							)

										else:
																	snake_case_ ,				snake_case_      =				sf.read(a__							)

										snake_case_      =				array.T
										if self.mono:
																	snake_case_      =				librosa.to_mono(a__							)
										if self.sampling_rate and self.sampling_rate != sampling_rate:
																	snake_case_      =				librosa.resample(a__    ,							orig_sr=a__    ,							target_sr=self.sampling_rate							)
																	snake_case_      =				self.sampling_rate

										return {"path": path, "array": array, "sampling_rate": sampling_rate}




			def        lowerCAmelCase__    ( self							)    ->    Union["FeatureType", Dict[str, "FeatureType"]]:

										'''simple docstring'''




										from .features import Value

										if self.decode:
																	raise ValueError("Cannot flatten a decoded Audio feature."							)
										return {
										    "bytes": Value("binary"							),
										    "path": Value("string"							),
										}




			def        lowerCAmelCase__    ( self    ,							a__							)    ->    pa.StructArray:

										'''simple docstring'''




										if pa.types.is_string(storage.type							):
																	snake_case_      =				pa.array([None] * len(a__							)    ,							type=pa.binary()							)
																	snake_case_      =				pa.StructArray.from_arrays([bytes_array, storage]    ,							["bytes", "path"]    ,							mask=storage.is_null()							)
										elif pa.types.is_binary(storage.type							):
																	snake_case_      =				pa.array([None] * len(a__							)    ,							type=pa.string()							)
																	snake_case_      =				pa.StructArray.from_arrays([storage, path_array]    ,							["bytes", "path"]    ,							mask=storage.is_null()							)
										elif pa.types.is_struct(storage.type							) and storage.type.get_all_field_indices("array"							):
																	snake_case_      =				pa.array([Audio().encode_example(a__							) if x is not None else None for x in storage.to_pylist()]							)
										elif pa.types.is_struct(storage.type							):
																	if storage.type.get_field_index("bytes"							) >= 0:
																								snake_case_      =				storage.field("bytes"							)
																	else:
																								snake_case_      =				pa.array([None] * len(a__							)    ,							type=pa.binary()							)
																	if storage.type.get_field_index("path"							) >= 0:
																								snake_case_      =				storage.field("path"							)
																	else:
																								snake_case_      =				pa.array([None] * len(a__							)    ,							type=pa.string()							)
																	snake_case_      =				pa.StructArray.from_arrays([bytes_array, path_array]    ,							["bytes", "path"]    ,							mask=storage.is_null()							)
										return array_cast(a__    ,							self.pa_type							)




			def        lowerCAmelCase__    ( self    ,							a__							)    ->    pa.StructArray:

										'''simple docstring'''




										@no_op_if_value_is_null
										def path_to_bytes(a__							):
																	with xopen(a__    ,							"rb"							) as f:
																								snake_case_      =				f.read()
																	return bytes_

										snake_case_      =				pa.array(
										    [
										        (path_to_bytes(x["path"]							) if x["bytes"] is None else x["bytes"]) if x is not None else None
										        for x in storage.to_pylist()
										    ]    ,							type=pa.binary()    ,							)
										snake_case_      =				pa.array(
										    [os.path.basename(a__							) if path is not None else None for path in storage.field("path"							).to_pylist()]    ,							type=pa.string()    ,							)
										snake_case_      =				pa.StructArray.from_arrays([bytes_array, path_array]    ,							["bytes", "path"]    ,							mask=bytes_array.is_null()							)
										return array_cast(a__    ,							self.pa_type							)










'''simple docstring'''





from random import shuffle

import tensorflow as tf
from numpy import array


def 					UpperCamelCase_(     snake_case							:	Optional[int]							,    snake_case							:	Optional[int]					):

							'''simple docstring'''






							snake_case_      =				int(snake_case					)
							assert noofclusters < len(snake_case					)

							# Find out the dimensionality
							snake_case_      =				len(vectors[0]					)

							# Will help select random centroids from among the available vectors
							snake_case_      =				list(range(len(snake_case					)					)					)
							shuffle(snake_case					)

							# GRAPH OF COMPUTATION
							# We initialize a new graph and set it as the default during each run
							# of this algorithm. This ensures that as this function is called
							# multiple times, the default graph doesn't keep getting crowded with
							# unused ops and Variables from previous function calls.

							snake_case_      =				tf.Graph()

							with graph.as_default():
														# SESSION OF COMPUTATION

														snake_case_      =				tf.Session()

														##CONSTRUCTING THE ELEMENTS OF COMPUTATION

														##First lets ensure we have a Variable vector for each centroid,
														##initialized to one of the vectors from the available data points
														snake_case_      =				[
														    tf.Variable(vectors[vector_indices[i]]					) for i in range(snake_case					)
														]
														##These nodes will assign the centroid Variables the appropriate
														##values
														snake_case_      =				tf.placeholder("float64"							,    [dim]					)
														snake_case_      =				[]
														for centroid in centroids:
																					cent_assigns.append(tf.assign(snake_case							,    snake_case					)					)

														##Variables for cluster assignments of individual vectors(initialized
														##to 0 at first)
														snake_case_      =				[tf.Variable(0					) for i in range(len(snake_case					)					)]
														##These nodes will assign an assignment Variable the appropriate
														##value
														snake_case_      =				tf.placeholder("int32"					)
														snake_case_      =				[]
														for assignment in assignments:
																					cluster_assigns.append(tf.assign(snake_case							,    snake_case					)					)

														##Now lets construct the node that will compute the mean
														# The placeholder for the input
														snake_case_      =				tf.placeholder("float"							,    [None, dim]					)
														# The Node/op takes the input and computes a mean along the 0th
														# dimension, i.e. the list of input vectors
														snake_case_      =				tf.reduce_mean(snake_case							,    0					)

														##Node for computing Euclidean distances
														# Placeholders for input
														snake_case_      =				tf.placeholder("float"							,    [dim]					)
														snake_case_      =				tf.placeholder("float"							,    [dim]					)
														snake_case_      =				tf.sqrt(tf.reduce_sum(tf.pow(tf.sub(snake_case							,    snake_case					)							,    2					)					)					)

														##This node will figure out which cluster to assign a vector to,
														##based on Euclidean distances of the vector from the centroids.
														# Placeholder for input
														snake_case_      =				tf.placeholder("float"							,    [noofclusters]					)
														snake_case_      =				tf.argmin(snake_case							,    0					)

														##INITIALIZING STATE VARIABLES

														##This will help initialization of all Variables defined with respect
														##to the graph. The Variable-initializer should be defined after
														##all the Variables have been constructed, so that each of them
														##will be included in the initialization.
														snake_case_      =				tf.initialize_all_variables()

														# Initialize all variables
														sess.run(snake_case					)

														##CLUSTERING ITERATIONS

														# Now perform the Expectation-Maximization steps of K-Means clustering
														# iterations. To keep things simple, we will only do a set number of
														# iterations, instead of using a Stopping Criterion.
														snake_case_      =				1_0_0
														for _ in range(snake_case					):
																					##EXPECTATION STEP
																					##Based on the centroid locations till last iteration, compute
																					##the _expected_ centroid assignments.
																					# Iterate over each vector
																					for vector_n in range(len(snake_case					)					):
																												snake_case_      =				vectors[vector_n]
																												# Compute Euclidean distance between this vector and each
																												# centroid. Remember that this list cannot be named
																												#'centroid_distances', since that is the input to the
																												# cluster assignment node.
																												snake_case_      =				[
																												    sess.run(snake_case							,    feed_dict={va: vect, va: sess.run(snake_case					)}					)
																												    for centroid in centroids
																												]
																												# Now use the cluster assignment node, with the distances
																												# as the input
																												snake_case_      =				sess.run(
																												    snake_case							,    feed_dict={centroid_distances: distances}					)
																												# Now assign the value to the appropriate state variable
																												sess.run(
																												    cluster_assigns[vector_n]							,    feed_dict={assignment_value: assignment}					)

																					##MAXIMIZATION STEP
																					# Based on the expected state computed from the Expectation Step,
																					# compute the locations of the centroids so as to maximize the
																					# overall objective of minimizing within-cluster Sum-of-Squares
																					for cluster_n in range(snake_case					):
																												# Collect all the vectors assigned to this cluster
																												snake_case_      =				[
																												    vectors[i]
																												    for i in range(len(snake_case					)					)
																												    if sess.run(assignments[i]					) == cluster_n
																												]
																												# Compute new centroid location
																												snake_case_      =				sess.run(
																												    snake_case							,    feed_dict={mean_input: array(snake_case					)}					)
																												# Assign value to appropriate variable
																												sess.run(
																												    cent_assigns[cluster_n]							,    feed_dict={centroid_value: new_location}					)

        # Return centroids and assignments
														snake_case_      =				sess.run(snake_case					)
														snake_case_      =				sess.run(snake_case					)
														return centroids, assignments




