From 39e29a23a16162963801ee93dc250e100237ee5c Mon Sep 17 00:00:00 2001 From: Pranav Date: Wed, 5 Jun 2024 19:20:54 +0530 Subject: [PATCH] initial local uploads --- README.md | 27 +- SGD_brane_old_tf.py | 303 ++++++++++++ SGD_main.py | 446 ++++++++++++++++++ SGD_torch.py | 141 ++++++ SGD_write.py | 591 ++++++++++++++++++++++++ requirements.txt | 5 + scipy_optimize.py | 50 ++ tensorflow_python_methods.png | Bin 0 -> 127456 bytes u1_sgd_info.py | 843 ++++++++++++++++++++++++++++++++++ u1_susy_sgd.py | 742 ++++++++++++++++++++++++++++++ 10 files changed, 3146 insertions(+), 2 deletions(-) mode change 100644 => 100755 README.md create mode 100644 SGD_brane_old_tf.py create mode 100644 SGD_main.py create mode 100644 SGD_torch.py create mode 100644 SGD_write.py create mode 100755 requirements.txt create mode 100644 scipy_optimize.py create mode 100644 tensorflow_python_methods.png create mode 100644 u1_sgd_info.py create mode 100644 u1_susy_sgd.py diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 5bf4d65..c48477f --- a/README.md +++ b/README.md @@ -1,2 +1,25 @@ -# brane-sgd -TF and Pytorch Code to find the minima in string brane configurations using SGD +# String Theory and Machine Learning Loss Landscape +## TF and Pytorch Code to find the minima in string brane configurations using SGD + +### How to find all the minima of the landscapes predicted by different brane configuration, using ML optimization methods + +A code repository for papers listed below + +https://link.springer.com/article/10.1007/JHEP10(2023)107 + +https://arxiv.org/abs/2312.04643 + +## Workflow + +All the codefiles in this repository are some permutation of an algorithm where the potential function created using physical principles is cast as a landscape, whereupon we start from a randomly chosen point, and use SGD(or any of the other Keras optmizer) to find a minima, using the value of the loss function as a threshold to stop the run. Because the number of minima changes with a Hyperparameter of the cost function (N or N4 in the codes), the code needs to run many many times, sometimes as many as 1000 times, hence the code is paralellized and we have used @tf.function to speed it up. + +## Structure + +All the .py files are self contained files. There is no directory structure as we were running them on colab or Kaggle often, and keeping track of all the changes over a directory was cumbersone, so we stuck one script which needed to be edited to change the code. + + +## Getting started + +To get started, first install the required libraries inside a virtual environment: + +`pip install -r requirements.txt` diff --git a/SGD_brane_old_tf.py b/SGD_brane_old_tf.py new file mode 100644 index 0000000..5d2f9ea --- /dev/null +++ b/SGD_brane_old_tf.py @@ -0,0 +1,303 @@ +#!/usr/bin/python3 + +import time +import pickle +import tensorflow as tf +from numpy import zeros +from multiprocessing import Pool +num_stacks = 4 +real_dtype = tf.float64 +complex_dtype = tf.complex128 +mean = 0.0 +minval = 0.0 +maxval = 2.0 +search_range = int(abs(mean) + abs(maxval)) + + +def Z(i, j, N4): + N = [1, 1, 1, N4] + shape = (N[i - 1], N[j - 1]) + """ + Initialize real matrices randomly, and combine to make them complex + """ + rand_real = tf.random.uniform( + shape, minval, maxval, dtype=real_dtype) + rand_imag = tf.random.uniform( + shape, minval, maxval, dtype=real_dtype) + return tf.Variable(tf.complex(rand_real, rand_imag)) + + +def phi(N4): + shape = (N4, N4) + """ + Initialize real matrices randomly, and combine to make them complex + """ + rand_real = tf.random.uniform( + shape, minval, maxval, dtype=real_dtype) + rand_imag = tf.random.uniform( + shape, minval, maxval, dtype=real_dtype) + return tf.Variable(tf.complex(rand_real, rand_imag)) + + +def phi_gauged(N4): + shape = [N4] + """ + Initialize real matrices randomly, and combine to make them complex + """ + rand_real = tf.random.uniform( + shape, minval, maxval, dtype=real_dtype) + rand_imag = tf.random.uniform( + shape, minval, maxval, dtype=real_dtype) + return tf.Variable(tf.complex(rand_real, rand_imag)) + + +def Z_gauged(i, j, N4): + N = [1, 1, 1, N4] + shape = (N[i - 1], N[j - 1]) + """ + Initialize a zeros matrix, and replace the last element with 1 + """ + rand_real = tf.Variable(tf.zeros(shape, dtype=real_dtype)) + rand_real[-1, -1].assign(1) + + return tf.constant(tf.cast(rand_real, complex_dtype)) + + +def C(i, j): + if (i, j) == (1, 2): + return tf.cast(0.696667, dtype=complex_dtype) + elif (i, j) == (1, 3): + return tf.cast(0.178734, dtype=complex_dtype) + elif (i, j) == (1, 4): + return tf.cast(0.292304, dtype=complex_dtype) + elif (i, j) == (2, 3): + return tf.cast(-0.54981, dtype=complex_dtype) + elif (i, j) == (2, 4): + return tf.cast(0.962468, dtype=complex_dtype) + elif (i, j) == (3, 4): + return tf.cast(-0.506718, dtype=complex_dtype) + + +def complex_id(N4): + return tf.cast(tf.eye(N4, N4), complex_dtype) + + +def commutator(a, b): + return tf.matmul(a, b) - tf.matmul(b, a) + + +def triple_mul(a, b, c): + return tf.matmul(a, tf.matmul(b, c)) + + +@tf.function +def make_mat(input): + N4 = input.shape[0] + shape = (N4 - 1, N4) + arr = zeros(shape) + for i in range(N4 - 1): + for j in range(N4): + if i + j >= N4 - 1: + arr[i, j] = 1 + arr = tf.convert_to_tensor(arr, dtype=complex_dtype) + return tf.concat([arr, tf.reshape(input, [1, input.shape[0]])], 0) + + +def full_vars(arg_list, index): + arg_list[index] = make_mat(arg_list[index]) + return arg_list + + +def E12(Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z41, Z42): + return triple_mul(Z12, Z23, Z31) + triple_mul(Z12, Z24, Z41) - triple_mul(Z21, Z13, Z32) - triple_mul(Z21, Z14, Z42) + + +def E13(Z12, Z13, Z14, Z21, Z23, Z31, Z32, Z34, Z41, Z43): + return triple_mul(Z13, Z32, Z21) - triple_mul(Z13, Z34, Z41) - triple_mul(Z31, Z12, Z23) - triple_mul(Z31, Z14, Z43) + + +def E23(Z12, Z13, Z21, Z23, Z24, Z31, Z32, Z34, Z42, Z43): + return triple_mul(Z23, Z31, Z12) + triple_mul(Z23, Z34, Z42) - triple_mul(Z32, Z21, Z13) - triple_mul(Z32, Z24, Z43) + + +def F12(Z12, Z21): + return tf.matmul(Z12, Z21) + C(1, 2) + + +def F23(Z23, Z32): + return tf.matmul(Z23, Z32) + C(2, 3) + + +def F31(Z13, Z31): + return tf.matmul(Z31, Z13) + C(1, 3) + + +def F41(Z14, Z41, phi2, phi3): + N4 = Z41.shape[0] + return tf.matmul(Z41, Z14) + C(1, 4) * complex_id(N4) + commutator(phi2, phi3) + + +def F42(Z24, Z42, phi1, phi3): + N4 = Z42.shape[0] + return tf.matmul(Z42, Z24) + C(2, 4) * complex_id(N4) + commutator(phi3, phi1) + + +def F43(Z34, Z43, phi1, phi2): + N4 = Z43.shape[0] + return tf.matmul(Z43, Z34) + C(3, 4) * complex_id(N4) + commutator(phi1, phi2) + + +def G14(Z12, Z13, Z14, Z24, Z34, phi1): + return -tf.matmul(Z14, phi1) + tf.matmul(Z12, Z24) - tf.matmul(Z13, Z34) + + +def G24(Z14, Z21, Z23, Z24, Z34, phi2): + return -tf.matmul(Z24, phi2) + tf.matmul(Z21, Z14) + tf.matmul(Z23, Z34) + + +def G34(Z14, Z24, Z31, Z32, Z34, phi3): + return -tf.matmul(Z34, phi3) + tf.matmul(Z31, Z14) + tf.matmul(Z32, Z24) + + +def G41(Z21, Z31, Z41, Z42, Z43, phi1): + return -tf.matmul(phi1, Z41) + tf.matmul(Z42, Z21) + tf.matmul(Z43, Z31) + + +def G42(Z12, Z32, Z41, Z42, Z43, phi2): + return -tf.matmul(phi2, Z42) + tf.matmul(Z43, Z32) + tf.matmul(Z41, Z12) + + +def G43(Z13, Z23, Z41, Z42, Z43, phi3): + return -tf.matmul(phi3, Z43) - tf.matmul(Z41, Z13) + tf.matmul(Z42, Z23) + + +def init_vars(N4): + Z12 = Z_gauged(1, 2, N4) + Z23 = Z_gauged(2, 3, N4) + Z41 = Z_gauged(4, 1, N4) + + Z13 = Z(1, 3, N4) + Z14 = Z(1, 4, N4) + Z21 = Z(2, 1, N4) + Z24 = Z(2, 4, N4) + Z31 = Z(3, 1, N4) + Z32 = Z(3, 2, N4) + Z34 = Z(3, 4, N4) + Z42 = Z(4, 2, N4) + Z43 = Z(4, 3, N4) + phi1 = phi(N4) + phi2 = phi_gauged(N4) + phi3 = phi(N4) + + arg_list = [Z12, Z13, Z14, Z21, Z23, Z24, Z31, + Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3] + var_list = [Z13, Z14, Z21, Z24, Z31, Z32, Z34, Z42, Z43, phi1, phi2, phi3] + + return arg_list, var_list + + +gauge_index = 13 + + +@tf.function +def brane_potential(Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3): + E12_sqnorm = tf.norm( + E12(Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z41, Z42)) ** 2 + E13_sqnorm = tf.norm( + E13(Z12, Z13, Z14, Z21, Z23, Z31, Z32, Z34, Z41, Z43)) ** 2 + E23_sqnorm = tf.norm( + E23(Z12, Z13, Z21, Z23, Z24, Z31, Z32, Z34, Z42, Z43)) ** 2 + + phi2 = make_mat(phi2) + + F12_sqnorm = tf.norm(F12(Z12, Z21)) ** 2 + F23_sqnorm = tf.norm(F23(Z23, Z32)) ** 2 + F31_sqnorm = tf.norm(F31(Z13, Z31)) ** 2 + F41_sqnorm = tf.norm(F41(Z14, Z41, phi2, phi3)) ** 2 + F42_sqnorm = tf.norm(F42(Z24, Z42, phi1, phi3)) ** 2 + F43_sqnorm = tf.norm(F43(Z34, Z43, phi1, phi2)) ** 2 + + G14_sqnorm = tf.norm(G14(Z12, Z13, Z14, Z24, Z34, phi1)) ** 2 + G24_sqnorm = tf.norm(G24(Z14, Z21, Z23, Z24, Z34, phi2)) ** 2 + G34_sqnorm = tf.norm(G34(Z14, Z24, Z31, Z32, Z34, phi3)) ** 2 + G41_sqnorm = tf.norm(G41(Z21, Z31, Z41, Z42, Z43, phi1)) ** 2 + G42_sqnorm = tf.norm(G42(Z12, Z32, Z41, Z42, Z43, phi2)) ** 2 + G43_sqnorm = tf.norm(G43(Z13, Z23, Z41, Z42, Z43, phi3)) ** 2 + + return tf.math.real(E12_sqnorm + E13_sqnorm + E23_sqnorm + F12_sqnorm + F23_sqnorm + F31_sqnorm + F41_sqnorm + F42_sqnorm + F43_sqnorm + G14_sqnorm + G24_sqnorm + G34_sqnorm + G41_sqnorm + G42_sqnorm + G43_sqnorm) + + +def optimize_2loops(N4): + arg_list, var_list = init_vars(N4) + + def loss(): + return brane_potential(*arg_list) + + num_cycles = 500 + search_range * 250 + num_epochs = 100 + learning_rate = 1e-4 / search_range + momentum = 0.99 + + loss_vals = [loss()] + + print('beginning_loss:', loss_vals[-1].numpy(), 'Z12:', arg_list[0].numpy(), + 'Z13:', arg_list[1].numpy(), 'Z14:', arg_list[2].numpy(), 'phi_gauge:', arg_list[gauge_index].numpy()) + + for cycle in range(num_cycles): + + # print('cycle:', cycle, "V:", loss_vals[-1]) + # print('learning rate:', learning_rate) + + opt = tf.keras.optimizers.SGD( + learning_rate=learning_rate, momentum=momentum) + + for _ in range(num_epochs): + opt.minimize(loss, var_list=var_list) + + loss_vals.append(loss()) + + if loss_vals[-1] < 1e-12 or loss_vals[-1] > 1e+8 or tf.math.is_nan(loss_vals[-1]): + break + elif loss_vals[-1] > loss_vals[-2]: + learning_rate /= 1.1 + else: + learning_rate = min(learning_rate * 1.1, 1e-2) + + print('end_loss:', loss_vals[-1].numpy(), 'Z12:', arg_list[0].numpy(), + 'Z13:', arg_list[1].numpy(), 'Z14:', arg_list[2].numpy(), 'phi_gauge:', arg_list[gauge_index].numpy()) + + return loss_vals[-1], arg_list + + +def main(N4): + + start_time = time.time() # at the beginning of the program + + variable_list = [] + N4_list = [N4 for _ in range(num_runs[N4])] + print("N4:", N4, "number of runs:", len(N4_list)) + + threshold = 1e-6 + with Pool() as pool: + for loss, arg_list in pool.map(optimize_2loops, N4_list): + if loss < threshold: + variable_list.append(full_vars(arg_list, gauge_index)) + + print("N4:", N4, "number of runs:", len(N4_list), + 'results_length:', len(variable_list)) + with open('variables_N4={}_{}.data'.format(N4, gauge_index - 11), 'wb') as filehandle: + pickle.dump(variable_list, filehandle) + + end_time = time.time() # at the beginning of the program + print('for N4 = {}..... time taken = {} seconds'.format( + N4, round(end_time - start_time, 2))) + + +num_runs = {1: 25, 2: 4, 3: 4} +N4 = 3 + + +if __name__ == "__main__": + main(N4) + +exit() \ No newline at end of file diff --git a/SGD_main.py b/SGD_main.py new file mode 100644 index 0000000..1b9d16a --- /dev/null +++ b/SGD_main.py @@ -0,0 +1,446 @@ +#!/usr/bin/python3 + +import time +import pickle +import tensorflow as tf +from numpy import zeros +from multiprocessing import Pool +from contextlib import contextmanager +from copy import deepcopy +num_stacks = 4 +real_dtype = tf.float64 +complex_dtype = tf.complex128 +gauge_type = 0 +scale = 1.0 +minval = -4.1 * scale +maxval = 4.1 * scale + + +def Z(i, j, N4): + N = [1, 1, 1, N4] + shape = (N[i - 1], N[j - 1]) + """ + Initialize real matrices randomly, and combine to make them complex + """ + rand_real = tf.random.uniform( + shape, minval, maxval, dtype=real_dtype) + rand_imag = tf.random.uniform( + shape, minval, maxval, dtype=real_dtype) + return tf.Variable(tf.complex(rand_real, rand_imag)) + + +def phi(N4): + shape = (N4, N4) + """ + Initialize real matrices randomly, and combine to make them complex + """ + rand_real = tf.random.uniform( + shape, minval, maxval, dtype=real_dtype) + rand_imag = tf.random.uniform( + shape, minval, maxval, dtype=real_dtype) + return tf.Variable(tf.complex(rand_real, rand_imag)) + + +def phi_gauged(N4): + shape = [N4] + """ + Initialize real matrices randomly, and combine to make them complex + """ + rand_real = tf.random.uniform( + shape, minval, maxval, dtype=real_dtype) + rand_imag = tf.random.uniform( + shape, minval, maxval, dtype=real_dtype) + return tf.Variable(tf.complex(rand_real, rand_imag), name="phi_gauged") + + +def Z_gauged(i, j, N4): + N = [1, 1, 1, N4] + shape = (N[i - 1], N[j - 1]) + """ + Initialize a zeros matrix, and replace the last element with 1 + """ + rand_real = tf.Variable(tf.zeros(shape, dtype=real_dtype)) + rand_real[-1, -1].assign(1) + + return tf.constant(tf.cast(rand_real, complex_dtype)) + + +def C(i, j): + if (i, j) == (1, 2): + return tf.cast(2 / 3 * scale**2, dtype=complex_dtype) + elif (i, j) == (1, 3): + return tf.cast(3 / 5 * scale**2, dtype=complex_dtype) + elif (i, j) == (1, 4): + return tf.cast(5 / 7 * scale**2, dtype=complex_dtype) + elif (i, j) == (2, 3): + return tf.cast(7 / 11 * scale**2, dtype=complex_dtype) + elif (i, j) == (2, 4): + return tf.cast(11 / 13 * scale**2, dtype=complex_dtype) + elif (i, j) == (3, 4): + return tf.cast(13 / 17 * scale**2, dtype=complex_dtype) + + +# def C(i, j): +# if (i, j) == (1, 2): +# return tf.cast(0.696667 * scale**2, dtype=complex_dtype) +# elif (i, j) == (1, 3): +# return tf.cast(0.178734 * scale**2, dtype=complex_dtype) +# elif (i, j) == (1, 4): +# return tf.cast(0.292304 * scale**2, dtype=complex_dtype) +# elif (i, j) == (2, 3): +# return tf.cast(-0.54981 * scale**2, dtype=complex_dtype) +# elif (i, j) == (2, 4): +# return tf.cast(0.962468 * scale**2, dtype=complex_dtype) +# elif (i, j) == (3, 4): +# return tf.cast(-0.506718 * scale**2, dtype=complex_dtype) + + +def complex_id(N4): + return tf.cast(tf.eye(N4, N4), complex_dtype) + + +def commutator(a, b): + return tf.matmul(a, b) - tf.matmul(b, a) + + +def triple_mul(a, b, c): + return tf.matmul(a, tf.matmul(b, c)) + + +@tf.function +def make_mat(input): + N4 = input.shape[0] + shape = (N4 - 1, N4) + arr = zeros(shape) + for i in range(N4 - 1): + for j in range(N4): + if i + j >= N4 - 1: + if gauge_type: + arr[i, j] = (i + j) * scale + else: + arr[i, j] = 1 * scale + arr = tf.convert_to_tensor(arr, dtype=complex_dtype) + return tf.concat([arr, tf.reshape(input, [1, input.shape[0]])], 0) + + +def saddle1(arg_list): + [Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, + Z43, phi1, phi2, phi3, phi12, phi23, phi31] = arg_list + Z21, Z31, Z32, Z41, phi12, phi23, phi31 = [val.assign( + val * 0) if isinstance(val, tf.Variable) else val for val in [Z21, Z31, Z32, Z41, phi12, phi23, phi31]] + return [Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3, phi12, phi23, phi31] + + +def saddle2(arg_list): + [Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, + Z43, phi1, phi2, phi3, phi12, phi23, phi31] = arg_list + [Z12, Z31, Z32, Z34, phi1, phi12, phi23, phi31] = [val.assign( + val * 0) if isinstance(val, tf.Variable) else val for val in [Z12, Z31, Z32, Z34, phi1, phi12, phi23, phi31]] + return [Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3, phi12, phi23, phi31] + + +def F12(Z12, Z21): + return tf.matmul(Z12, Z21) + C(1, 2) + + +def F23(Z23, Z32): + return tf.matmul(Z23, Z32) + C(2, 3) + + +def F31(Z13, Z31): + return tf.matmul(Z31, Z13) + C(1, 3) + + +def F41(Z14, Z41, phi2, phi3): + N4 = Z41.shape[0] + return tf.matmul(Z41, Z14) + C(1, 4) * complex_id(N4) + commutator(phi2, phi3) + + +def F42(Z24, Z42, phi1, phi3): + N4 = Z42.shape[0] + return tf.matmul(Z42, Z24) + C(2, 4) * complex_id(N4) + commutator(phi3, phi1) + + +def F43(Z34, Z43, phi1, phi2): + N4 = Z43.shape[0] + return tf.matmul(Z43, Z34) + C(3, 4) * complex_id(N4) - commutator(phi2, phi1) + + +def G21(Z21, Z23, Z24, Z31, Z41, phi12): + return tf.matmul(Z21, phi12) + tf.matmul(Z23, Z31) + tf.matmul(Z24, Z41) + + +def G12(Z12, Z13, Z14, Z32, Z42, phi12): + return tf.matmul(Z12, phi12) + tf.matmul(Z13, Z32) + tf.matmul(Z14, Z42) + + +def G31(Z21, Z31, Z32, Z34, Z41, phi31): + return tf.matmul(Z31, phi31) + tf.matmul(Z32, Z21) - tf.matmul(Z34, Z41) + + +def G13(Z12, Z13, Z14, Z23, Z43, phi31): + return tf.matmul(Z13, phi31) + tf.matmul(Z12, Z23) + tf.matmul(Z14, Z43) + + +def G32(Z12, Z31, Z32, Z34, Z42, phi23): + return tf.matmul(Z32, phi23) + tf.matmul(Z31, Z12) + tf.matmul(Z34, Z42) + + +def G23(Z13, Z21, Z23, Z24, Z43, phi23): + return tf.matmul(Z23, phi23) + tf.matmul(Z21, Z13) + tf.matmul(Z24, Z43) + + +def G14(Z12, Z13, Z14, Z24, Z34, phi1): + return -tf.matmul(Z14, phi1) + tf.matmul(Z12, Z24) - tf.matmul(Z13, Z34) + + +def G24(Z14, Z21, Z23, Z24, Z34, phi2): + return -tf.matmul(Z24, phi2) + tf.matmul(Z21, Z14) + tf.matmul(Z23, Z34) + + +def G34(Z14, Z24, Z31, Z32, Z34, phi3): + return -tf.matmul(Z34, phi3) + tf.matmul(Z31, Z14) + tf.matmul(Z32, Z24) + + +def G41(Z21, Z31, Z41, Z42, Z43, phi1): + return -tf.matmul(phi1, Z41) + tf.matmul(Z42, Z21) + tf.matmul(Z43, Z31) + + +def G42(Z12, Z32, Z41, Z42, Z43, phi2): + return -tf.matmul(phi2, Z42) + tf.matmul(Z43, Z32) + tf.matmul(Z41, Z12) + + +def G43(Z13, Z23, Z41, Z42, Z43, phi3): + return -tf.matmul(phi3, Z43) - tf.matmul(Z41, Z13) + tf.matmul(Z42, Z23) + + +def init_vars(N4, t1221, t2332, tzi4, tphi): + + Z12 = Z_gauged(1, 2, N4) + Z23 = Z_gauged(2, 3, N4) + Z34 = Z_gauged(3, 4, N4) + + Z13 = Z(1, 3, N4) + Z14 = Z(1, 4, N4) + Z21 = Z(2, 1, N4) + Z24 = Z(2, 4, N4) + Z31 = Z(3, 1, N4) + Z32 = Z(3, 2, N4) + Z41 = Z(4, 1, N4) + Z42 = Z(4, 2, N4) + Z43 = Z(4, 3, N4) + phi1 = phi_gauged(N4) + phi2 = phi(N4) + phi3 = phi(N4) + phi12 = phi(1) + phi23 = phi(1) + phi31 = phi(1) + + if t1221: + Z12, Z21 = Z21, Z12 + if t2332: + Z23, Z32 = Z32, Z23 + if tzi4 == 1: + Z34, Z14 = Z14, Z34 + elif tzi4 == 2: + Z34, Z24 = Z24, Z34 + elif tzi4 == 3: + Z34, Z41 = tf.Variable(tf.transpose(Z41)), tf.transpose(Z34) + elif tzi4 == 4: + Z34, Z42 = tf.Variable(tf.transpose(Z42)), tf.transpose(Z34) + elif tzi4 == 5: + Z34, Z43 = tf.Variable(tf.transpose(Z43)), tf.transpose(Z34) + if tphi == 1: + phi1, phi2 = phi2, phi1 + elif tphi == 2: + phi1, phi3 = phi3, phi1 + + return [Z12, Z13, Z14, Z21, Z23, Z24, Z31, + Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3, phi12, phi23, phi31] + + +@tf.function +def brane_potential(Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3, phi12, phi23, phi31): + + G21_sqnorm = tf.norm(G21(Z21, Z23, Z24, Z31, Z41, phi12)) ** 2 + G12_sqnorm = tf.norm(G12(Z12, Z13, Z14, Z32, Z42, phi12)) ** 2 + G31_sqnorm = tf.norm(G31(Z21, Z31, Z32, Z34, Z41, phi31)) ** 2 + G13_sqnorm = tf.norm(G13(Z12, Z13, Z14, Z23, Z43, phi31)) ** 2 + G32_sqnorm = tf.norm(G32(Z12, Z31, Z32, Z34, Z42, phi23)) ** 2 + G23_sqnorm = tf.norm(G23(Z13, Z21, Z23, Z24, Z43, phi23)) ** 2 + + phi1, phi2, phi3 = [make_mat( + val) if val.name == 'phi_gauged:0' else val for val in [phi1, phi2, phi3]] + + F12_sqnorm = tf.norm(F12(Z12, Z21)) ** 2 + F23_sqnorm = tf.norm(F23(Z23, Z32)) ** 2 + F31_sqnorm = tf.norm(F31(Z13, Z31)) ** 2 + F41_sqnorm = tf.norm(F41(Z14, Z41, phi2, phi3)) ** 2 + F42_sqnorm = tf.norm(F42(Z24, Z42, phi1, phi3)) ** 2 + F43_sqnorm = tf.norm(F43(Z34, Z43, phi1, phi2)) ** 2 + + G14_sqnorm = tf.norm(G14(Z12, Z13, Z14, Z24, Z34, phi1)) ** 2 + G24_sqnorm = tf.norm(G24(Z14, Z21, Z23, Z24, Z34, phi2)) ** 2 + G34_sqnorm = tf.norm(G34(Z14, Z24, Z31, Z32, Z34, phi3)) ** 2 + G41_sqnorm = tf.norm(G41(Z21, Z31, Z41, Z42, Z43, phi1)) ** 2 + G42_sqnorm = tf.norm(G42(Z12, Z32, Z41, Z42, Z43, phi2)) ** 2 + G43_sqnorm = tf.norm(G43(Z13, Z23, Z41, Z42, Z43, phi3)) ** 2 + + return tf.math.real(G21_sqnorm + G12_sqnorm + G31_sqnorm + G13_sqnorm + G32_sqnorm + G23_sqnorm + + F12_sqnorm + F23_sqnorm + F31_sqnorm + F41_sqnorm + F42_sqnorm + F43_sqnorm + + G14_sqnorm + G24_sqnorm + G34_sqnorm + G41_sqnorm + G42_sqnorm + G43_sqnorm) / scale**4 + + +def saddle_optimize(arguments): + var_list = [val for val in arguments if isinstance(val, tf.Variable)] + + def loss(): + return brane_potential(*arguments) + + num_cycles = 500 + learning_rate = 1e-3 + momentum = 0.99 + + loss_vals = [loss()] + + print('saddle beginning_loss:', loss_vals[-1], 'Z13:', + arguments[1], 'phi12:', arguments[15]) + + for cycle in range(num_cycles): + + # print('cycle_1:', cycle, "V:", loss_vals[-1]) + # print('learning rate:', learning_rate) + + opt = tf.keras.optimizers.SGD( + learning_rate=learning_rate, momentum=momentum) + + for _ in range(100): + opt.minimize(loss, var_list=var_list) + + loss_vals.append(loss()) + + if loss_vals[-1] < 1e-9 or tf.math.is_nan(loss_vals[-1]): + break + elif loss_vals[-1] < loss_vals[-2]: + learning_rate = min(learning_rate * 1.1, 2e-2) + elif loss_vals[-1] > loss_vals[-2]: + learning_rate /= 1.1 + + print('saddle end_loss:', loss_vals[-1], 'Z13:', + arguments[1], 'phi12:', arguments[15]) + + return loss_vals[-1], arguments + + +def optimize_2loops(N4, t1221, t2332, tzi4, tphi): + print(N4, t1221, t2332, tzi4, tphi) + + arg_list = init_vars(N4, t1221, t2332, tzi4, tphi) + # var_list = [val for val in arg_list if type(val).__name__ == 'ResourceVariable'] + var_list = [val for val in arg_list if isinstance(val, tf.Variable)] + + def loss(): + return brane_potential(*arg_list) + + loss_vals = [loss()] + + num_cycles = 500 + learning_rate = 1 / loss_vals[0] + momentum = 0.99 + + print('beginning_loss:', loss_vals[-1], 'Z12:', + arg_list[0], '\n phi12:', arg_list[15]) + + for cycle in range(num_cycles): + + # print('cycle_1:', cycle, "V:", loss_vals[-1]) + # print('learning rate:', learning_rate) + + opt = tf.keras.optimizers.SGD( + learning_rate=learning_rate, momentum=momentum) + + for _ in range(100): + opt.minimize(loss, var_list=var_list) + + loss_vals.append(loss()) + + if loss_vals[-1] < 1e-15 or tf.math.is_nan(loss_vals[-1]): + break + elif loss_vals[-1] < loss_vals[-2]: + learning_rate = min(learning_rate * 1.1, 1e-2 * scale) + elif loss_vals[-1] > loss_vals[-2]: + learning_rate /= 1.1 + + print('end_loss:', loss_vals[-1], 'Z12:', + arg_list[0], '\n phi12:', arg_list[15]) + + return loss_vals[-1], arg_list + + +def main(N4): + + start_time = time.time() # at the beginning of the program + + variable_list = [] + saddle2_variables_list = [] + saddle1_variables_list = [] + + params = [] + N4_list = [N4 for _ in range(num_runs[N4])] + for num in N4_list: + for t1221 in range(2): + for t2332 in range(2): + for tzi4 in range(6): + for tphi in range(1): + params.append((num, t1221, t2332, tzi4, tphi)) + + print("N4:", N4, "number of runs:", len(params)) + + @contextmanager + def poolcontext(*args, **kwargs): + pool = Pool(*args, **kwargs) + yield pool + pool.terminate() + + threshold = 1e-6 + with poolcontext() as pool: + for loss, arg_list in pool.starmap(optimize_2loops, params): + if loss < threshold: + variable_list.append(arg_list) + + # new_variable_list = deepcopy(variable_list) + + # saddle2_init_vars = [saddle2(args) for args in new_variable_list] + # for saddle2_loss, saddle2_arg_list in pool.map(saddle_optimize, saddle2_init_vars): + # if saddle2_loss < threshold: + # saddle2_variables_list.append(saddle2_arg_list) + + # if z_fixed != 1: + # saddle1_init_vars = [ + # saddle1(args) for args in new_variable_list] + # for saddle1_loss, saddle1_arg_list in pool.map(saddle_optimize, saddle1_init_vars): + # if saddle1_loss < threshold: + # saddle1_variables_list.append(saddle1_arg_list) + + for args in variable_list + saddle2_variables_list + saddle1_variables_list: + print(args[17]) + print("N4:", N4, "number of runs:", len(params), + 'results_length:', len(variable_list + saddle2_variables_list + saddle1_variables_list)) + fname = 'variables_N4={}.({})_{}.data'.format(N4, scale, gauge_type) + with open(fname, 'wb') as filehandle: + pickle.dump(variable_list + saddle2_variables_list + + saddle1_variables_list, filehandle) + end_time = time.time() # at the beginning of the program + print('for N4 = {}..... time taken = {} seconds'.format( + N4, round(end_time - start_time, 2))) + print(">>> Dumped to {}".format(fname)) + + +num_runs = {1: 1, 2: 2, 3: 4} +N4 = 1 + + +if __name__ == "__main__": + main(N4) + +exit() diff --git a/SGD_torch.py b/SGD_torch.py new file mode 100644 index 0000000..bd0891d --- /dev/null +++ b/SGD_torch.py @@ -0,0 +1,141 @@ +#!/usr/bin/python3 + +# adapted from https://github.com/jankrepl/mildlyoverfitted/blob/master/mini_tutorials/custom_optimizer_in_pytorch/src.py + + +import numpy as np +import torch +from torch.optim import Adam, SGD, ASGD, LBFGS, RMSprop +from tqdm import tqdm + +def Z(i, j, N4, minval=-1, maxval=1): + N = [1, 1, 1, N4] + shape = (N[i - 1], N[j - 1]) + """ + Initialize real matrices randomly, and combine to make them complex + """ + rand_real = np.random.uniform(size=shape, low=minval, high=maxval) + rand_imag = np.random.uniform(size=shape, low=minval, high=maxval) + z = np.array(rand_real, dtype=complex) + z.imag = rand_imag + return torch.tensor(z, requires_grad=True) + + +def phi(N4, minval=-1, maxval=1): + shape = (N4, N4) + """ + Initialize real matrices randomly, and combine to make them complex + """ + rand_real = np.random.uniform(size=shape, low=minval, high=maxval) + rand_imag = np.random.uniform(size=shape, low=minval, high=maxval) + z = np.array(rand_real, dtype=complex) + z.imag = rand_imag + return torch.tensor(z, requires_grad=True) + + +def phi_gauged(N4, minval=-1, maxval=1): + shape = (1, N4) + """ + Initialize real matrices randomly, and combine to make them complex + """ + rand_real = np.random.uniform(size=shape, low=minval, high=maxval) + rand_imag = np.random.uniform(size=shape, low=minval, high=maxval) + z = np.array(rand_real, dtype=complex) + z.imag = rand_imag + return torch.tensor(z, requires_grad=True) + + +def phi_constant(N4): + shape = (N4 - 1, N4) + rand_real = np.ones(shape) + rand_imag = np.zeros(shape) + z = np.array(rand_real, dtype=complex) + z.imag = rand_imag + return torch.tensor(z, requires_grad=False) + + + +def Z_gauged(i, j, N4): + N = [1, 1, 1, N4] + shape = (N[i - 1], N[j - 1]) + """ + Initialize a zeros matrix, and replace the last element with 1 + """ + rand_real = np.zeros(shape, dtype = complex) + rand_real[-1, -1] = 1 + return torch.tensor(rand_real, requires_grad=False) + + +def commutator(a,b): + return torch.mm(a, b) - torch.mm(b, a) + + +def brane_potential(Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi_gauged, phi2, phi3, phi12, phi23, phi31, phi_constant, C): + N4 = Z14.shape[1] + phi1 = torch.cat((phi_constant, phi_gauged), dim=0) + + F12_sqnorm = torch.norm(torch.mm(Z12, Z21) + C[0,1])**2 + F23_sqnorm = torch.norm(torch.mm(Z23, Z32) + C[1,2])**2 + F31_sqnorm = torch.norm(torch.mm(Z31, Z13) + C[0,2])**2 + F41_sqnorm = torch.norm(torch.mm(Z41, Z14) + C[0,3] * torch.eye(N4, dtype=torch.complex128) + commutator(phi2, phi3))**2 + F42_sqnorm = torch.norm(torch.mm(Z42, Z24) + C[1,3] * torch.eye(N4, dtype=torch.complex128) + commutator(phi3, phi1))**2 + F43_sqnorm = torch.norm(torch.mm(Z43, Z34) + C[2,3] * torch.eye(N4, dtype=torch.complex128) - commutator(phi2, phi1))**2 + G21_sqnorm = torch.norm(torch.mm(Z21, phi12) + torch.mm(Z23, Z31) + torch.mm(Z24, Z41))**2 + G12_sqnorm = torch.norm(torch.mm(Z12, phi12) + torch.mm(Z13, Z32) + torch.mm(Z14, Z42))**2 + G31_sqnorm = torch.norm(torch.mm(Z31, phi31) + torch.mm(Z32, Z21) - torch.mm(Z34, Z41))**2 + G13_sqnorm = torch.norm(torch.mm(Z13, phi31) + torch.mm(Z12, Z23) + torch.mm(Z14, Z43))**2 + G32_sqnorm = torch.norm(torch.mm(Z32, phi23) + torch.mm(Z31, Z12) + torch.mm(Z34, Z42))**2 + G23_sqnorm = torch.norm(torch.mm(Z23, phi23) + torch.mm(Z21, Z13) + torch.mm(Z24, Z43))**2 + G14_sqnorm = torch.norm(-torch.mm(Z14, phi1) + torch.mm(Z12, Z24) - torch.mm(Z13, Z34))**2 + G24_sqnorm = torch.norm(-torch.mm(Z24, phi2) + torch.mm(Z21, Z14) + torch.mm(Z23, Z34))**2 + G34_sqnorm = torch.norm(-torch.mm(Z34, phi3) + torch.mm(Z31, Z14) + torch.mm(Z32, Z24))**2 + G41_sqnorm = torch.norm(-torch.mm(phi1, Z41) + torch.mm(Z42, Z21) + torch.mm(Z43, Z31))**2 + G42_sqnorm = torch.norm(-torch.mm(phi2, Z42) + torch.mm(Z43, Z32) + torch.mm(Z41, Z12))**2 + G43_sqnorm = torch.norm(-torch.mm(phi3, Z43) - torch.mm(Z41, Z13) + torch.mm(Z42, Z23))**2 + + return (G21_sqnorm + G12_sqnorm + G31_sqnorm + G13_sqnorm + G32_sqnorm + G23_sqnorm + + F12_sqnorm + F23_sqnorm + F31_sqnorm + F41_sqnorm + F42_sqnorm + F43_sqnorm + + G14_sqnorm + G24_sqnorm + G34_sqnorm + G41_sqnorm + G42_sqnorm + G43_sqnorm) + + +def run_optimization(var_dict, arg_dict, C, optimizer_class, n_iter, **optimizer_kwargs): + + optimizer = optimizer_class(var_dict.values(), **optimizer_kwargs) + all_args = {**var_dict,**arg_dict} + + path = np.empty((n_iter + 1, len(var_dict)), dtype=complex) + # path[0, :] = list(var_dict.values()) + + for i in tqdm(range(1, n_iter + 1)): + optimizer.zero_grad() + loss = brane_potential(**all_args, C=C) + loss.backward() + torch.nn.utils.clip_grad_norm_(var_dict.values(), 1e+6) + optimizer.step() + print(loss, var_dict['Z13']) + # path[i, :] = var_args.detach().numpy() + + return path + + +if __name__ == "__main__": + N4=2 + C = torch.tensor([[0, 2/3, 3/5, 5/7],[0, 0, 7/11, 11/13],[0, 0, 0, 13/17]], dtype=torch.complex128, requires_grad=False) + var_dict = {'Z13': Z(1, 3, N4, minval=0, maxval=1), 'Z14': Z(1, 4, N4), 'Z21': Z(2, 1, N4), + 'Z24': Z(2, 4, N4), 'Z31': Z(3, 1, N4), + 'Z32': Z(3, 2, N4), 'Z41': Z(4, 1, N4), 'Z42': Z(4, 2, N4), + 'Z43': Z(4, 3, N4), 'phi_gauged': phi_gauged(N4),'phi2': phi(N4), + 'phi3': phi(N4), 'phi12': phi(1), 'phi23':phi(1), 'phi31': phi(1)} + arg_dict = {'Z12':Z_gauged(1, 2, N4), 'Z23': Z_gauged(2, 3, N4), 'Z34': Z_gauged(3, 4, N4), 'phi_constant': phi_constant(N4)} + + n_iter = 10000 + + path_sgd = run_optimization(var_dict, arg_dict, C, SGD, n_iter, lr=1e-2, momentum=0.99) + # path_adam = run_optimization(var_dict, arg_dict, C, Adam, n_iter, lr=1e-2) + # path_RMS = run_optimization(var_dict, arg_dict, C, RMSprop, n_iter, lr=1e-1, momentum=0.0) + + + print(arg_dict, C) + # print(path_sgd[-1], C, sep='\n') + + quit() diff --git a/SGD_write.py b/SGD_write.py new file mode 100644 index 0000000..50b6e2c --- /dev/null +++ b/SGD_write.py @@ -0,0 +1,591 @@ +#!/usr/bin/python3 + +import os +import time +import pickle +import tensorflow as tf +import numpy as np +from copy import deepcopy +import collections +import matplotlib.pyplot as plt +import pandas as pd +# num_stacks = 4 +real_dtype = tf.float64 +complex_dtype = tf.complex128 +os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' + + +def C(i, j): + if (i, j) == (1, 2): + return tf.cast(2 / 3, dtype=complex_dtype) + elif (i, j) == (1, 3): + return tf.cast(3 / 5, dtype=complex_dtype) + elif (i, j) == (1, 4): + return tf.cast(5 / 7, dtype=complex_dtype) + elif (i, j) == (2, 3): + return tf.cast(7 / 11, dtype=complex_dtype) + elif (i, j) == (2, 4): + return tf.cast(11 / 13, dtype=complex_dtype) + elif (i, j) == (3, 4): + return tf.cast(13 / 17, dtype=complex_dtype) + + +def eq26(Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3, phi12, phi23, phi31): + [val.assign(tf.math.multiply(val, scale)) if isinstance(val, tf.Variable) else tf.math.multiply(val, scale) + for val in [Z13, Z14, Z23, Z24, Z31, Z32, Z41, Z42]] + [val.assign(tf.math.multiply(val, tf.math.pow(scale, 2))) if isinstance(val, tf.Variable) + else tf.math.multiply(val, tf.math.pow(scale, 2)) for val in [phi3, phi12]] + return [Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3, phi12, phi23, phi31] + + +def complex_id(N4): + return tf.cast(tf.eye(N4, N4), complex_dtype) + + +def commutator(a, b): + return tf.matmul(a, b) - tf.matmul(b, a) + + +def triple_mul(a, b, c): + return tf.matmul(a, tf.matmul(b, c)) + + +def F12(Z12, Z21): + return tf.matmul(Z12, Z21) + C(1, 2) + + +def F23(Z23, Z32): + return tf.matmul(Z23, Z32) + C(2, 3) + + +def F31(Z13, Z31): + return tf.matmul(Z31, Z13) + C(1, 3) + + +def F41(Z14, Z41, phi2, phi3): + N4 = Z41.shape[0] + return tf.matmul(Z41, Z14) + C(1, 4) * complex_id(N4) + commutator(phi2, phi3) + + +def F42(Z24, Z42, phi1, phi3): + N4 = Z42.shape[0] + return tf.matmul(Z42, Z24) + C(2, 4) * complex_id(N4) + commutator(phi3, phi1) + + +def F43(Z34, Z43, phi1, phi2): + N4 = Z43.shape[0] + return tf.matmul(Z43, Z34) + C(3, 4) * complex_id(N4) - commutator(phi2, phi1) + + +def G21(Z21, Z23, Z24, Z31, Z41, phi12): + return tf.matmul(Z21, phi12) + tf.matmul(Z23, Z31) + tf.matmul(Z24, Z41) + + +def G12(Z12, Z13, Z14, Z32, Z42, phi12): + return tf.matmul(Z12, phi12) + tf.matmul(Z13, Z32) + tf.matmul(Z14, Z42) + + +def G31(Z21, Z31, Z32, Z34, Z41, phi31): + return tf.matmul(Z31, phi31) + tf.matmul(Z32, Z21) - tf.matmul(Z34, Z41) + + +def G13(Z12, Z13, Z14, Z23, Z43, phi31): + return tf.matmul(Z13, phi31) + tf.matmul(Z12, Z23) + tf.matmul(Z14, Z43) + + +def G32(Z12, Z31, Z32, Z34, Z42, phi23): + return tf.matmul(Z32, phi23) + tf.matmul(Z31, Z12) + tf.matmul(Z34, Z42) + + +def G23(Z13, Z21, Z23, Z24, Z43, phi23): + return tf.matmul(Z23, phi23) + tf.matmul(Z21, Z13) + tf.matmul(Z24, Z43) + + +def G14(Z12, Z13, Z14, Z24, Z34, phi1): + return -tf.matmul(Z14, phi1) + tf.matmul(Z12, Z24) - tf.matmul(Z13, Z34) + + +def G24(Z14, Z21, Z23, Z24, Z34, phi2): + return -tf.matmul(Z24, phi2) + tf.matmul(Z21, Z14) + tf.matmul(Z23, Z34) + + +def G34(Z14, Z24, Z31, Z32, Z34, phi3): + return -tf.matmul(Z34, phi3) + tf.matmul(Z31, Z14) + tf.matmul(Z32, Z24) + + +def G41(Z21, Z31, Z41, Z42, Z43, phi1): + return -tf.matmul(phi1, Z41) + tf.matmul(Z42, Z21) + tf.matmul(Z43, Z31) + + +def G42(Z12, Z32, Z41, Z42, Z43, phi2): + return -tf.matmul(phi2, Z42) + tf.matmul(Z43, Z32) + tf.matmul(Z41, Z12) + + +def G43(Z13, Z23, Z41, Z42, Z43, phi3): + return -tf.matmul(phi3, Z43) - tf.matmul(Z41, Z13) + tf.matmul(Z42, Z23) + + +def reverse_get_vars(arg_list): + """Given that we only store the original set of solutions, the tf.Variable and tf.tensor + structure should be preserved, except in the phi_gauged one(s). So just look for that, separate + it into 2, convert the bottom into a variable, and you're done""" + + # arg_list = [tf.Variable(val) if not tf.equal(tf.math.real( + # val[0, 0]), 0.) and i != 0 and i != 4 else val for (i, val) in enumerate(arg_list)] + + for i in [12, 13, 14]: + if not isinstance(arg_list[i], tf.Variable): + N4 = arg_list[i].shape[1] + top_phi, arg_list[i] = tf.split(arg_list[i], [N4 - 1, 1], 0) + arg_list[i] = tf.Variable(arg_list[i], name="phi_gauged") + arg_list.append(top_phi) + + return arg_list + + +def neg_vars(arg_list): + return [-arg for arg in arg_list] + + +def conj_vars(arg_list): + return [tf.math.conj(arg) for arg in arg_list] + + +def saddle1(Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3, phi12, phi23, phi31, top_phi): + [val.assign(val * 0, read_value=True) for val in [Z21, Z31, Z32, + Z41, phi12, phi23, phi31] if isinstance(val, tf.Variable)] + return [Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3, phi12, phi23, phi31, top_phi] + + +def saddle2(Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3, phi12, phi23, phi31, top_phi): + [val.assign(val * 0, read_value=True) for val in [Z21, Z31, Z32, + Z34, phi1, phi12, phi23, phi31] if isinstance(val, tf.Variable)] + return [Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3, phi12, phi23, phi31, top_phi] + + +def full_vars(Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3, phi12, phi23, phi31, top_phi): + phi1, phi2, phi3 = [make_mat(val, top_phi) if val.name == + '1:0' or val.name == '2:0' else val for val in [phi1, phi2, phi3]] + return [Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3, phi12, phi23, phi31] + + +def mat_power(a, n): + if n == 0: + return complex_id(a.shape[0]) + elif n == 1: + return tf.math.pow(a, n) + else: + b = a + for _ in range(1, n): + b = tf.matmul(b, a) + return b + + +def B_invariant(Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3, phi12, phi23, phi31): + N4 = phi1.shape[0] + B = [] + """Append phi12, phi12, phi23, phi31 first""" + + B.append(tf.math.divide(phi12, 1.)[0, 0]) + B.append(tf.math.divide(phi23, 1.)[0, 0]) + B.append(tf.math.divide(phi31, 1.)[0, 0]) + + """Adding Tr(phi1), Tr(phi2), and Tr(phi3)""" + B.append(tf.math.divide(tf.linalg.trace(phi1), 1.)) + B.append(tf.math.divide(tf.linalg.trace(phi2), 1.)) + B.append(tf.math.divide(tf.linalg.trace(phi3), 1.)) + + """The next 3 are u7, u8, and u9 respectively""" + B.append(triple_mul(Z12, Z24, Z41)[0, 0]) + B.append(triple_mul(Z13, Z34, Z41)[0, 0]) + B.append(triple_mul(Z23, Z34, Z42)[0, 0]) + # for n in range(1, N4 + 1): + # B.append(tf.matmul(tf.matmul(Z14, (mat_power(phi1, n))), + # tf.matmul(mat_power(phi2, N4 - n), Z41))[0, 0]) + # B.append(tf.matmul(tf.matmul(Z24, (mat_power(phi2, n))), + # tf.matmul(mat_power(phi3, N4 - n), Z42))[0, 0]) + # B.append(tf.matmul(tf.matmul(Z34, (mat_power(phi3, n))), + # tf.matmul(mat_power(phi1, N4 - n), Z43))[0, 0]) + return B + + +def write_markers(arg_list, data_dict, loss): + data_dict['loss'].append(loss.numpy()) + B = B_invariant(*arg_list) + for i in range(len(B)): + data_dict[str(i) + '-real'].append(tf.math.real(B[i]).numpy()) + data_dict[str(i) + '-imag'].append(tf.math.imag(B[i]).numpy()) + + +def brane_potential(Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3, phi12, phi23, phi31, top_phi): + + Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3, phi12, phi23, phi31 = full_vars( + Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3, phi12, phi23, phi31, top_phi) + + G21_sqnorm = tf.norm(G21(Z21, Z23, Z24, Z31, Z41, phi12)) ** 2 + G12_sqnorm = tf.norm(G12(Z12, Z13, Z14, Z32, Z42, phi12)) ** 2 + G31_sqnorm = tf.norm(G31(Z21, Z31, Z32, Z34, Z41, phi31)) ** 2 + G13_sqnorm = tf.norm(G13(Z12, Z13, Z14, Z23, Z43, phi31)) ** 2 + G32_sqnorm = tf.norm(G32(Z12, Z31, Z32, Z34, Z42, phi23)) ** 2 + G23_sqnorm = tf.norm(G23(Z13, Z21, Z23, Z24, Z43, phi23)) ** 2 + + F12_sqnorm = tf.norm(F12(Z12, Z21)) ** 2 + F23_sqnorm = tf.norm(F23(Z23, Z32)) ** 2 + F31_sqnorm = tf.norm(F31(Z13, Z31)) ** 2 + F41_sqnorm = tf.norm(F41(Z14, Z41, phi2, phi3)) ** 2 + F42_sqnorm = tf.norm(F42(Z24, Z42, phi1, phi3)) ** 2 + F43_sqnorm = tf.norm(F43(Z34, Z43, phi1, phi2)) ** 2 + + G14_sqnorm = tf.norm(G14(Z12, Z13, Z14, Z24, Z34, phi1)) ** 2 + G24_sqnorm = tf.norm(G24(Z14, Z21, Z23, Z24, Z34, phi2)) ** 2 + G34_sqnorm = tf.norm(G34(Z14, Z24, Z31, Z32, Z34, phi3)) ** 2 + G41_sqnorm = tf.norm(G41(Z21, Z31, Z41, Z42, Z43, phi1)) ** 2 + G42_sqnorm = tf.norm(G42(Z12, Z32, Z41, Z42, Z43, phi2)) ** 2 + G43_sqnorm = tf.norm(G43(Z13, Z23, Z41, Z42, Z43, phi3)) ** 2 + + return tf.math.real(G21_sqnorm + G12_sqnorm + G31_sqnorm + G13_sqnorm + G32_sqnorm + G23_sqnorm + + F12_sqnorm + F23_sqnorm + F31_sqnorm + F41_sqnorm + F42_sqnorm + F43_sqnorm + + G14_sqnorm + G24_sqnorm + G34_sqnorm + G41_sqnorm + G42_sqnorm + G43_sqnorm) + + +def brane_potential_joined(Z12, Z13, Z14, Z21, Z23, Z24, Z31, Z32, Z34, Z41, Z42, Z43, phi1, phi2, phi3, phi12, phi23, phi31): + + G21_sqnorm = tf.norm(G21(Z21, Z23, Z24, Z31, Z41, phi12)) ** 2 + G12_sqnorm = tf.norm(G12(Z12, Z13, Z14, Z32, Z42, phi12)) ** 2 + G31_sqnorm = tf.norm(G31(Z21, Z31, Z32, Z34, Z41, phi31)) ** 2 + G13_sqnorm = tf.norm(G13(Z12, Z13, Z14, Z23, Z43, phi31)) ** 2 + G32_sqnorm = tf.norm(G32(Z12, Z31, Z32, Z34, Z42, phi23)) ** 2 + G23_sqnorm = tf.norm(G23(Z13, Z21, Z23, Z24, Z43, phi23)) ** 2 + + F12_sqnorm = tf.norm(F12(Z12, Z21)) ** 2 + F23_sqnorm = tf.norm(F23(Z23, Z32)) ** 2 + F31_sqnorm = tf.norm(F31(Z13, Z31)) ** 2 + F41_sqnorm = tf.norm(F41(Z14, Z41, phi2, phi3)) ** 2 + F42_sqnorm = tf.norm(F42(Z24, Z42, phi1, phi3)) ** 2 + F43_sqnorm = tf.norm(F43(Z34, Z43, phi1, phi2)) ** 2 + + G14_sqnorm = tf.norm(G14(Z12, Z13, Z14, Z24, Z34, phi1)) ** 2 + G24_sqnorm = tf.norm(G24(Z14, Z21, Z23, Z24, Z34, phi2)) ** 2 + G34_sqnorm = tf.norm(G34(Z14, Z24, Z31, Z32, Z34, phi3)) ** 2 + G41_sqnorm = tf.norm(G41(Z21, Z31, Z41, Z42, Z43, phi1)) ** 2 + G42_sqnorm = tf.norm(G42(Z12, Z32, Z41, Z42, Z43, phi2)) ** 2 + G43_sqnorm = tf.norm(G43(Z13, Z23, Z41, Z42, Z43, phi3)) ** 2 + + return tf.math.real(G21_sqnorm + G12_sqnorm + G31_sqnorm + G13_sqnorm + G32_sqnorm + G23_sqnorm + + F12_sqnorm + F23_sqnorm + F31_sqnorm + F41_sqnorm + F42_sqnorm + F43_sqnorm + + G14_sqnorm + G24_sqnorm + G34_sqnorm + G41_sqnorm + G42_sqnorm + G43_sqnorm) + + +def saddle_optimize(arguments, solution): + var_list = [val for val in arguments if isinstance(val, tf.Variable)] + + sol_list = [solution, neg_vars(solution), conj_vars( + solution), neg_vars(conj_vars(solution))] + + def loss(): + V0 = brane_potential(*arguments) + for sols in sol_list: + ex = tf.math.real((tf.math.tanh( + 5 * (sum([tf.norm(arguments[i] - sols[i])**2 for i in range(len(sols))]) - 1)) + 1) / 2) + V0 = ex * V0 + 5 * (1 - ex) + return V0 + + loss_vals = [loss()] + + num_cycles = 60 + learning_rate = min(1e-3, 1 / loss_vals[0]) + momentum = 0.99 + + print('saddle beginning_loss:', loss_vals[-1], 'Z12:', + arguments[0], '\n phi31:', solution[-2]) + + for cycle in range(num_cycles): + + # print('cycle_1:', cycle, "V:", loss_vals[-1]) + # print('learning rate:', learning_rate) + + opt = tf.keras.optimizers.SGD( + learning_rate=learning_rate, momentum=momentum) + + @tf.function + def opt_cycle1(): + for _ in tf.range(1e+4): + opt.minimize(loss, var_list=var_list) + + opt_cycle1() + + loss_vals.append(loss()) + + if tf.math.is_nan(loss_vals[-1]) or loss_vals[-1] < 1e-17 or cycle > int(num_cycles / 2) and loss_vals[-1] > 1e-3: + break + elif loss_vals[-1] < loss_vals[-2]: + learning_rate = min(learning_rate * 2, 1e-2) + elif loss_vals[-1] > loss_vals[-2]: + learning_rate /= 1.1 + + print('saddle end_loss:', loss_vals[-1], 'Z12:', + arguments[0], '\n phi31:', arguments[-2]) + + return loss_vals[-1], arguments + + +def optimize_2loops(arguments): + + var_list = [val for val in arguments if isinstance(val, tf.Variable)] + + def loss(): + return brane_potential(*arguments) + + loss_vals = [loss()] + + num_cycles = 100 + learning_rate = min(1e-3, 1 / loss_vals[0]) + momentum = 0.99 + + print('beginning_loss:', loss_vals[-1], 'Z12:', + arguments[0], '\n phi31:', arguments[-2]) + + for cycle in range(num_cycles): + + # print('cycle_1:', cycle, "V:", loss_vals[-1]) + # print('learning rate:', learning_rate) + + opt = tf.keras.optimizers.SGD( + learning_rate=learning_rate, momentum=momentum) + + @tf.function + def opt_cycle1(): + for _ in tf.range(1e+3): + opt.minimize(loss, var_list=var_list) + + opt_cycle1() + + loss_vals.append(loss()) + + if tf.math.is_nan(loss_vals[-1]) or loss_vals[-1] < 1e-21 or cycle > int(num_cycles / 2) and loss_vals[-1] > 1e-3: + break + elif loss_vals[-1] < loss_vals[-2]: + learning_rate = min(learning_rate * 2, 1e-2) + elif loss_vals[-1] > loss_vals[-2]: + learning_rate /= 1.1 + + print('end_loss:', loss_vals[-1], 'Z12:', + arguments[0], '\n phi31:', arguments[-2]) + + return loss_vals[-1], arguments + + +from random import sample + + +def main_distill(N4): + + result_dir = '../input/brane-sgd-variables/' + result_dir = './Good Results/' + data_filename = 'variables_N4={}.combined'.format(N4) + + start_time = time.time() # at the beginning of the program + with open(result_dir + data_filename + '.data', 'rb') as filehandle: + # read the data as binary data stream + loaded_variables = pickle.load(filehandle) + unique_list = [] + + def distance(a, b): + return tf.math.real(sum([tf.norm(a[i] - b[i])**2 for i in range(len(a))])) + + dist_threshold = 1e-4 + # loaded_variables = sample(loaded_variables, min(100, len(loaded_variables))) + # loaded_variables = loaded_variables[:int(len(loaded_variables)/2)] + + print("N4:", N4, 'total samples:', len(loaded_variables)) + + # traverse for all elements + for arg_list in loaded_variables: + flipper = 1 + # check if exists in unique_list or not + for (i, sol_list) in enumerate(unique_list): + a_dist = distance(B_invariant(*arg_list), B_invariant(*sol_list)) + b_dist = distance(B_invariant(*arg_list), + B_invariant(*neg_vars(sol_list))) + c_dist = distance(B_invariant(*arg_list), + B_invariant(*conj_vars(sol_list))) + d_dist = distance(B_invariant(*arg_list), + B_invariant(*neg_vars(conj_vars(sol_list)))) + if a_dist < dist_threshold or b_dist < dist_threshold or c_dist < dist_threshold or d_dist < dist_threshold: + arg_loss, sol_loss = brane_potential_joined( + *arg_list), brane_potential_joined(*sol_list) + print('distance:', min(a_dist, b_dist, c_dist, d_dist)) + if arg_loss < sol_loss: + unique_list[i] = arg_list + flipper *= 0 + break + + if flipper: + unique_list.append(arg_list) + print(len(unique_list)) + + for sols in unique_list: + print('loss:', brane_potential_joined(*sols), 'phi31:', sols[-1]) + + dist_matrix = [[distance(a, b) for a in unique_list] + for b in unique_list] + dist_matrix = np.asarray(dist_matrix) + plt.imshow(dist_matrix) + plt.savefig('distance_{}.png'.format(data_filename), dpi=len(unique_list)) + # plt.gray() + plt.show() + + print("N4:", N4, "number of runs:", len(loaded_variables), + 'results_length:', len(unique_list)) + + with open(data_filename + 'distilled.data', 'wb') as filehandle: + pickle.dump(unique_list, filehandle) + + end_time = time.time() # at the beginning of the program + print('for N4 = {}..... time taken = {} seconds'.format( + N4, round(end_time - start_time, 2))) + + +def main_saddle(N4): + + result_dir = '../input/brane-sgd-variables/' + result_dir = './' + data_filename = 'variables_N4={}'.format(N4) + + solutions_list = [] + markers = collections.defaultdict(list) + + start_time = time.time() # at the beginning of the program + with open(result_dir + data_filename + '.data', 'rb') as filehandle: + # read the data as binary data stream + loaded_variables = pickle.load(filehandle) + + # loaded_variables = sample(loaded_variables, min(2, len(loaded_variables))) + # loaded_variables = loaded_variables[:int(len(loaded_variables)/2)] + + print("N4:", N4, 'total samples:', len(loaded_variables)) + + threshold = 1e-6 + for arg_list in loaded_variables: + + arg_list = reverse_get_vars(list(arg_list)) + saddle_init_args = saddle2(*deepcopy(arg_list)) + + sol_loss, sol_list = saddle_optimize(saddle_init_args, arg_list) + if sol_loss < threshold: + full_sols = full_vars(*sol_list) + + print('.....') + + """Only ever append the original solution to the .data file. + It preserves the tensor and variable structure""" + + solutions_list.append(full_sols) + write_markers(full_sols, markers, sol_loss) + + write_markers(neg_vars(full_sols), markers, sol_loss) + + write_markers(conj_vars(full_sols), markers, sol_loss) + + write_markers(conj_vars(neg_vars(full_sols)), + markers, sol_loss) + + print('*' * 8) + for sol_list in solutions_list: + print(sol_list[-1]) + + print("N4:", N4, "number of runs:", len(loaded_variables), + 'results_length:', len(solutions_list)) + + with open(data_filename + 'rerun.data', 'wb') as filehandle: + pickle.dump(solutions_list, filehandle) + + (pd.DataFrame.from_dict(data=markers, orient='columns').to_csv( + data_filename + '.csv'.format(N4), header=True, index=False)) + + print('csv results_length:', len(markers['loss'])) + + end_time = time.time() # at the beginning of the program + print('for N4 = {}..... time taken = {} seconds'.format( + N4, round(end_time - start_time, 2))) + print(">>> Dumped to {}.csv".format(data_filename)) + + +def main_write(N4): + + result_dir = '../input/brane-sgd-variables/' + result_dir = './Good Results/data/' + data_filename = 'variables_N4={}'.format(N4) + + solutions_list = [] + markers = collections.defaultdict(list) + + start_time = time.time() # at the beginning of the program + with open(result_dir + data_filename + '.data', 'rb') as filehandle: + # read the data as binary data stream + loaded_variables = pickle.load(filehandle) + + # print(*loaded_variables[1], sep='\n') + # loaded_variables = loaded_variables[:int(len(loaded_variables) / 2)] + # loaded_variables = [loaded_variables[1]] + + print("N4:", N4, 'total samples:', len(loaded_variables)) + + threshold = 1e-6 + threshold1 = 1e-15 + for arg_list in loaded_variables: + + # arg_list = interfere(list(arg_list)) + # print(*arg_list, sep='\n') + + sol_loss = brane_potential_joined(*arg_list) + print(sol_loss) + print(arg_list[12], arg_list[13], arg_list[14], arg_list[-1]) + + # if sol_loss > threshold: + # sol_loss, sol_list = optimize_2loops(arg_list) + + if sol_loss < threshold: + # full_sols = full_vars(*arg_list) + full_sols = arg_list + + # print('loss:', sol_loss, 'phi31:', full_sols[-1]) + print('.....') + + """Only ever append the original solution to the .data file. + It preserves the tensor and variable structure""" + + solutions_list.append(full_sols) + write_markers(full_sols, markers, sol_loss) + + write_markers(neg_vars(full_sols), markers, sol_loss) + + write_markers(conj_vars(full_sols), markers, sol_loss) + + write_markers(conj_vars(neg_vars(full_sols)), + markers, sol_loss) + + for sol_list in solutions_list: + print(sol_list[-1]) + + print("N4:", N4, "number of runs:", len(loaded_variables), + 'results_length:', len(solutions_list)) + + # with open(data_filename + 'rerun.data', 'wb') as filehandle: + # pickle.dump(solutions_list, filehandle) + + (pd.DataFrame.from_dict(data=markers, orient='columns').to_csv( + data_filename + '.csv'.format(N4), header=True, index=False)) + + print('csv results_length:', len(markers['loss'])) + + end_time = time.time() # at the beginning of the program + print('for N4 = {}..... time taken = {} seconds'.format( + N4, round(end_time - start_time, 2))) + print(">>> Dumped to {}.csv".format(data_filename)) + + +if __name__ == "__main__": + N4 = 3 + main_distill(N4) + exit() diff --git a/requirements.txt b/requirements.txt new file mode 100755 index 0000000..382987e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +Keras==2.2.4 +pandas +tensorflow==1.14.0 +torch +tqdm diff --git a/scipy_optimize.py b/scipy_optimize.py new file mode 100644 index 0000000..54c142e --- /dev/null +++ b/scipy_optimize.py @@ -0,0 +1,50 @@ +#from https://stackoverflow.com/questions/53068908/scipy-optimize-fsolve-on-my-complex-equation + +import numpy as np +from scipy.optimize import minimize + +delta = 84.37228318652858 * np.pi / 180 +psi = 55.2217535040673 * np.pi / 180 +n_S = 2.6726 + 3.0375j +phi_i = 70 * np.pi / 180 +d_L = 300 # thickness of layer in nm +n_air = 1 # refractive index of air + + +def snell(phi, n1, n2): + phi_ref = np.arcsin((n1 / n2) * np.sin(phi)) + return phi_ref + + +def fresnel(n1, phi1, n2, phi2): + rs = (n1 * np.cos(phi1) - n2 * np.cos(phi2)) / ( + n1 * np.cos(phi1) + n2 * np.cos(phi2)) + rp = (n2 * np.cos(phi1) - n1 * np.cos(phi2)) / ( + n2 * np.cos(phi1) + n1 * np.cos(phi2)) + return rs, rp + + +def calc_rho(n_k): + n = n_k[0] + k = n_k[1] + n_L = n + 1j * k + phi_L = snell(phi_i, n_air, n_L) + phi_S = snell(phi_L, n_L, n_S) + rs_al, rp_al = fresnel(n_air, phi_i, n_L, phi_L) + rs_ls, rp_ls = fresnel(n_L, phi_L, n_S, phi_S) + beta = 2 * np.pi * d_L * n_L * np.cos(phi_L) / lambda_vac + rp_L = (rp_al + rp_ls * np.exp(-2 * 1j * beta)) / ( + 1 + rp_al * rp_ls * np.exp(-2 * 1j * beta)) + rs_L = (rs_al + rs_ls * np.exp(-2 * 1j * beta)) / ( + 1 + rs_al * rs_ls * np.exp(-2 * 1j * beta)) + rho_L = rp_L / rs_L + return abs(rho_L - rho_given) + + +lambda_vac = 300 +n_S = 2.6726 + 3.0375j +rho_given = np.tan(psi) * np.exp( + 1j * delta) # should be 1.4399295435287844+0.011780279522394433j +initialGuess = [1.5, 0.1] +nsolve = minimize(calc_rho, initialGuess, method='Nelder-Mead') +print(nsolve) \ No newline at end of file diff --git a/tensorflow_python_methods.png b/tensorflow_python_methods.png new file mode 100644 index 0000000000000000000000000000000000000000..56138b003b76464771dec9fa8e10ed5b6f7b8e3b GIT binary patch literal 127456 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 z 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 jg8I1@cb!>Z 0: + unique_solutions_dval_set = functions.uniquify(solutions_list, dval_list) + unique_solutions_list = [item[0] for item in unique_solutions_dval_set] + + s = functions.SUSY_coeff + t = time.time() + fname = f"U1info_variables_N4={N4}_s={s}_t={t}" + fname_sol = f"U1info_solutions_N4={N4}_s={s}_t={t}" + + # with open(fname_sol + ".data", "wb") as filehandle: + # pickle.dump(unique_solutions_list, filehandle) + + for sol_dict, dval in unique_solutions_dval_set: + functions.write_markers_U1(sol_dict, markers, dval) + functions.write_full_solution_U1(sol_dict, solutions_to_print, dval) + + # functions.write_markers_U1(functions.neg_vars(sol_dict), markers, dval) + + # functions.write_markers_U1(functions.conj_vars(sol_dict), markers, dval) + + # functions.write_markers_U1( + # functions.conj_vars(functions.neg_vars(sol_dict)), markers, dval + # ) + + pd.DataFrame.from_dict(data=markers, orient="columns").to_csv( + fname + ".csv", header=True, index=False + ) + pd.DataFrame.from_dict(data=solutions_to_print, orient="columns").to_csv( + fname_sol + ".csv", header=True, index=False + ) + else: + unique_solutions_list = [] + + print("number of runs:", num_runs, "results_length:", len(unique_solutions_list)) + + +if __name__ == "__main__": + start_time = time.time() # at the beginning of the program + + N4 = 1 + num_runs = 36 + n_steps = 6e4 + learning_rate = 2e-4 + functions = Functions(N4) + fi = functions.FI + c = functions.C + result = (1 / 2) * (fi[0] ** 2 + fi[1] ** 2 + fi[2] ** 2 + fi[3] ** 2) + 4 * ( + c[0, 1] ** 2 + + c[0, 2] ** 2 + + c[0, 3] ** 2 + + c[1, 2] ** 2 + + c[1, 3] ** 2 + + c[2, 3] ** 2 + ) + print('fi:', fi) + print("c:", c) + print(result) + # main(N4, num_runs, n_steps, learning_rate) + end_time = time.time() # at the end of the program + print(f"for N4 = {N4}..... time taken = {round(end_time - start_time, 2)} seconds") + exit() diff --git a/u1_susy_sgd.py b/u1_susy_sgd.py new file mode 100644 index 0000000..72d278e --- /dev/null +++ b/u1_susy_sgd.py @@ -0,0 +1,742 @@ +import time +import collections +from tqdm import tqdm +import tensorflow as tf +import numpy as np +import pandas as pd +import pickle +import pathos.multiprocessing as mp + + +class Variables: + """Class for generating the variables and constants of the system""" + + def __init__(self, N4): + self.N4 = N4 + + def Z(self, i, j, minval=-3, maxval=3, name="Z"): + N = [1, 1, 1, self.N4] + shape = (N[i - 1], N[j - 1]) + """ + Initialize real matrices randomly, and combine to make them complex + """ + rand_real = np.random.uniform(size=shape, low=minval, high=maxval) + rand_imag = np.random.uniform(size=shape, low=minval, high=maxval) + z = np.array(rand_real, dtype=complex) + z.imag = rand_imag + return tf.Variable(z, name=name, trainable=True) + + def Z_gauged(self, i, j, name="ZGauged"): + N = [1, 1, 1, self.N4] + shape = (N[i - 1], N[j - 1]) + """ + Initialize a zeros matrix, and replace the last element with 1 + """ + rand_real = np.zeros(shape, dtype=complex) + rand_real[-1, -1] = 1 + return tf.constant(rand_real, name=name) + + def Z_U1gauged(self, i, j, minval=-3, maxval=3, name="ZU1"): + N = [1, 1, 1, self.N4] + shape = (N[i - 1], N[j - 1]) + rand_real = np.random.uniform(size=shape, low=minval, high=maxval) + return tf.Variable(rand_real, name=name, trainable=True) + + def phi(self, N, minval=-3, maxval=3, name="phiV"): + shape = (N, N) + """ + Initialize real matrices randomly, and combine to make them complex + """ + rand_real = np.random.uniform(size=shape, low=minval, high=maxval) + rand_imag = np.random.uniform(size=shape, low=minval, high=maxval) + z = np.array(rand_real, dtype=complex) + z.imag = rand_imag + return tf.Variable(z, name=name, trainable=True) + + +class Functions: + """Class for the transformations and functions of the variables.""" + + def __init__(self, N4): + self.N4 = N4 + self.num_cycles = 10 + self.C = tf.constant( + [[0, 2 / 3, 3 / 5, 5 / 7], [0, 0, 7 / 11, 11 / 13], [0, 0, 0, 13 / 17]], + dtype=tf.complex128, + ) + self.FI = tf.constant([1, 2, 3, -6], dtype=tf.complex128) + self.lam = tf.constant(1, dtype=tf.complex128) + self.SUSY_coeff_1 = 0.01 + self.SUSY_coeff_2 = 0.05 + self.SUSY_coeff_3 = 0.02 + + def commutator(self, a, b): + return tf.linalg.matmul(a, b) - tf.linalg.matmul(b, a) + + def distance(self, a, b): + """Sum of squares of distance between entries of two lists""" + return tf.math.real(sum([tf.norm(a[i] - b[i]) ** 2 for i in range(len(a))])) + + def neg_vars(self, input_dict): + """ + Negate each value in the input dictionary and return the modified dictionary. + + Args: + input_dict (dict): The input dictionary. + + Returns: + dict: A new dictionary with negated values. + """ + negated_dict = {key: -value for key, value in input_dict.items()} + return negated_dict + + def conj_vars(self, input_dict): + """ + Complex Conjugate each value in the input dictionary and return the modified dictionary. + + Args: + input_dict (dict): The input dictionary. + + Returns: + dict: A new dictionary with negated values. + """ + negated_dict = {key: tf.math.conj(value) for key, value in input_dict.items()} + return negated_dict + + def full_vars_U1( + self, + Z12, + Z13, + Z14, + Z21, + Z23, + Z24, + Z31, + Z32, + Z34, + Z41, + Z42, + Z43, + phi1, + phi2, + phi3, + phi12, + phi23, + phi31, + ): + Z12, Z23, Z34 = ( + tf.complex(Z12, tf.zeros_like(Z12)), + tf.complex(Z23, tf.zeros_like(Z23)), + tf.complex(Z34, tf.zeros_like(Z34)), + ) + return ( + Z12, + Z13, + Z14, + Z21, + Z23, + Z24, + Z31, + Z32, + Z34, + Z41, + Z42, + Z43, + phi1, + phi2, + phi3, + phi12, + phi23, + phi31, + ) + + def brane_potential( + self, + Z12, + Z13, + Z14, + Z21, + Z23, + Z24, + Z31, + Z32, + Z34, + Z41, + Z42, + Z43, + phi1, + phi2, + phi3, + phi12, + phi23, + phi31, + ): + F12_sqnorm = tf.norm(tf.linalg.matmul(Z12, Z21) + self.C[0, 1]) ** 2 + F21_sqnorm = tf.norm(tf.linalg.matmul(Z21, Z12) + self.C[0, 1]) ** 2 + + F23_sqnorm = tf.norm(tf.linalg.matmul(Z23, Z32) + self.C[1, 2]) ** 2 + F32_sqnorm = tf.norm(tf.linalg.matmul(Z32, Z23) + self.C[1, 2]) ** 2 + + F31_sqnorm = tf.norm(tf.linalg.matmul(Z31, Z13) + self.C[0, 2]) ** 2 + F13_sqnorm = tf.norm(tf.linalg.matmul(Z13, Z31) + self.C[0, 2]) ** 2 + + F41_sqnorm = ( + tf.norm( + tf.linalg.matmul(Z41, Z14) + + self.C[0, 3] * tf.eye(self.N4, dtype=tf.complex128) + + self.commutator(phi2, phi3) + ) + ** 2 + ) + F14_sqnorm = tf.norm(tf.linalg.matmul(Z14, Z41) + self.C[0, 3] * self.N4) ** 2 + F42_sqnorm = ( + tf.norm( + tf.linalg.matmul(Z42, Z24) + + self.C[1, 3] * tf.eye(self.N4, dtype=tf.complex128) + + self.commutator(phi3, phi1) + ) + ** 2 + ) + F24_sqnorm = tf.norm(tf.linalg.matmul(Z24, Z42) + self.C[1, 3] * self.N4) ** 2 + F43_sqnorm = ( + tf.norm( + tf.linalg.matmul(Z43, Z34) + + self.C[2, 3] * tf.eye(self.N4, dtype=tf.complex128) + - self.commutator(phi2, phi1) + ) + ** 2 + ) + F34_sqnorm = tf.norm(tf.linalg.matmul(Z34, Z43) + self.C[2, 3] * self.N4) ** 2 + G21_sqnorm = ( + tf.norm( + tf.linalg.matmul(Z21, phi12) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z23, Z31)) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z24, Z41)) + ) + ** 2 + ) + G12_sqnorm = ( + tf.norm( + tf.linalg.matmul(Z12, phi12) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z13, Z32)) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z14, Z42)) + ) + ** 2 + ) + G31_sqnorm = ( + tf.norm( + tf.linalg.matmul(Z31, phi31) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z32, Z21)) + - tf.math.multiply(self.lam, tf.linalg.matmul(Z34, Z41)) + ) + ** 2 + ) + G13_sqnorm = ( + tf.norm( + tf.linalg.matmul(Z13, phi31) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z12, Z23)) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z14, Z43)) + ) + ** 2 + ) + G32_sqnorm = ( + tf.norm( + tf.linalg.matmul(Z32, phi23) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z31, Z12)) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z34, Z42)) + ) + ** 2 + ) + G23_sqnorm = ( + tf.norm( + tf.linalg.matmul(Z23, phi23) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z21, Z13)) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z24, Z43)) + ) + ** 2 + ) + G14_sqnorm = ( + tf.norm( + -tf.linalg.matmul(Z14, phi1) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z12, Z24)) + - tf.math.multiply(self.lam, tf.linalg.matmul(Z13, Z34)) + ) + ** 2 + ) + G24_sqnorm = ( + tf.norm( + -tf.linalg.matmul(Z24, phi2) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z21, Z14)) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z23, Z34)) + ) + ** 2 + ) + G34_sqnorm = ( + tf.norm( + -tf.linalg.matmul(Z34, phi3) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z31, Z14)) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z32, Z24)) + ) + ** 2 + ) + G41_sqnorm = ( + tf.norm( + -tf.linalg.matmul(phi1, Z41) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z42, Z21)) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z43, Z31)) + ) + ** 2 + ) + G42_sqnorm = ( + tf.norm( + -tf.linalg.matmul(phi2, Z42) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z43, Z32)) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z41, Z12)) + ) + ** 2 + ) + G43_sqnorm = ( + tf.norm( + -tf.linalg.matmul(phi3, Z43) + - tf.math.multiply(self.lam, tf.linalg.matmul(Z41, Z13)) + + tf.math.multiply(self.lam, tf.linalg.matmul(Z42, Z23)) + ) + ** 2 + ) + D1_sqnorm = ( + tf.norm( + tf.norm(Z12) ** 2 + + tf.norm(Z13) ** 2 + + tf.norm(Z14) ** 2 + - tf.norm(Z21) ** 2 + - tf.norm(Z31) ** 2 + - tf.norm(Z41) ** 2 + - self.FI[0] + ) + ** 2 + ) + D2_sqnorm = ( + tf.norm( + tf.norm(Z21) ** 2 + + tf.norm(Z23) ** 2 + + tf.norm(Z24) ** 2 + - tf.norm(Z12) ** 2 + - tf.norm(Z32) ** 2 + - tf.norm(Z42) ** 2 + - self.FI[1] + ) + ** 2 + ) + D3_sqnorm = ( + tf.norm( + tf.norm(Z31) ** 2 + + tf.norm(Z32) ** 2 + + tf.norm(Z34) ** 2 + - tf.norm(Z13) ** 2 + - tf.norm(Z23) ** 2 + - tf.norm(Z43) ** 2 + - self.FI[2] + ) + ** 2 + ) + D4_sqnorm = ( + tf.norm( + tf.linalg.matmul(Z41, tf.math.conj(Z41)) + + tf.linalg.matmul(Z42, tf.math.conj(Z42)) + + tf.linalg.matmul(Z43, tf.math.conj(Z43)) + - tf.linalg.matmul(tf.math.conj(Z14), Z14) + - tf.linalg.matmul(tf.math.conj(Z24), Z24) + - tf.linalg.matmul(tf.math.conj(Z34), Z34) + + self.commutator(phi1, tf.math.conj(phi1)) + + self.commutator(phi2, tf.math.conj(phi2)) + + self.commutator(phi3, tf.math.conj(phi3)) + - self.FI[3] * tf.eye(self.N4, dtype=tf.complex128) / self.N4 + ) + ** 2 + ) + + return ( + ( + 2 + * ( + G21_sqnorm + + G12_sqnorm + + G31_sqnorm + + G13_sqnorm + + G32_sqnorm + + G23_sqnorm + + F12_sqnorm + + F21_sqnorm + + F23_sqnorm + + F32_sqnorm + + F31_sqnorm + + F13_sqnorm + + F14_sqnorm + + F24_sqnorm + + F34_sqnorm + + F41_sqnorm + + F42_sqnorm + + F43_sqnorm + + G14_sqnorm + + G24_sqnorm + + G34_sqnorm + + G41_sqnorm + + G42_sqnorm + + G43_sqnorm + ) + + 1 / 2 * (D1_sqnorm + D2_sqnorm + D3_sqnorm + D4_sqnorm) + ) + + self.SUSY_coeff_1 * tf.norm(phi1) ** 2 + + self.SUSY_coeff_2 * tf.norm(phi2) ** 2 + + self.SUSY_coeff_3 * tf.norm(phi3) ** 2 + ) + + def uniquify( + self, solutions_set, dval_list, dist_threshold=1e-4, use_symmetry=False + ): + unique_solutions_dval_set = [] + for j, arg_dict in enumerate(solutions_set): + flipper = 1 + # check if solution exists in unique_list or not + for i, (sol_dict, _) in enumerate(unique_solutions_dval_set): + # print("sol_dict:", sol_dict) + # print("arg_list:", arg_list) + + a_dist = self.distance( + self.B_invariant(**arg_dict), self.B_invariant(**sol_dict) + ) + b_dist = self.distance( + self.B_invariant(**arg_dict), + self.B_invariant(**self.neg_vars(sol_dict)), + ) + c_dist = self.distance( + self.B_invariant(**arg_dict), + self.B_invariant(**self.conj_vars(sol_dict)), + ) + d_dist = self.distance( + self.B_invariant(**arg_dict), + self.B_invariant(**self.neg_vars(self.conj_vars(sol_dict))), + ) + + if use_symmetry: + if ( + a_dist < dist_threshold + or b_dist < dist_threshold + or c_dist < dist_threshold + or d_dist < dist_threshold + ): + arg_loss, sol_loss = self.brane_potential( + *self.full_vars_U1(**arg_dict) + ), self.brane_potential(*self.full_vars_U1(**sol_dict)) + # print("distance:", min(a_dist, b_dist, c_dist, d_dist)) + if tf.math.real(arg_loss) < tf.math.real(sol_loss): + unique_solutions_dval_set[i] = (arg_dict, dval_list[j]) + flipper *= 0 + break + break + else: + if a_dist < dist_threshold: + arg_loss, sol_loss = self.brane_potential( + *self.full_vars_U1(**arg_dict) + ), self.brane_potential(*self.full_vars_U1(**sol_dict)) + # print("distance:", min(a_dist, b_dist, c_dist, d_dist)) + if tf.math.real(arg_loss) < tf.math.real(sol_loss): + unique_solutions_dval_set[i] = (arg_dict, dval_list[j]) + flipper *= 0 + break + break + + if flipper: + unique_solutions_dval_set.append((arg_dict, dval_list[j])) + print("no of unique solutions:", len(unique_solutions_dval_set)) + + return unique_solutions_dval_set + + def B_invariant( + self, + Z12, + Z13, + Z14, + Z21, + Z23, + Z24, + Z31, + Z32, + Z34, + Z41, + Z42, + Z43, + phi1, + phi2, + phi3, + phi12, + phi23, + phi31, + ): + """Receives combined variables to produce a list of""" + B = [] + """Append phi12, phi12, phi23, phi31 first""" + + B.append(phi12[0, 0]) + B.append(phi23[0, 0]) + B.append(phi31[0, 0]) + + """Adding Tr(phi1), Tr(phi2), and Tr(phi3)""" + B.append(tf.linalg.trace(phi1)) + B.append(tf.linalg.trace(phi2)) + B.append(tf.linalg.trace(phi3)) + + """The next 3 are u7, u8, and u9 respectively""" + # B.append(triple_mul(Z12, Z24, Z41)[0, 0]) + # B.append(triple_mul(Z13, Z34, Z41)[0, 0]) + # B.append(triple_mul(Z23, Z34, Z42)[0, 0]) + # for n in range(1, N4 + 1): + # B.append(tf.linalg.matmul(tf.linalg.matmul(Z14, (mat_power(phi1, n))), + # tf.linalg.matmul(mat_power(phi2, N4 - n), Z41))[0, 0]) + # B.append(tf.linalg.matmul(tf.linalg.matmul(Z24, (mat_power(phi2, n))), + # tf.linalg.matmul(mat_power(phi3, N4 - n), Z42))[0, 0]) + # B.append(tf.linalg.matmul(tf.linalg.matmul(Z34, (mat_power(phi3, n))), + # tf.linalg.matmul(mat_power(phi1, N4 - n), Z43))[0, 0]) + return B + + def write_markers(self, full_arg_dict, data_dict): + sol_array = self.full_vars_U1(**full_arg_dict) + loss = self.brane_potential(*sol_array) + data_dict["loss"].append(tf.math.real(loss).numpy()) + B = self.B_invariant(*sol_array) + for i in range(len(B)): + data_dict[str(i) + "-real"].append(tf.math.real(B[i]).numpy()) + data_dict[str(i) + "-imag"].append(tf.math.imag(B[i]).numpy()) + + def write_hyperparameters_U1(self, data_dict): + data_dict["C12_real"].append(tf.math.real(self.C[0, 1]).numpy()) + data_dict["C12_imag"].append(tf.math.imag(self.C[0, 1]).numpy()) + data_dict["C13_real"].append(tf.math.real(self.C[0, 2]).numpy()) + data_dict["C13_imag"].append(tf.math.imag(self.C[0, 2]).numpy()) + data_dict["C14_real"].append(tf.math.real(self.C[0, 3]).numpy()) + data_dict["C14_imag"].append(tf.math.imag(self.C[0, 3]).numpy()) + data_dict["C23_real"].append(tf.math.real(self.C[1, 2]).numpy()) + data_dict["C23_imag"].append(tf.math.imag(self.C[1, 2]).numpy()) + data_dict["C24_real"].append(tf.math.real(self.C[1, 3]).numpy()) + data_dict["C24_imag"].append(tf.math.imag(self.C[1, 3]).numpy()) + data_dict["C34_real"].append(tf.math.real(self.C[2, 3]).numpy()) + data_dict["C34_imag"].append(tf.math.imag(self.C[2, 3]).numpy()) + + for i in range(len(self.FI)): + val = self.FI[i] + # print(val) + data_dict["FI-" + str(i)].append(tf.math.real(val).numpy()) + + def write_markers_U1(self, full_arg_dict, data_dict, dval): + sol_array = self.full_vars_U1(**full_arg_dict) + loss = self.brane_potential(*sol_array) + data_dict["loss"].append(tf.math.real(loss).numpy()) + data_dict["dval"].append(tf.math.real(dval).numpy()) + B = self.B_invariant(*sol_array) + for i in range(len(B)): + data_dict[str(i) + "-real"].append(tf.math.real(B[i]).numpy()) + data_dict[str(i) + "-imag"].append(tf.math.imag(B[i]).numpy()) + + self.write_hyperparameters_U1(data_dict) + + def write_full_solution_U1(self, full_arg_dict, data_dict, dval): + sol_array = self.full_vars_U1(**full_arg_dict) + loss = self.brane_potential(*sol_array) + data_dict["loss"].append(tf.math.real(loss).numpy()) + data_dict["dval"].append(tf.math.real(dval).numpy()) + for i in range(len(sol_array)): + val = sol_array[i] + # print(val) + data_dict[str(i) + "-real"].append(tf.math.real(val[0, 0]).numpy()) + data_dict[str(i) + "-imag"].append(tf.math.imag(val[0, 0]).numpy()) + + self.write_hyperparameters_U1(data_dict) + + +class Solver: + """Class for initializing and running the optimizer.""" + + def __init__(self, N4): + self.N4 = N4 + self.functions = Functions(self.N4) + + def run_optimization( + self, var_dict, arg_dict, optimizer_class, n_steps, **optimizer_kwargs + ): + optimizer = optimizer_class(**optimizer_kwargs) + all_args = {**var_dict, **arg_dict} + + def loss(): + return self.functions.brane_potential( + *self.functions.full_vars_U1(**all_args) + ) + + # Initialize a list to store gradients + gradients = [tf.Variable(tf.zeros_like(var)) for var in var_dict.values()] + + @tf.function + def opt_cycle0(opt, loss, var_list, n_steps): + for _ in tf.range(n_steps): + with tf.GradientTape() as tape: + current_loss = loss() + grads = tape.gradient(current_loss, var_list) + opt.apply_gradients(zip(grads, var_list)) + + # Accumulate gradients + for i in range(len(var_list)): + gradients[i].assign_add(grads[i]) + + opt_cycle0(optimizer, loss, list(var_dict.values()), n_steps) + + # Calculate the final loss value + loss_value = loss() + + # Calculate the L2 norm of accumulated gradients + gradient_norm = tf.sqrt( + sum([tf.reduce_sum(tf.square(tf.abs(g))) for g in gradients]) + ) + + return tf.math.real(loss_value), var_dict, arg_dict, gradient_norm + + def init_run(self, n_steps, learning_rate=1e-3): + vars = Variables(self.N4) + minmaxval = 5 + var_dict = { + "Z12": vars.Z_U1gauged( + 1, 2, minval=-minmaxval, maxval=minmaxval, name="Z12" + ), + "Z23": vars.Z_U1gauged( + 2, 3, minval=-minmaxval, maxval=minmaxval, name="Z23" + ), + "Z34": vars.Z_U1gauged( + 3, 4, minval=-minmaxval, maxval=minmaxval, name="Z34" + ), + "Z13": vars.Z(1, 3, minval=-minmaxval, maxval=minmaxval, name="Z13"), + "Z14": vars.Z(1, 4, minval=-minmaxval, maxval=minmaxval, name="Z14"), + "Z21": vars.Z(2, 1, minval=-minmaxval, maxval=minmaxval, name="Z21"), + "Z24": vars.Z(2, 4, minval=-minmaxval, maxval=minmaxval, name="Z24"), + "Z31": vars.Z(3, 1, minval=-minmaxval, maxval=minmaxval, name="Z31"), + "Z32": vars.Z(3, 2, minval=-minmaxval, maxval=minmaxval, name="Z32"), + "Z41": vars.Z(4, 1, minval=-minmaxval, maxval=minmaxval, name="Z41"), + "Z42": vars.Z(4, 2, minval=-minmaxval, maxval=minmaxval, name="Z42"), + "Z43": vars.Z(4, 3, minval=-minmaxval, maxval=minmaxval, name="Z43"), + "phi1": vars.phi(self.N4, minval=-minmaxval, maxval=minmaxval, name="phi1"), + "phi2": vars.phi(self.N4, minval=-minmaxval, maxval=minmaxval, name="phi2"), + "phi3": vars.phi(self.N4, minval=-minmaxval, maxval=minmaxval, name="phi3"), + "phi12": vars.phi(1, minval=-minmaxval, maxval=minmaxval, name="phi12"), + "phi23": vars.phi(1, minval=-minmaxval, maxval=minmaxval, name="phi23"), + "phi31": vars.phi(1, minval=-minmaxval, maxval=minmaxval, name="phi31"), + } + arg_dict = {} + + opt = tf.keras.optimizers.SGD + + for _ in tqdm(range(self.functions.num_cycles)): + loss_val, var_dict, arg_dict, gradient_norm = self.run_optimization( + var_dict, arg_dict, opt, n_steps, learning_rate=learning_rate + ) + + print( + "loss:", + loss_val.numpy(), + "dval:", + gradient_norm.numpy(), + "phi31:", + var_dict["phi31"][0][0].numpy(), + "lr:", + learning_rate, + ) + + if gradient_norm < 1: + learning_rate *= 0.5 + opt = tf.keras.optimizers.Adam + else: + opt = tf.keras.optimizers.SGD + + if loss_val < 1e-9 or gradient_norm < 1e-6 or tf.math.is_nan(loss_val): + break + + return loss_val, {**var_dict, **arg_dict}, gradient_norm + + +def main(N4, num_runs, n_steps, learning_rate): + def solve_task(args): + N4, n_steps, learning_rate = args + return Solver(N4).init_run(n_steps, learning_rate) + + pool = mp.Pool() # Create a processing pool + + # Create a list of argument tuples for the solver function + args_list = [(N4, n_steps, learning_rate)] * num_runs + + # Use `map` to parallelize the task and get results + results = pool.map(solve_task, args_list) + + # Close the pool to release resources + pool.close() + pool.join() + + solutions_list, dval_list = [], [] + for i in results: + print("dval:", i[-1], "loss:", i[0]) + if ( + i[-1] < 1e-6 or i[0] < 1e-6 or (i[-1] < 1 and i[0] < 1) + ): # Keeping low derivative or low loss solutions + solutions_list.append(i[1]) + dval_list.append(i[-1]) + + functions = Functions(N4) + markers = collections.defaultdict(list) + solutions_to_print = collections.defaultdict(list) + if len(solutions_list) > 0: + unique_solutions_dval_set = functions.uniquify(solutions_list, dval_list) + unique_solutions_list = [item[0] for item in unique_solutions_dval_set] + + s1, s2, s3 = ( + functions.SUSY_coeff_1, + functions.SUSY_coeff_2, + functions.SUSY_coeff_3, + ) + t = time.time() + fname = f"U1markers_N4={N4}_s1={s1}_s2={s2}_s3={s3}_t={t}" + fname_sol = f"U1fullsols_N4={N4}_s1={s1}_s2={s2}_s3={s3}_t={t}" + + # with open(fname_sol + ".data", "wb") as filehandle: + # pickle.dump(unique_solutions_list, filehandle) + + for sol_dict, dval in unique_solutions_dval_set: + functions.write_markers_U1(sol_dict, markers, dval) + functions.write_full_solution_U1(sol_dict, solutions_to_print, dval) + + # functions.write_markers_U1(functions.neg_vars(sol_dict), markers, dval) + + # functions.write_markers_U1(functions.conj_vars(sol_dict), markers, dval) + + # functions.write_markers_U1( + # functions.conj_vars(functions.neg_vars(sol_dict)), markers, dval + # ) + + pd.DataFrame.from_dict(data=markers, orient="columns").to_csv( + fname + ".csv", header=True, index=False + ) + pd.DataFrame.from_dict(data=solutions_to_print, orient="columns").to_csv( + fname_sol + ".csv", header=True, index=False + ) + else: + unique_solutions_list = [] + + print("number of runs:", num_runs, "results_length:", len(unique_solutions_list)) + + +if __name__ == "__main__": + start_time = time.time() # at the beginning of the program + + N4 = 1 + num_runs = 64 + n_steps = 1e5 + learning_rate = 1e-3 + + main(N4, num_runs, n_steps, learning_rate) + end_time = time.time() # at the end of the program + print(f"for N4 = {N4}..... time taken = {round(end_time - start_time, 2)} seconds") + exit()