| import numpy as np |
| import tensorflow as tf |
| import tensorflow_probability as tfp |
| from scipy.spatial.distance import mahalanobis |
| from sklearn.covariance import EmpiricalCovariance |
|
|
| |
| |
| |
| from bayes_logic import ( |
| BayesLogic, |
| PRN, |
| shannon_entropy, |
| calculate_cosines |
| ) |
|
|
| class QuantumBayesMahalanobis(BayesLogic): |
| """ |
| Clase que combina la lógica de Bayes con el cálculo de la distancia de Mahalanobis |
| aplicada a estados cuánticos, permitiendo proyecciones vectorizadas e inferencias |
| de coherencia/entropía. |
| """ |
| def __init__(self): |
| """ |
| Constructor que inicializa el estimador de covarianza para su posterior uso. |
| """ |
| super().__init__() |
| self.covariance_estimator = EmpiricalCovariance() |
|
|
| def _get_inverse_covariance(self, data: np.ndarray) -> np.ndarray: |
| """ |
| Ajusta el estimador de covarianza con los datos y retorna la inversa de la |
| matriz de covarianza. Si la matriz no fuera invertible, se retorna la |
| pseudo-inversa (pinv). |
| |
| Parámetros: |
| ----------- |
| data: np.ndarray |
| Datos con forma (n_muestras, n_dimensiones). |
| |
| Retorna: |
| -------- |
| inv_cov_matrix: np.ndarray |
| Inversa o pseudo-inversa de la matriz de covarianza estimada. |
| """ |
| if data.ndim != 2: |
| raise ValueError("Los datos deben ser una matriz bidimensional (n_muestras, n_dimensiones).") |
| self.covariance_estimator.fit(data) |
| cov_matrix = self.covariance_estimator.covariance_ |
| try: |
| inv_cov_matrix = np.linalg.inv(cov_matrix) |
| except np.linalg.LinAlgError: |
| inv_cov_matrix = np.linalg.pinv(cov_matrix) |
| return inv_cov_matrix |
|
|
| def compute_quantum_mahalanobis(self, |
| quantum_states_A: np.ndarray, |
| quantum_states_B: np.ndarray) -> np.ndarray: |
| """ |
| Calcula la distancia de Mahalanobis para cada estado en 'quantum_states_B' |
| respecto a la distribución de 'quantum_states_A'. Retorna un arreglo 1D |
| con tantas distancias como filas tenga 'quantum_states_B'. |
| |
| Parámetros: |
| ----------- |
| quantum_states_A: np.ndarray |
| Representa el conjunto de estados cuánticos de referencia. |
| Forma esperada: (n_muestras, n_dimensiones). |
| |
| quantum_states_B: np.ndarray |
| Estados cuánticos para los que calcularemos la distancia |
| de Mahalanobis. Forma: (n_muestras, n_dimensiones). |
| |
| Retorna: |
| -------- |
| distances: np.ndarray |
| Distancias de Mahalanobis calculadas para cada entrada de B. |
| """ |
| if quantum_states_A.ndim != 2 or quantum_states_B.ndim != 2: |
| raise ValueError("Los estados cuánticos deben ser matrices bidimensionales.") |
| if quantum_states_A.shape[1] != quantum_states_B.shape[1]: |
| raise ValueError("La dimensión (n_dimensiones) de A y B debe coincidir.") |
|
|
| inv_cov_matrix = self._get_inverse_covariance(quantum_states_A) |
| mean_A = np.mean(quantum_states_A, axis=0) |
|
|
| diff_B = quantum_states_B - mean_A |
| aux = diff_B @ inv_cov_matrix |
| dist_sqr = np.einsum('ij,ij->i', aux, diff_B) |
| distances = np.sqrt(dist_sqr) |
| return distances |
|
|
| def quantum_cosine_projection(self, |
| quantum_states: np.ndarray, |
| entropy: float, |
| coherence: float) -> tf.Tensor: |
| """ |
| Proyecta los estados cuánticos usando cosenos directores y calcula la |
| distancia de Mahalanobis entre dos proyecciones vectorizadas (A y B). |
| Finalmente retorna las distancias normalizadas (softmax). |
| |
| Parámetros: |
| ----------- |
| quantum_states: np.ndarray |
| Estados cuánticos de entrada con forma (n_muestras, 2). |
| entropy: float |
| Entropía del sistema a usar en la función calculate_cosines. |
| coherence: float |
| Coherencia del sistema a usar en la función calculate_cosines. |
| |
| Retorna: |
| -------- |
| normalized_distances: tf.Tensor |
| Tensor 1D con las distancias normalizadas (softmax). |
| """ |
| if quantum_states.shape[1] != 2: |
| raise ValueError("Se espera que 'quantum_states' tenga exactamente 2 columnas.") |
| cos_x, cos_y, cos_z = calculate_cosines(entropy, coherence) |
|
|
| |
| projected_states_A = quantum_states * np.array([cos_x, cos_y]) |
| |
| projected_states_B = quantum_states * np.array([cos_x * cos_z, cos_y * cos_z]) |
|
|
| |
| mahalanobis_distances = self.compute_quantum_mahalanobis( |
| projected_states_A, |
| projected_states_B |
| ) |
|
|
| |
| mahalanobis_distances_tf = tf.convert_to_tensor(mahalanobis_distances, dtype=tf.float32) |
| normalized_distances = tf.nn.softmax(mahalanobis_distances_tf) |
| return normalized_distances |
|
|
| def calculate_quantum_posterior_with_mahalanobis(self, |
| quantum_states: np.ndarray, |
| entropy: float, |
| coherence: float): |
| """ |
| Calcula la probabilidad posterior usando la distancia de Mahalanobis |
| en proyecciones cuánticas e integra la lógica de Bayes. |
| |
| Parámetros: |
| ----------- |
| quantum_states: np.ndarray |
| Matriz de estados cuánticos (n_muestras, 2). |
| entropy: float |
| Entropía del sistema. |
| coherence: float |
| Coherencia del sistema. |
| |
| Retorna: |
| -------- |
| posterior: tf.Tensor |
| Probabilidad posterior calculada combinando la lógica bayesiana. |
| quantum_projections: tf.Tensor |
| Proyecciones cuánticas normalizadas (distancias softmax). |
| """ |
| quantum_projections = self.quantum_cosine_projection( |
| quantum_states, |
| entropy, |
| coherence |
| ) |
|
|
| |
| tensor_projections = tf.convert_to_tensor(quantum_projections, dtype=tf.float32) |
| quantum_covariance = tfp.stats.covariance(tensor_projections, sample_axis=0) |
|
|
| |
| dim = tf.cast(tf.shape(quantum_covariance)[0], tf.float32) |
| quantum_prior = tf.linalg.trace(quantum_covariance) / dim |
|
|
| |
| prior_coherence = self.calculate_high_coherence_prior(coherence) |
| joint_prob = self.calculate_joint_probability( |
| coherence, |
| 1, |
| tf.reduce_mean(tensor_projections) |
| ) |
| cond_prob = self.calculate_conditional_probability(joint_prob, quantum_prior) |
| posterior = self.calculate_posterior_probability(quantum_prior, |
| prior_coherence, |
| cond_prob) |
| return posterior, quantum_projections |
|
|
| def predict_quantum_state(self, |
| quantum_states: np.ndarray, |
| entropy: float, |
| coherence: float): |
| """ |
| Predice el siguiente estado cuántico con base en la proyección y la distancia |
| de Mahalanobis, generando un "estado futuro". |
| |
| Parámetros: |
| ----------- |
| quantum_states: np.ndarray |
| Estados cuánticos de entrada (n_muestras, 2). |
| entropy: float |
| Entropía del sistema. |
| coherence: float |
| Coherencia del sistema. |
| |
| Retorna: |
| -------- |
| next_state_prediction: tf.Tensor |
| Predicción del siguiente estado cuántico. |
| posterior: tf.Tensor |
| Probabilidad posterior que se usó en la predicción. |
| """ |
| posterior, projections = self.calculate_quantum_posterior_with_mahalanobis( |
| quantum_states, |
| entropy, |
| coherence |
| ) |
|
|
| |
| |
| next_state_prediction = tf.reduce_sum( |
| tf.multiply(projections, tf.expand_dims(posterior, -1)), |
| axis=0 |
| ) |
| return next_state_prediction, posterior |
|
|
|
|
| class EnhancedPRN(PRN): |
| """ |
| Extiende la clase PRN para registrar distancias de Mahalanobis y con ello |
| definir un 'ruido cuántico' adicional en el sistema. |
| """ |
| def __init__(self, influence: float = 0.5, algorithm_type: str = None, **parameters): |
| """ |
| Constructor que permite definir la influencia y el tipo de algoritmo, |
| además de inicializar una lista para conservar registros promedio de |
| distancias de Mahalanobis. |
| """ |
| super().__init__(influence, algorithm_type, **parameters) |
| self.mahalanobis_records = [] |
|
|
| def record_quantum_noise(self, probabilities: dict, quantum_states: np.ndarray): |
| """ |
| Registra un 'ruido cuántico' basado en la distancia de Mahalanobis |
| calculada para los estados cuánticos. |
| |
| Parámetros: |
| ----------- |
| probabilities: dict |
| Diccionario de probabilidades (ej. {"0": p_0, "1": p_1, ...}). |
| quantum_states: np.ndarray |
| Estados cuánticos (n_muestras, n_dimensiones). |
| |
| Retorna: |
| -------- |
| (entropy, mahal_mean): Tuple[float, float] |
| - Entropía calculada a partir de probabilities. |
| - Distancia promedio de Mahalanobis. |
| """ |
| |
| entropy = self.record_noise(probabilities) |
|
|
| |
| cov_estimator = EmpiricalCovariance().fit(quantum_states) |
| mean_state = np.mean(quantum_states, axis=0) |
| inv_cov = np.linalg.pinv(cov_estimator.covariance_) |
|
|
| |
| diff = quantum_states - mean_state |
| aux = diff @ inv_cov |
| dist_sqr = np.einsum('ij,ij->i', aux, diff) |
| distances = np.sqrt(dist_sqr) |
| mahal_mean = np.mean(distances) |
| |
| def von_neumann_entropy(density_matrix: np.ndarray) -> float: |
| """Calcula la entropía de von Neumann para una matriz de densidad.""" |
| |
| eigenvalues = np.linalg.eigvalsh(density_matrix) |
| |
| non_zero_eigenvalues = eigenvalues[eigenvalues > 0] |
| |
| entropy = -np.sum(non_zero_eigenvalues * np.log(non_zero_eigenvalues)) |
| |
| self.mahalanobis_records.append(mahal_mean) |
|
|
| return entropy, mahal_mean |
|
|
| class QuantumNoiseCollapse(QuantumBayesMahalanobis): |
| """ |
| Combina la lógica bayesiana cuántica (QuantumBayesMahalanobis) y el registro ExtendedPRN |
| para simular el 'colapso de onda' usando distancias de Mahalanobis como parte del ruido. |
| """ |
| def __init__(self, prn_influence: float = 0.5): |
| """ |
| Constructor que crea internamente un EnhancedPRN por defecto, con una |
| influencia configurable. |
| """ |
| super().__init__() |
| self.prn = EnhancedPRN(influence=prn_influence) |
|
|
| def simulate_wave_collapse(self, |
| quantum_states: np.ndarray, |
| prn_influence: float, |
| previous_action: int): |
| """ |
| Simula el colapso de onda incorporando ruido cuántico (a través de PRN) e |
| integra el resultado para determinar una acción bayesiana. |
| |
| Parámetros: |
| ----------- |
| quantum_states: np.ndarray |
| Estados cuánticos de entrada. |
| prn_influence: float |
| Influencia del PRN en el sistema (se puede alinear con self.prn.influence). |
| previous_action: int |
| Acción previa del sistema que se utiliza como condicionante. |
| |
| Retorna: |
| -------- |
| dict con llaves: |
| "collapsed_state": tf.Tensor |
| Representación final colapsada del estado. |
| "action": int |
| Acción tomada según lógica bayesiana. |
| "entropy": float |
| Entropía calculada. |
| "coherence": float |
| Coherencia derivada. |
| "mahalanobis_distance": float |
| Distancia promedio de Mahalanobis. |
| "cosines": Tuple[float, float, float] |
| Valores de (cos_x, cos_y, cos_z) usados en la proyección. |
| """ |
| |
| probabilities = {str(i): np.sum(state) for i, state in enumerate(quantum_states)} |
|
|
| |
| entropy, mahalanobis_mean = self.prn.record_quantum_noise(probabilities, quantum_states) |
|
|
| |
| cos_x, cos_y, cos_z = calculate_cosines(entropy, mahalanobis_mean) |
|
|
| |
| coherence = np.exp(-mahalanobis_mean) * (cos_x + cos_y + cos_z) / 3.0 |
|
|
| |
| bayes_probs = self.calculate_probabilities_and_select_action( |
| entropy=entropy, |
| coherence=coherence, |
| prn_influence=prn_influence, |
| action=previous_action |
| ) |
|
|
| |
| projected_states = self.quantum_cosine_projection( |
| quantum_states, |
| entropy, |
| coherence |
| ) |
|
|
| |
| collapsed_state = tf.reduce_sum( |
| tf.multiply( |
| projected_states, |
| tf.cast(bayes_probs["action_to_take"], tf.float32) |
| ) |
| ) |
|
|
| return { |
| "collapsed_state": collapsed_state, |
| "action": bayes_probs["action_to_take"], |
| "entropy": entropy, |
| "coherence": coherence, |
| "mahalanobis_distance": mahalanobis_mean, |
| "cosines": (cos_x, cos_y, cos_z) |
| } |
|
|
| def objective_function_with_noise(self, |
| quantum_states: np.ndarray, |
| target_state: np.ndarray, |
| entropy_weight: float = 1.0) -> tf.Tensor: |
| """ |
| Función objetivo que combina fidelidad, entropía y distancia de Mahalanobis |
| para encontrar un compromiso entre mantener la fidelidad al estado objetivo |
| y el ruido cuántico en el sistema. |
| |
| Parámetros: |
| ----------- |
| quantum_states: np.ndarray |
| Estados cuánticos actuales (n_muestras, n_dimensiones). |
| target_state: np.ndarray |
| Estado objetivo que se desea alcanzar. |
| entropy_weight: float |
| Factor que pondera la influencia de la entropía en la función objetivo. |
| |
| Retorna: |
| -------- |
| objective_value: tf.Tensor |
| Valor de la función objetivo (cuanto menor, mejor). |
| """ |
| |
| |
| fidelity = tf.abs(tf.reduce_sum(quantum_states * tf.cast(target_state, quantum_states.dtype)))**2 |
|
|
| |
| probabilities = {str(i): np.sum(st) for i, st in enumerate(quantum_states)} |
| entropy, mahalanobis_dist = self.prn.record_quantum_noise(probabilities, quantum_states) |
|
|
| |
| objective_value = ((1.0 - fidelity) |
| + entropy_weight * entropy |
| + (1.0 - np.exp(-mahalanobis_dist))) |
|
|
| return objective_value |
|
|
| def optimize_quantum_state(self, |
| initial_states: np.ndarray, |
| target_state: np.ndarray, |
| max_iterations: int = 100, |
| learning_rate: float = 0.01): |
| """ |
| Optimiza los estados cuánticos para acercarlos al estado objetivo, |
| mediante un descenso de gradiente (Adam). |
| |
| Parámetros: |
| ----------- |
| initial_states: np.ndarray |
| Estados cuánticos iniciales. |
| target_state: np.ndarray |
| Estado objetivo. |
| max_iterations: int |
| Número máximo de iteraciones de optimización. |
| learning_rate: float |
| Tasa de aprendizaje para Adam. |
| |
| Retorna: |
| -------- |
| best_states: np.ndarray |
| Estados optimizados que reportan el menor valor de la función objetivo. |
| best_objective: float |
| Valor final alcanzado por la función objetivo. |
| """ |
| |
| current_states = tf.Variable(initial_states, dtype=tf.float32) |
|
|
| best_objective = float('inf') |
| best_states = current_states.numpy().copy() |
|
|
| optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate) |
|
|
| for _ in range(max_iterations): |
| with tf.GradientTape() as tape: |
| |
| objective = self.objective_function_with_noise(current_states.numpy(), target_state) |
| grads = tape.gradient(objective, [current_states]) |
|
|
| if grads[0] is None: |
| |
| break |
|
|
| optimizer.apply_gradients(zip(grads, [current_states])) |
|
|
| |
| new_objective = self.objective_function_with_noise(current_states.numpy(), target_state) |
| if new_objective < best_objective: |
| best_objective = new_objective |
| best_states = current_states.numpy().copy() |
|
|
| return best_states, best_objective |
|
|
|
|
| |
| |
| |
| if __name__ == "__main__": |
| qnc = QuantumNoiseCollapse() |
|
|
| |
| initial_states = np.array([ |
| [0.8, 0.2], |
| [0.9, 0.4], |
| [0.1, 0.7] |
| ]) |
|
|
| |
| target_state = np.array([1.0, 0.0]) |
|
|
| |
| optimized_states, final_objective = qnc.optimize_quantum_state( |
| initial_states, |
| target_state, |
| max_iterations=100, |
| learning_rate=0.01 |
| ) |
|
|
| |
| final_collapse = qnc.simulate_wave_collapse( |
| optimized_states, |
| prn_influence=0.5, |
| previous_action=0 |
| ) |
|
|
| print("Estados optimizados:", optimized_states) |
| print("Valor final de la función objetivo:", final_objective) |
| print("Resultado del colapso final:", final_collapse) |
|
|