├── models ├── __init__.py ├── __pycache__ │ ├── FF_1H.cpython-39.pyc │ └── __init__.cpython-39.pyc ├── FF_1H.py └── set_transformer.py ├── datasets ├── __init__.py ├── __pycache__ │ ├── AntDataset.cpython-39.pyc │ └── __init__.cpython-39.pyc └── AntDataset.py ├── utils ├── __pycache__ │ ├── util.cpython-39.pyc │ └── __init__.cpython-39.pyc ├── __init__.py ├── visualizer.py ├── Standard_Norm.py └── util.py ├── antenna_array_conversion ├── __pycache__ │ ├── op_true_func.cpython-39.pyc │ ├── torch_function.cpython-39.pyc │ └── true_function.cpython-39.pyc ├── true_function.py ├── torch_function.py └── verification.ipynb ├── LICENSE ├── README.md ├── main.py └── .gitignore /models/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /datasets/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /utils/__pycache__/util.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david5010/Optimization-of-Antenna-Arrays/HEAD/utils/__pycache__/util.cpython-39.pyc -------------------------------------------------------------------------------- /models/__pycache__/FF_1H.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david5010/Optimization-of-Antenna-Arrays/HEAD/models/__pycache__/FF_1H.cpython-39.pyc -------------------------------------------------------------------------------- /utils/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david5010/Optimization-of-Antenna-Arrays/HEAD/utils/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /models/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david5010/Optimization-of-Antenna-Arrays/HEAD/models/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /datasets/__pycache__/AntDataset.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david5010/Optimization-of-Antenna-Arrays/HEAD/datasets/__pycache__/AntDataset.cpython-39.pyc -------------------------------------------------------------------------------- /datasets/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david5010/Optimization-of-Antenna-Arrays/HEAD/datasets/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /antenna_array_conversion/__pycache__/op_true_func.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david5010/Optimization-of-Antenna-Arrays/HEAD/antenna_array_conversion/__pycache__/op_true_func.cpython-39.pyc -------------------------------------------------------------------------------- /antenna_array_conversion/__pycache__/torch_function.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david5010/Optimization-of-Antenna-Arrays/HEAD/antenna_array_conversion/__pycache__/torch_function.cpython-39.pyc -------------------------------------------------------------------------------- /antenna_array_conversion/__pycache__/true_function.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david5010/Optimization-of-Antenna-Arrays/HEAD/antenna_array_conversion/__pycache__/true_function.cpython-39.pyc -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 david5010 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- 1 | import json 2 | import math 3 | import numpy as np 4 | import os 5 | from pathlib import Path 6 | import torch 7 | from torch.optim import lr_scheduler 8 | 9 | def transfer_to_device(x, device): 10 | """ 11 | Transfers PyTorch tensors or lists of tensors to GPU. 12 | This function is recursive to deal with lists of lists. 13 | """ 14 | if isinstance(x, list): 15 | for i in range(len(x)): 16 | x[i] = transfer_to_device(x[i], device) 17 | else: 18 | x= x.to(device) 19 | return x 20 | 21 | def parse_configuration(config_file): 22 | """ 23 | Load config file if a string was passed and returns the input if a dictionary was passed 24 | """ 25 | if isinstance(config_file, str): 26 | with open(config_file) as json_file: 27 | return json.load(json_file) 28 | else: 29 | return config_file 30 | 31 | def get_scheduler(optimizer, configuration, last_epoch = -1): 32 | """ 33 | Return a learning rate scheduler 34 | """ 35 | if configuration['lr_policy'] == 'step': 36 | scheduler = lr_scheduler.StepLR(optimizer, step_size=configuration['lr_decay_iters'], gamma = 0.3, last_epoch=last_epoch) 37 | else: 38 | return NotImplementedError('Learning rate policy [{0}] is not implemented'.format(configuration['lr_policy'])) 39 | return scheduler 40 | 41 | def stack_all(list, dim = 0): 42 | """ 43 | Stack all iterables of torch tensors in a list 44 | i.e. [[(tensor), (tensor)], [(tensor, tensor)]] 45 | """ 46 | return [torch.stacks(s,dim) for s in list] 47 | -------------------------------------------------------------------------------- /models/FF_1H.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import numpy as np 4 | import pandas as pd 5 | 6 | class SimpleNN(nn.Module): 7 | # in the future, implement one with configuration files for ease 8 | def __init__(self, input_size, output_size, hidden_size , act_func, dropout = 0) -> None: 9 | super(SimpleNN, self).__init__() 10 | self.name = 'FF' 11 | self.regressor = nn.Sequential( 12 | nn.Linear(input_size, hidden_size), 13 | act_func(), 14 | nn.Dropout(p=dropout), 15 | nn.Linear(hidden_size, output_size) 16 | ) 17 | 18 | def forward(self, x): 19 | return self.regressor(x) 20 | 21 | class NN2(nn.Module): 22 | # Two-layers 23 | def __init__(self, input_size, output_size, hid1_size, hid2_size, act_func,dropout = 0) -> None: 24 | super(NN2, self).__init__() 25 | self.name = 'FF' 26 | self.regressor = nn.Sequential( 27 | nn.Linear(input_size, hid1_size), 28 | act_func(), 29 | nn.Dropout(p=dropout), 30 | nn.Linear(hid1_size, hid2_size), 31 | act_func(), 32 | nn.Dropout(p=dropout), 33 | nn.Linear(hid2_size, output_size) 34 | ) 35 | 36 | def forward(self, x): 37 | return self.regressor(x) 38 | 39 | class LinearRegression(nn.Module): 40 | def __init__(self, input_size): 41 | super(LinearRegression, self).__init__() 42 | self.linear = nn.Linear(input_size,1) 43 | 44 | def forward(self, x): 45 | out = self.linear(x) 46 | return out -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Optimizing Antenna Array Configurations using Deep Learning 2 | **authors**: David Lin Yi Lu, Lior Maman, Amir Boag, Pierre Baldi 3 | ## Abstract 4 | 5 | We introduce a deep learning-based optimization method that enhances the design of sparse phased array antennas by reducing grating lobes. Our approach begins with a generation of sparse antenna array configurations, efficiently addressing the non-convex challenges and high degrees of freedom in array design. We then employ neural networks, trained on 70,000 and tested on 30,000 configurations, to approximate a non-convex cost function that measures the ratio between the energy of the main lobe and the side lobe level. The approximation is differentiable and allows minimizing the cost function by gradient descent with respect to the antenna coordinates, yielding a new optimized configuration. A custom penalty mechanism is also implemented, integrating various physical and design constraints into our optimization framework. The effectiveness of our method is tested on the ten configurations with the lowest costs, showing a reduction in cost by 46\% to 89\%, with an average of 74\% on the best optimization framework. 6 | 7 | ## Overview 8 | 9 | - **/models**: You can find the various neural networks we used (FNN, Set Transformer). These models need to be trained and saved. 10 | 11 | - **/utils/util.py**: This file contains various helper functions and our optimization technique using the built-in Adam Optimizer 12 | 13 | - **/antenna_array_conversion**: This directory includes the code for evaluating the true cost function (ratio between the energy of the main lobe and side lobe level) using torch. 14 | 15 | For additional questions, feel free to open issues on this repository or to contact davidlu5010@gmail.com -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from models.FF_1H import * 2 | from datasets.AntDataset import AntDataset, AntDataset2D 3 | from torch.utils.data import DataLoader 4 | import torch.nn as nn 5 | import matplotlib.pyplot as plt 6 | import torch.optim as optim 7 | from sklearn.model_selection import KFold 8 | 9 | def train(model, optimizer, criterion, train_loader, device): 10 | model.train() 11 | total_loss = 0.0 12 | for i, (inputs, targets) in enumerate(train_loader): 13 | inputs, targets = inputs.to(device), targets.to(device) 14 | optimizer.zero_grad() 15 | outputs = model(inputs) 16 | loss = criterion(outputs, targets.unsqueeze(1)) 17 | loss.backward() 18 | optimizer.step() 19 | total_loss += loss.item() 20 | 21 | return total_loss/len(train_loader) 22 | 23 | def evaluate(model, criterion, test_loader, device): 24 | model.eval() 25 | total_loss = 0.0 26 | 27 | with torch.no_grad(): 28 | for inputs, targets in test_loader: 29 | inputs, targets = inputs.to(device), targets.to(device) 30 | 31 | outputs = model(inputs) 32 | loss = criterion(outputs, targets.unsqueeze(1)) 33 | total_loss += loss.item() 34 | 35 | return total_loss/len(test_loader) 36 | 37 | def train_and_evaluate(model, optimizer, criterion, train_loader, test_loader, num_epochs, device): 38 | train_losses = [] 39 | test_losses = [] 40 | for epoch in range(num_epochs): 41 | train_loss = train(model, optimizer, criterion, train_loader, device) 42 | test_loss = evaluate(model, criterion, test_loader, device) 43 | train_losses.append(train_loss) 44 | test_losses.append(test_loss) 45 | print(f"Epoch {epoch+1} - Train Loss: {train_loss:.4f}, Test Loss: {test_loss:.4f}") 46 | return train_losses, test_losses 47 | 48 | def weight_reset(m): 49 | if isinstance(m, nn.Conv2d) or isinstance(m, nn.Linear): 50 | m.reset_parameters() 51 | 52 | def cross_validate(fold, model, optimizer, criterion, epochs, data, batch_size, device): 53 | 54 | kf = KFold(n_splits = fold, shuffle = True) 55 | training_avg_loss = [] 56 | testing_avg_loss = [] 57 | for k, (train, test) in enumerate(kf.split(np.arange(len(data)))): 58 | print(f'{k}-Fold') 59 | train_loader = DataLoader(AntDataset(data[train]), batch_size=batch_size) 60 | test_loader = DataLoader(AntDataset(data[test]), batch_size=batch_size) 61 | new_fold = model 62 | new_fold.to(device) 63 | train_loss, test_loss = train_and_evaluate(new_fold, optimizer, criterion, train_loader, test_loader, epochs, device) 64 | training_avg_loss.append(train_loss) 65 | testing_avg_loss.append(test_loss) 66 | model.apply(weight_reset) 67 | new_fold.apply(weight_reset) 68 | 69 | return training_avg_loss, testing_avg_loss 70 | 71 | -------------------------------------------------------------------------------- /datasets/AntDataset.py: -------------------------------------------------------------------------------- 1 | from torch.utils.data import Dataset 2 | import pandas as pd 3 | import numpy as np 4 | import torch 5 | import os 6 | 7 | class AntDataset(Dataset): 8 | def __init__(self, data, shuffle = False, seed = 123): 9 | if not isinstance(data,str): 10 | self.data = data.astype(np.float32) 11 | elif os.path.splitext(data)[-1] == '.csv': 12 | self.data = pd.read_csv(data, header = None).values.astype(np.float32) 13 | elif os.path.splitext(data)[-1] == '.npz': 14 | self.data = np.load(data)['data'].astype(np.float32) 15 | else: 16 | self.data = np.load(data)['data'].astype(np.float32) 17 | 18 | self.shuffle = shuffle 19 | 20 | if self.shuffle: 21 | # Shuffle the antennas around 22 | num_ant = (self.data.shape[1]-1)//2 23 | index_order = np.random.RandomState(seed=seed).permutation(num_ant) 24 | X, Y, label = self.data[:, :num_ant], self.data[:, num_ant:-1], self.data[:,-1].reshape(-1,1) 25 | self.data = np.hstack((X[:, index_order], Y[:, index_order], label[:, -1].reshape(-1, 1))) 26 | 27 | 28 | 29 | def __len__(self): 30 | return len(self.data) 31 | 32 | def __getitem__(self, index): 33 | features = self.data[index, :-1] 34 | label = self.data[index, -1] 35 | return torch.from_numpy(features), torch.from_numpy(np.array(label)) 36 | 37 | class AntDataset2D(Dataset): 38 | def __init__(self, data, shuffle = False, seed = 123): 39 | if os.path.splitext(data)[-1] == '.csv': 40 | self.data = pd.read_csv(data, header= None).values.astype(np.float32) 41 | elif os.path.splitext(data)[-1] == '.npz': 42 | self.data = np.load(data)['data'].astype(np.float32) 43 | 44 | self.shuffle = shuffle 45 | if self.shuffle: 46 | # Shuffle the antennas around 47 | num_ant = (self.data.shape[1]-1)//2 48 | index_order = np.random.RandomState(seed=seed).permutation(num_ant) 49 | X, Y, label = self.data[:, :num_ant], self.data[:, num_ant:-1], self.data[:,-1].reshape(-1,1) 50 | self.data = np.hstack((X[:, index_order], Y[:, index_order], label[:, -1].reshape(-1, 1))) 51 | def __len__(self): 52 | return len(self.data) 53 | 54 | def __getitem__(self, idx): 55 | # Get the array pattern and target from the CSV data 56 | array_pattern = self.data[idx, :-1] 57 | target = self.data[idx, -1] 58 | 59 | # Reshape the array pattern and convert to tensor 60 | sequence_length = 1024 61 | input_dim = 2 62 | array_pattern = array_pattern.reshape(input_dim, sequence_length).T 63 | array_pattern = torch.from_numpy(array_pattern) 64 | 65 | # Convert the target to tensor 66 | target = torch.from_numpy(np.array(target)) 67 | 68 | return array_pattern, target -------------------------------------------------------------------------------- /utils/visualizer.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import sys 3 | from subprocess import Popen, PIPE # Creates a subprocess, mainly used for GUI application to visualize 4 | import utils # My own module 5 | import visdom 6 | 7 | 8 | class Visualizer(): 9 | """ 10 | This class includes several functions that can display images and pring logging information 11 | """ 12 | 13 | def __init__(self, configuration): 14 | """ 15 | Initialize the Visualizer class. 16 | 17 | Input params: 18 | Configuration -- stores all the configuration 19 | """ 20 | self.configuration = configuration 21 | self.display_id = 0 22 | self.name = configuration['name'] 23 | 24 | self.ncols = 0 25 | self.vis = visdom.Visdom() 26 | if not self.vis.check_connection(): 27 | self.create_visdom_connections() 28 | 29 | def reset(self): 30 | pass 31 | 32 | def create_visdom_connections(self): 33 | """If the program could not connect to Visdom server, this function will start a new server at the default port. 34 | """ 35 | cmd = sys.executable + ' -m visdom.server' 36 | print('\n\nCould not connect to Visdom server. \n Trying to start a server....') 37 | print('Command: %s' % cmd) 38 | Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) 39 | 40 | def plot_current_losses(self, epoch, counter_ratio, losses): 41 | """ 42 | Display the current losses on visdom display: dictionary of error labels and values 43 | 44 | Input params: 45 | epoch: Current epoch 46 | counter_ratio: Progress (percentage) in the current epoch, bewteen 0 to 1 47 | losses: Training losses stored in the format of (name, float) pairs 48 | """ 49 | if not hasattr(self, 'loss_plot_data'): 50 | self.loss_plot_data = {'X': [], 'Y':[], 'legend': list(losses.keys())} 51 | self.loss_plot_data['X'].append(epoch + counter_ratio) 52 | self.loss_plot_data['Y'].append([losses[k] for k in self.loss_plot_data['legend']]) 53 | x = np.squeeze(np.stack([np.array(self.loss_plot_data['X'])] * len(self.loss_plot_data['legend']), 1), axis=1) 54 | y = np.squeeze(np.array(self.loss_plot_data['Y']), axis=1) 55 | try: 56 | self.vis.line( 57 | X = x, 58 | Y = y, 59 | opts = { 60 | 'title': self.name + ' loss over time', 61 | 'legend': 'epoch', 62 | 'xlabel': 'epoch', 63 | 'ylabel': 'loss' 64 | }, 65 | win = self.display_id 66 | ) 67 | except ConnectionError: 68 | self.create_visdom_connections() 69 | 70 | def plot_current_validation_metrics(self, epoch, metrics): 71 | if not hasattr(self, 'val_plot_data'): 72 | self.val_plot_data = {'X': [], 'Y': [], 'legend': list(metrics.keys())} 73 | self.val_plot_data['X'].append(epoch) 74 | self.val_plot_data['Y'].append([metrics[k] for k in self.val_plot_data['legend']]) 75 | x = np.squeeze(np.stack([np.array(self.val_plot_data['X'])] * len(self.val_plot_data['legend']), 1), axis=1) 76 | y = np.squeeze(np.array(self.val_plot_data['Y']), axis=1) 77 | try: 78 | self.vis.line( 79 | X=x, 80 | Y=y, 81 | opts={ 82 | 'title': self.name + ' over time', 83 | 'legend': self.val_plot_data['legend'], 84 | 'xlabel': 'epoch', 85 | 'ylabel': 'metric'}, 86 | win=self.display_id+1) 87 | except ConnectionError: 88 | self.create_visdom_connections() -------------------------------------------------------------------------------- /models/set_transformer.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | import math 5 | 6 | class MAB(nn.Module): 7 | """ 8 | Code from Set Transformer by Lee et al. 9 | Multi-Attention Block 10 | """ 11 | def __init__(self, dim_Q, dim_K, dim_V, num_heads, ln = False) -> None: 12 | super(MAB, self).__init__() 13 | self.dim_V = dim_V 14 | self.num_heads = num_heads 15 | self.fc_q = nn.Linear(dim_Q, dim_V) 16 | self.fc_k = nn.Linear(dim_K, dim_V) 17 | self.fc_v = nn.Linear(dim_K, dim_V) 18 | if ln: 19 | self.ln0 = nn.LayerNorm(dim_V) 20 | self.ln1 = nn.LayerNorm(dim_V) 21 | self.fc_o = nn.Linear(dim_V, dim_V) 22 | 23 | def forward(self, Q, K): 24 | Q = self.fc_q(Q) 25 | K, V = self.fc_k(K), self.fc_v(K) 26 | 27 | dim_split = self.dim_V//self.num_heads 28 | Q_ = torch.cat(Q.split(dim_split, 2), 0) 29 | K_ = torch.cat(K.split(dim_split, 2), 0) 30 | V_ = torch.cat(V.split(dim_split, 2), 0) 31 | 32 | A = torch.softmax(Q_.bmm(K_.transpose(1,2))/math.sqrt(self.dim_V), 2) 33 | O = torch.cat((Q_ + A.bmm(V_)).split(Q.size(0), 0), 2) 34 | O = O if getattr(self, 'ln0', None) is None else self.ln0(O) 35 | O = O + F.relu(self.fc_o(O)) 36 | O = O if getattr(self, 'ln1', None) is None else self.ln1(O) 37 | return O 38 | 39 | class SAB(nn.Module): 40 | """ 41 | Code from Set Transformer by Lee et al. 42 | Set-Attention Block 43 | """ 44 | def __init__(self, dim_in, dim_out, num_heads, ln=False): 45 | super(SAB, self).__init__() 46 | self.mab = MAB(dim_in, dim_in, dim_out, num_heads, ln=ln) 47 | 48 | def forward(self, X): 49 | return self.mab(X, X) 50 | 51 | class ISAB(nn.Module): 52 | """ 53 | Code from Set Transformer by Lee et al. 54 | Permutation Equivariant (Induced) Set Attention Blocks 55 | """ 56 | def __init__(self, dim_in, dim_out, num_heads, num_inds, ln = False): 57 | super(ISAB, self).__init__() 58 | self.I = nn.Parameter(torch.Tensor(1, num_inds, dim_out)) 59 | nn.init.xavier_uniform_(self.I) 60 | self.mab0 = MAB(dim_out, dim_in, dim_out, num_heads, ln=ln) 61 | self.mab1 = MAB(dim_in, dim_out, dim_out, num_heads, ln=ln) 62 | 63 | def forward(self, X): 64 | H = self.mab0(self.I.repeat(X.size(0), 1, 1), X) 65 | return self.mab1(X, H) 66 | 67 | class PMA(nn.Module): 68 | """ 69 | Code from Set Transformer by Lee et al. 70 | Pooling by Multihead Attention 71 | """ 72 | def __init__(self, dim, num_heads, num_seeds, ln=False): 73 | super(PMA, self).__init__() 74 | self.S = nn.Parameter(torch.Tensor(1, num_seeds, dim)) 75 | nn.init.xavier_uniform_(self.S) 76 | self.mab = MAB(dim, dim, dim, num_heads, ln=ln) 77 | 78 | def forward(self, X): 79 | return self.mab(self.S.repeat(X.size(0), 1, 1), X) 80 | 81 | class SetTransformer(nn.Module): 82 | """ 83 | Code from Set Transformer by Lee et al. 84 | """ 85 | def __init__(self, dim_input, num_outputs, dim_output, 86 | num_inds=32, dim_hidden=128, num_heads=4, ln=False): 87 | super(SetTransformer, self).__init__() 88 | self.enc = nn.Sequential( 89 | ISAB(dim_input, dim_hidden, num_heads, num_inds, ln=ln), 90 | ISAB(dim_hidden, dim_hidden, num_heads, num_inds, ln=ln)) 91 | self.dec = nn.Sequential( 92 | PMA(dim_hidden, num_heads, num_outputs, ln=ln), 93 | SAB(dim_hidden, dim_hidden, num_heads, ln=ln), 94 | SAB(dim_hidden, dim_hidden, num_heads, ln=ln), 95 | nn.Linear(dim_hidden, dim_output)) 96 | 97 | def forward(self, X): 98 | return self.dec(self.enc(X)).squeeze(-1) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | -------------------------------------------------------------------------------- /utils/Standard_Norm.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import math 3 | import numpy as np 4 | 5 | class ScaleCost: 6 | """ 7 | Scale Only the cost 8 | """ 9 | def __init__(self, mean = None, std = None) -> None: 10 | self.mean = mean 11 | self.scale = std 12 | 13 | def fit(self, data): 14 | self.mean = np.mean(data) 15 | self.scale = np.std(data) 16 | 17 | def transform(self, data): 18 | if self.mean is None or self.scale is None: 19 | raise ValueError("Scaler has not been fitted") 20 | return (data - self.mean) / self.scale 21 | 22 | def inverse_transform(self, scaled_data): 23 | if self.mean is None or self.scale is None: 24 | raise ValueError("Scaler has not been fitted") 25 | return (scaled_data * self.scale) + self.mean 26 | 27 | def save_scaler(self, path): 28 | """ 29 | Saves the fitted parameters 30 | """ 31 | scaler_attributes = { 32 | 'mean': self.mean, 33 | 'scale': self.scale 34 | } 35 | torch.save(scaler_attributes, path) 36 | 37 | def load_scaler(self, path): 38 | scaler_attributes = torch.load(path) 39 | self.mean = scaler_attributes['mean'] 40 | self.scale = scaler_attributes['scale'] 41 | 42 | class ScaleYZCost: 43 | """ 44 | Scale All 45 | """ 46 | def __init__(self, y_mean = None, z_mean = None, 47 | y_scale = None, z_scale = None, 48 | cost_mean = None, cost_scale = None) -> None: 49 | self.y_mean = y_mean 50 | self.z_mean = z_mean 51 | self.y_scale = y_scale 52 | self.z_scale = z_scale 53 | self.cost_mean = cost_mean 54 | self.cost_scale = cost_scale 55 | 56 | def fit(self, y_data, z_data, cost_data): 57 | """ 58 | Don't count the 0 59 | """ 60 | y_mask = (y_data != 0) 61 | non_padded_y = y_data[y_mask] 62 | self.y_mean = non_padded_y.mean() 63 | self.y_scale = non_padded_y.std() 64 | 65 | z_mask = (z_data != 0) 66 | non_padded_z = z_data[z_mask] 67 | self.z_mean = non_padded_z.mean() 68 | self.z_scale = non_padded_z.std() 69 | 70 | self.cost_mean = np.mean(cost_data) 71 | self.cost_scale = np.std(cost_data) 72 | 73 | def transform(self, y_data, z_data, cost_data): 74 | scaled_y = np.zeros_like(y_data) 75 | scaled_z = np.zeros_like(z_data) 76 | scaled_cost = (cost_data - self.cost_mean) / self.cost_scale 77 | 78 | y_mask = (y_data != 0) 79 | z_mask = (z_data != 0) 80 | 81 | scaled_y[y_mask] = (y_data[y_mask] - self.y_mean) / self.y_scale 82 | scaled_z[z_mask] = (z_data[z_mask] - self.z_mean) / self.z_scale 83 | 84 | scaled_cost = scaled_cost.reshape(-1, 1) 85 | combined = np.concatenate((scaled_y, scaled_z, scaled_cost), axis=1) 86 | 87 | return combined 88 | 89 | 90 | def inverse_transform(self, scaled_y, scaled_z, scaled_cost): 91 | y = (scaled_y * self.y_scale) + self.y_mean 92 | z = (scaled_z * self.z_scale) + self.z_mean 93 | cost = (scaled_cost * self.cost_scale) + self.cost_mean 94 | 95 | return np.concatenate((y,z,cost), axis = 1) 96 | 97 | def get_stats(self): 98 | stats = { 99 | 'y_mean': self.y_mean, 100 | 'z_mean': self.z_mean, 101 | 'cost_mean': self.cost_mean, 102 | 'y_scale': self.y_scale, 103 | 'z_scale': self.z_scale, 104 | 'cost_scale': self.cost_scale 105 | } 106 | return stats 107 | 108 | def save_scaler(self, path): 109 | """ 110 | Saves the fitted parameters 111 | """ 112 | scaler_attributes = { 113 | 'mean': self.mean, 114 | 'scale': self.scale 115 | } 116 | torch.save(scaler_attributes, path) 117 | 118 | def load_scaler(self, path): 119 | scaler_attributes = torch.load(path) 120 | self.mean = scaler_attributes['mean'] 121 | self.scale = scaler_attributes['scale'] 122 | 123 | -------------------------------------------------------------------------------- /utils/util.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import matplotlib.pyplot as plt 3 | import numpy as np 4 | import os 5 | def save_figure(figure, title, directory='figures'): 6 | # Ensure the directory exists 7 | if not os.path.exists(directory): 8 | os.makedirs(directory) 9 | 10 | figure_path = os.path.join(directory, f"{title}.png") 11 | figure.savefig(figure_path) # Save with reduced white space 12 | plt.close(figure) # Close the figure to free up memory 13 | 14 | def show_arrays(inp, title='Antenna Array Pattern', directory='figures'): 15 | fig, ax = plt.subplots() # Use subplots for better control over the figure 16 | data = inp.cpu().detach().numpy() 17 | reshaped_data = np.reshape(data, (2, 1024)) 18 | x, y = reshaped_data 19 | 20 | nonzero_ind = np.nonzero((x != 0) | (y != 0)) 21 | x, y = x[nonzero_ind], y[nonzero_ind] 22 | 23 | ax.scatter(x, y, s=0.75) 24 | ax.set_xlabel('Y') 25 | ax.set_ylabel('Z') 26 | ax.set_title(title) 27 | 28 | save_figure(fig, title, directory) # Pass the directory to save_figure 29 | 30 | 31 | def calculate_min_distance(ants, unit = 1): 32 | """ 33 | Checks the smallest Euclidean distance, if it violates then return True 34 | """ 35 | reshaped_tensor = torch.reshape(ants, (2, 1024)) 36 | 37 | # Transpose the reshaped tensor 38 | reshaped_tensor = torch.transpose(reshaped_tensor, 0, 1) 39 | nonzero_rows = torch.any(reshaped_tensor != 0, dim=1) 40 | filtered_tensor = reshaped_tensor[nonzero_rows] 41 | distances = torch.cdist(filtered_tensor, filtered_tensor) 42 | distances.fill_diagonal_(float('inf')) 43 | closest_neighbor_distances, _ = torch.min(distances, dim=1) 44 | smallest = torch.min(closest_neighbor_distances) 45 | return smallest.item() 46 | 47 | 48 | def reset_padding(tensor, padding_mask): 49 | # tensor: the tensor to be adjusted 50 | # padding_mask: a Boolean tensor of the same shape as tensor, where True indicates padding that should be reset to zero 51 | with torch.no_grad(): 52 | tensor[padding_mask] = 0 53 | 54 | def optimize_ants(model, ants_input, optimizer_class, iters, lr=0.001): 55 | ants = ants_input.clone().detach().requires_grad_(True) # Ensure ants is a clone and tracks gradients 56 | padding_mask = (ants == 0) 57 | opt = optimizer_class([ants], lr=lr) # Initialize the optimizer correctly 58 | 59 | for it in range(iters): 60 | last = ants.clone() 61 | opt.zero_grad() 62 | model_output = model(ants) 63 | model_output.backward() # Make sure the loss function is called correctly 64 | opt.step() # Call step on the correct optimizer instance 65 | reset_padding(ants, padding_mask) # Apply padding reset correctly 66 | if calculate_min_distance(ants) < 0.5: 67 | print(f'Early Stop at {it}') 68 | return last 69 | return ants # Return the optimized tensor 70 | 71 | def optimize_ants_pen(model, ants_input, optimizer_class, iters, lr=0.001, loss_fn = lambda x,y: x): 72 | ants = ants_input.clone().detach().requires_grad_(True) # Ensure ants is a clone and tracks gradients 73 | padding_mask = (ants == 0) 74 | opt = optimizer_class([ants], lr=lr) # Initialize the optimizer correctly 75 | 76 | for it in range(iters): 77 | last = ants.clone() 78 | opt.zero_grad() 79 | model_output = model(ants) 80 | loss = loss_fn(model_output, ants) # default only returns the model_output 81 | loss.backward() 82 | # model_output.backward() # Make sure the loss function is called correctly 83 | opt.step() # Call step on the correct optimizer instance 84 | reset_padding(ants, padding_mask) # Apply padding reset correctly 85 | if calculate_min_distance(ants) < 0.5: 86 | print(f'Early Stop at {it}') 87 | return last 88 | return ants # Return the optimized tensor 89 | 90 | def yz_split(tensor): 91 | """ 92 | Splits a 1D tensor into two parts, yant and zant, each taking half of the tensor. 93 | Then removes all trailing zeros from both parts. 94 | 95 | Args: 96 | - tensor (torch.Tensor): A 1D tensor with 2048 elements. 97 | 98 | Returns: 99 | - Tuple[torch.Tensor, torch.Tensor]: The two parts of the tensor with trailing zeros removed. 100 | """ 101 | # Split the tensor into yant and zant 102 | yant, zant = tensor.split(1024) 103 | 104 | # Function to remove trailing zeros from a tensor 105 | def remove_trailing_zeros(tensor): 106 | # Find the indices of non-zero elements and get the maximum index 107 | non_zero_indices = tensor.nonzero(as_tuple=True)[0] 108 | if len(non_zero_indices) == 0: # If tensor is all zeros 109 | return tensor[:0] # Return an empty tensor 110 | else: 111 | max_index = non_zero_indices.max() 112 | return tensor[:max_index + 1] 113 | 114 | # Remove trailing zeros from yant and zant 115 | yant = remove_trailing_zeros(yant) 116 | zant = remove_trailing_zeros(zant) 117 | 118 | return yant, zant -------------------------------------------------------------------------------- /antenna_array_conversion/true_function.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | # from numba import jit 4 | 5 | # @jit(nopython = True) 6 | def analytic_uy_uz_mapping_quarter(AZ0_max,AZ0_min,EL0_max,EL0_min): 7 | n = int(1e5) 8 | uz_SEC1_pos=np.ones(n)*(1+np.sin(np.deg2rad(np.abs(EL0_min)))) 9 | AZ0=np.linspace(0,np.abs(AZ0_min),n) 10 | uy_SEC1_pos=np.cos(np.deg2rad(EL0_min))*np.sin(np.deg2rad(AZ0)) 11 | 12 | uz_SEC2_pos=np.linspace(2*np.sin(np.deg2rad(np.abs(EL0_min))),1+np.sin(np.deg2rad(np.abs(EL0_min))),n) 13 | uy_SEC2_pos=np.sqrt(1-(uz_SEC2_pos-np.sin(np.deg2rad(np.abs(EL0_min))))**2)-np.cos(np.deg2rad(EL0_min))*np.sin(np.deg2rad(AZ0_min)) 14 | 15 | EL0_temp=np.linspace(0,np.abs(EL0_min),n) 16 | uz_SEC3_pos=np.linspace(0,2*np.sin(np.deg2rad(np.abs(EL0_min))),2*n) 17 | EL0_vec=np.zeros(uz_SEC3_pos.shape) 18 | EL0_vec[::2]=EL0_temp 19 | EL0_vec[1::2]=EL0_temp 20 | uy_SEC3_pos=np.sqrt(1-(uz_SEC3_pos-np.sin(np.deg2rad(EL0_vec)))**2)-np.cos(np.deg2rad(EL0_vec))*np.sin(np.deg2rad(AZ0_min)) 21 | 22 | uy_vec=np.concatenate((uy_SEC1_pos,uy_SEC2_pos,uy_SEC3_pos), axis=None) 23 | uz_vec=np.concatenate((uz_SEC1_pos,uz_SEC2_pos,uz_SEC3_pos), axis=None) 24 | 25 | n = 500 26 | duz = np.max(uz_vec)/n 27 | duy = np.max(uy_vec)/n 28 | uz_norm = [] 29 | uy_norm = [] 30 | 31 | for i in range(1, n+1): 32 | mask = (uy_vec>=(i-1)*duy) & (uy_vec<= i * duy) 33 | if mask.any(): 34 | uzsample_max = np.max(uz_vec[mask]) 35 | else: 36 | uzsample_max = 0 # or another suitable default value 37 | a=np.arange(0, uzsample_max+duz, duz) 38 | uz_norm.extend(a) 39 | uy_norm.extend(np.ones(len(a))*duy*(i-1)) 40 | 41 | return np.array(uy_norm), np.array(uz_norm) 42 | 43 | def InitializeParamsArray(ParamsArray = None): 44 | if ParamsArray is None: 45 | ParamsArray = {} 46 | 47 | # This function provides initialization of the array parameters. 48 | # lambda is the wavelength (default 0.1) 49 | # FlagTapeing provides the option for Hamming Window (default false) 50 | # The scanning domain is defined by EL0_max, EL0_min,AZ0_max,AZ0_min 51 | # (default EL0_max = 10, EL0_min = -10, AZ0_max = 20, AZ0_min = -20) 52 | # if the scaning domain is changed it should by symmetric (|EL0_max =|EL0_min|,|AZ0_max = AZ0_min|) 53 | # uy and uz are the differnce vector of the the observation with the scanning 54 | # PlotAF provides the option for displaying the radiation pattern in uy-uz domain (default false) 55 | # PlotYZ provides the option for displaying the array elements geometry (default false) 56 | 57 | ParamsArray["lambda"] = 0.1 # the wavelength 58 | ParamsArray["k"] = 2 * np.pi / ParamsArray["lambda"] # The wave number 59 | ParamsArray["FlagTapering"] = False # Optional Hamming tapering flag for reducing SLL (the defult is false) 60 | ParamsArray["EL0_max"] = 10 # the maximum scan in elvation 61 | ParamsArray["EL0_min"] = -10 # the minimum scan in elvation 62 | ParamsArray["AZ0_max"] = 20 # the maximum scan in azimuth 63 | ParamsArray["AZ0_min"] = -20 # the minimum scan in azimuth 64 | uy_norm, uz_norm = analytic_uy_uz_mapping_quarter(ParamsArray["AZ0_max"], ParamsArray["AZ0_min"], ParamsArray["EL0_max"], ParamsArray["EL0_min"]) 65 | ParamsArray["uy"] = np.array(uy_norm) * ParamsArray["k"] 66 | ParamsArray["uz"] = np.array(uz_norm) * ParamsArray["k"] 67 | ParamsArray["PlotAF"] = False # Flag option that provides the option for displaying the radiation pattern in uy-uz domain (default false) 68 | ParamsArray["PlotYZ"] = False # Flag option that provides the option for displaying the array elements geometry (default false) 69 | 70 | return ParamsArray 71 | 72 | # @jit(nopython = True) 73 | def CostFun(CostFunParams): 74 | lambda_ = CostFunParams['lambda'] 75 | uy = CostFunParams['uy'] 76 | uz = CostFunParams['uz'] 77 | Yant = CostFunParams['Yant'] 78 | Zant = CostFunParams['Zant'] 79 | In = CostFunParams['In'] 80 | p = CostFunParams['p'] 81 | k = 2 * np.pi / lambda_ 82 | 83 | AF = np.zeros(uy.shape, dtype=np.complex128) 84 | 85 | if In == 0: 86 | for i in range(len(Yant)): 87 | AF += np.exp(1j * (Yant[i] * uy + Zant[i] * uz)) 88 | else: 89 | for i in range(len(Yant)): 90 | AF += In[i] * np.exp(1j * (Yant[i] * uy + Zant[i] * uz)) 91 | 92 | uy3dB = k * (lambda_ / max(Yant)) / 2 * 1.3 93 | uz3dB = k * (lambda_ / max(Zant)) / 2 * 1.3 94 | 95 | idxuy = uy <= uy3dB 96 | idxuz = uz <= uz3dB 97 | idx = idxuy & idxuz 98 | 99 | ML = AF[idx] 100 | RSLL = AF[~idx] 101 | GratingLobes = 20 * np.log10(np.abs(np.max(ML) / np.max(RSLL))) 102 | 103 | AF_p = np.power(np.abs(AF) ** 2, p) 104 | nominator = np.sum(AF_p[idx]) 105 | dominator = np.sum(AF_p[~idx]) 106 | 107 | cost = - nominator / dominator 108 | 109 | return cost, GratingLobes 110 | 111 | # @jit(nopython = True) 112 | def AF_fun(xant_new, yant_new, ux_t, uy_t, I_np, AFlimit): 113 | AF = np.zeros(ux_t.shape, dtype=np.complex128) 114 | 115 | if I_np == 0: 116 | for i in range(len(xant_new)): 117 | AF += np.exp(1j * (xant_new[i] * ux_t + yant_new[i] * uy_t)) 118 | AFdB = 20 * np.log10(np.abs(AF) / np.max(np.abs(AF))) 119 | AFdB[AFdB - AFlimit < 0] = AFlimit 120 | else: 121 | for i in range(len(xant_new)): 122 | AF += I_np[i] * np.exp(1j * (xant_new[i] * ux_t + yant_new[i] * uy_t)) 123 | AFdB = 20 * np.log10(np.abs(AF) / np.nanmax(np.abs(AF))) 124 | AFdB[AFdB - AFlimit < 0] = AFlimit 125 | 126 | return AFdB 127 | 128 | 129 | def CostFunArray(Yant, Zant, ParamsArray): 130 | Yant = Yant * ParamsArray['lambda'] 131 | Zant = Zant * ParamsArray['lambda'] 132 | 133 | if ParamsArray['FlagTapering']: 134 | Iny = 0.54 + 0.46 * np.cos(np.pi / np.max(Yant) * Yant) 135 | Inz = 0.54 + 0.46 * np.cos(np.pi / np.max(Zant) * Zant) 136 | In = Inz * Iny 137 | else: 138 | In = 0 139 | 140 | if ParamsArray['PlotYZ']: 141 | plt.figure() 142 | plt.scatter(Yant / ParamsArray['lambda'], Zant / ParamsArray['lambda']) 143 | plt.xlabel('Yant/lambda') 144 | plt.ylabel('Zant/lambda') 145 | plt.grid(True) 146 | plt.show() 147 | 148 | if ParamsArray['PlotAF']: 149 | AFdB = AF_fun(Yant, Zant, ParamsArray['uy'], ParamsArray['uz'], 0, -25) 150 | pointsize = 80 151 | plt.figure(figsize=(10,7)) 152 | plt.scatter(ParamsArray['uy'].flatten() / ParamsArray['k'], ParamsArray['uz'].flatten() / ParamsArray['k'], pointsize, AFdB.flatten(), cmap='hot', alpha=0.6) 153 | plt.grid(True) 154 | plt.xlabel('u_y/k') 155 | plt.ylabel('u_z/k') 156 | plt.colorbar(label='AFdB') 157 | plt.title('Heatmap-like scatter plot') 158 | plt.show() 159 | 160 | 161 | CostFunParams = { 162 | 'In': In, 163 | 'Yant': Yant, 164 | 'Zant': Zant, 165 | 'lambda': ParamsArray['lambda'], 166 | 'uy': ParamsArray['uy'], 167 | 'uz': ParamsArray['uz'], 168 | 'p': 4 169 | } 170 | 171 | cost, _ = CostFun(CostFunParams) 172 | 173 | return cost 174 | -------------------------------------------------------------------------------- /antenna_array_conversion/torch_function.py: -------------------------------------------------------------------------------- 1 | # Torch version - Using Tensors to improve the function 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | import torch 5 | import math 6 | 7 | def analytic_uy_uz_mapping_quarter(AZ0_max, AZ0_min, EL0_max, EL0_min, device): 8 | n = int(1e5) 9 | 10 | uz_SEC1_pos = torch.ones(n, device=device) * (1 + torch.sin(torch.deg2rad(torch.abs(EL0_min)))).to(device) 11 | AZ0 = torch.linspace(0, torch.abs(AZ0_min), n, device=device) 12 | uy_SEC1_pos = torch.cos(torch.deg2rad(EL0_min)).to(device) * torch.sin(torch.deg2rad(AZ0)).to(device) 13 | 14 | uz_SEC2_pos = torch.linspace(2 * torch.sin(torch.deg2rad(torch.abs(EL0_min))), 1 + torch.sin(torch.deg2rad(torch.abs(EL0_min))), n, device=device) 15 | uy_SEC2_pos = torch.sqrt(1 - (uz_SEC2_pos - torch.sin(torch.deg2rad(torch.abs(EL0_min))))**2) - torch.cos(torch.deg2rad(EL0_min)) * torch.sin(torch.deg2rad(AZ0_min)) 16 | 17 | EL0_temp = torch.linspace(0, torch.abs(EL0_min), n, device=device) 18 | uz_SEC3_pos = torch.linspace(0, 2 * torch.sin(torch.deg2rad(torch.abs(EL0_min))), 2 * n, device=device) 19 | EL0_vec = torch.zeros(uz_SEC3_pos.shape, device=device) 20 | EL0_vec[::2] = EL0_temp 21 | EL0_vec[1::2] = EL0_temp 22 | uy_SEC3_pos = torch.sqrt(1 - (uz_SEC3_pos - torch.sin(torch.deg2rad(EL0_vec)))**2) - torch.cos(torch.deg2rad(EL0_vec)) * torch.sin(torch.deg2rad(AZ0_min)) 23 | 24 | uy_vec = torch.cat((uy_SEC1_pos, uy_SEC2_pos, uy_SEC3_pos)) 25 | uz_vec = torch.cat((uz_SEC1_pos, uz_SEC2_pos, uz_SEC3_pos)) 26 | 27 | n = 500 28 | duz = torch.max(uz_vec) / n 29 | duy = torch.max(uy_vec) / n 30 | uz_norm = [] 31 | uy_norm = [] 32 | 33 | for i in range(1, n+1): 34 | mask = (uy_vec >= (i-1) * duy) & (uy_vec <= i * duy) 35 | if mask.any(): 36 | uzsample_max = torch.max(uz_vec[mask]) 37 | else: 38 | uzsample_max = 0 39 | a = torch.arange(0, uzsample_max + duz, duz, device=device) 40 | uz_norm.extend(a) 41 | uy_norm.extend(torch.ones(len(a), device=device) * duy * (i-1)) 42 | 43 | return torch.tensor(uy_norm, device=device), torch.tensor(uz_norm, device=device) 44 | 45 | def InitializeParamsArray(ParamsArray=None, device=None): 46 | if ParamsArray is None: 47 | ParamsArray = {} 48 | 49 | if device is None: 50 | device = 'cuda' if torch.cuda.is_available() else 'cpu' 51 | 52 | # Initialization of the array parameters. 53 | ParamsArray["lambda"] = torch.tensor(0.1, device=device) # the wavelength 54 | ParamsArray["k"] = 2 * torch.tensor(torch.pi, device=device) / ParamsArray["lambda"] # The wave number 55 | ParamsArray["FlagTapering"] = False # Optional Hamming tapering flag for reducing SLL 56 | ParamsArray["EL0_max"] = torch.tensor(10, device=device) # the maximum scan in elevation 57 | ParamsArray["EL0_min"] = torch.tensor(-10, device=device) # the minimum scan in elevation 58 | ParamsArray["AZ0_max"] = torch.tensor(20, device=device) # the maximum scan in azimuth 59 | ParamsArray["AZ0_min"] = torch.tensor(-20, device=device) # the minimum scan in azimuth 60 | 61 | uy_norm, uz_norm = analytic_uy_uz_mapping_quarter(ParamsArray["AZ0_max"], ParamsArray["AZ0_min"], ParamsArray["EL0_max"], ParamsArray["EL0_min"], device) 62 | 63 | ParamsArray["uy"] = uy_norm * ParamsArray["k"] 64 | ParamsArray["uz"] = uz_norm * ParamsArray["k"] 65 | ParamsArray["PlotAF"] = False # Flag for displaying the radiation pattern in uy-uz domain 66 | ParamsArray["PlotYZ"] = False # Flag for displaying the array elements geometry 67 | 68 | return ParamsArray 69 | 70 | def CostFun(CostFunParams, device): 71 | lambda_ = CostFunParams['lambda'] 72 | uy = CostFunParams['uy'] 73 | uz = CostFunParams['uz'] 74 | Yant = CostFunParams['Yant'] 75 | Zant = CostFunParams['Zant'] 76 | In = CostFunParams['In'] 77 | p = CostFunParams['p'] 78 | k = 2 * torch.tensor(torch.pi, device=device) / lambda_ 79 | 80 | if In == 0: 81 | AF = torch.sum(torch.exp(1j * (Yant[:, None] * uy + Zant[:, None] * uz)), dim=0) 82 | else: 83 | AF = torch.sum(In[:, None] * torch.exp(1j * (Yant[:, None] * uy + Zant[:, None] * uz)), dim=0) 84 | 85 | uy3dB = k * (lambda_ / torch.max(Yant)) / 2 * 1.3 86 | uz3dB = k * (lambda_ / torch.max(Zant)) / 2 * 1.3 87 | 88 | idxuy = uy <= uy3dB 89 | idxuz = uz <= uz3dB 90 | idx = idxuy & idxuz 91 | 92 | ML = AF[idx] 93 | RSLL = AF[~idx] 94 | GratingLobes = 20 * torch.log10(torch.abs(torch.max(torch.abs(ML)) / torch.max(torch.abs(RSLL)))) 95 | 96 | AF_p = torch.pow(torch.abs(AF) ** 2, p) 97 | nominator = torch.sum(AF_p[idx]) 98 | dominator = torch.sum(AF_p[~idx]) 99 | 100 | cost = - nominator / dominator 101 | 102 | return cost.item(), GratingLobes.item() 103 | 104 | def AF_fun(xant_new, yant_new, ux_t, uy_t, I_np, AFlimit, device): 105 | # Convert inputs to tensors if they are not already 106 | xant_new = torch.tensor(xant_new, device=device) if not isinstance(xant_new, torch.Tensor) else xant_new 107 | yant_new = torch.tensor(yant_new, device=device) if not isinstance(yant_new, torch.Tensor) else yant_new 108 | ux_t = torch.tensor(ux_t, device=device) if not isinstance(ux_t, torch.Tensor) else ux_t 109 | uy_t = torch.tensor(uy_t, device=device) if not isinstance(uy_t, torch.Tensor) else uy_t 110 | I_np = torch.tensor(I_np, device=device) if not isinstance(I_np, torch.Tensor) else I_np 111 | 112 | if torch.equal(I_np, torch.tensor(0, device=device)): 113 | AF = torch.sum(torch.exp(1j * (xant_new[:, None] * ux_t + yant_new[:, None] * uy_t)), dim=0) 114 | AFdB = 20 * torch.log10(torch.abs(AF) / torch.max(torch.abs(AF))) 115 | AFdB[AFdB - AFlimit < 0] = AFlimit 116 | else: 117 | AF = torch.sum(I_np[:, None] * torch.exp(1j * (xant_new[:, None] * ux_t + yant_new[:, None] * uy_t)), dim=0) 118 | AFdB = 20 * torch.log10(torch.abs(AF) / torch.nanmax(torch.abs(AF))) 119 | AFdB[AFdB - AFlimit < 0] = AFlimit 120 | 121 | return AFdB 122 | 123 | def CostFunArray(Yant, Zant, ParamsArray, device): 124 | Yant = Yant.to(device) * ParamsArray['lambda'] 125 | Zant = Zant.to(device) * ParamsArray['lambda'] 126 | 127 | if ParamsArray['FlagTapering']: 128 | Iny = 0.54 + 0.46 * torch.cos(torch.pi / torch.max(Yant) * Yant) 129 | Inz = 0.54 + 0.46 * torch.cos(torch.pi / torch.max(Zant) * Zant) 130 | In = Inz * Iny 131 | else: 132 | In = torch.tensor(0, device=device) 133 | 134 | if ParamsArray['PlotYZ']: 135 | plt.figure() 136 | plt.scatter((Yant / ParamsArray['lambda']).cpu().numpy(), (Zant / ParamsArray['lambda']).cpu().numpy()) 137 | plt.xlabel('Yant/lambda') 138 | plt.ylabel('Zant/lambda') 139 | plt.grid(True) 140 | plt.show() 141 | 142 | if ParamsArray['PlotAF']: 143 | AFdB = AF_fun(Yant, Zant, ParamsArray['uy'], ParamsArray['uz'], 0, -25, device) 144 | pointsize = 80 145 | plt.figure(figsize=(10,7)) 146 | plt.scatter((ParamsArray['uy'] / ParamsArray['k']).cpu().numpy(), (ParamsArray['uz'] / ParamsArray['k']).cpu().numpy(), pointsize, AFdB.cpu().numpy(), cmap='hot', alpha=0.6) 147 | plt.grid(True) 148 | plt.xlabel('u_y/k') 149 | plt.ylabel('u_z/k') 150 | plt.colorbar(label='AFdB') 151 | plt.title('Heatmap-like scatter plot') 152 | plt.show() 153 | 154 | CostFunParams = { 155 | 'In': In, 156 | 'Yant': Yant, 157 | 'Zant': Zant, 158 | 'lambda': ParamsArray['lambda'], 159 | 'uy': ParamsArray['uy'], 160 | 'uz': ParamsArray['uz'], 161 | 'p': torch.tensor(4, device=device) 162 | } 163 | 164 | cost, _ = CostFun(CostFunParams, device) 165 | 166 | return cost -------------------------------------------------------------------------------- /antenna_array_conversion/verification.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stdout", 10 | "output_type": "stream", 11 | "text": [ 12 | "/home/david/Desktop/antenna_arrays\n" 13 | ] 14 | } 15 | ], 16 | "source": [ 17 | "%cd /home/david/Desktop/antenna_arrays" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 2, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "import pandas as pd\n", 27 | "import numpy as np\n", 28 | "import matplotlib.pyplot as plt\n", 29 | "import torch\n", 30 | "from true_function import *\n", 31 | "import op_true_func as op\n", 32 | "import torch_function as t_op" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": 3, 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "Yant0, Zant0 = pd.read_csv('check_shapes/shape 0/Given Yant0.csv', header= None).values.flatten(), pd.read_csv('check_shapes/shape 0/Given Zant0.csv', header = None).values.flatten()" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": 4, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "device = 'cuda' if torch.cuda.is_available() else 'cpu'" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 5, 56 | "metadata": {}, 57 | "outputs": [], 58 | "source": [ 59 | "ParamsArray = t_op.InitializeParamsArray(device = device)" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 6, 65 | "metadata": {}, 66 | "outputs": [], 67 | "source": [ 68 | "# Put Yant0 Zant0 to gpu\n", 69 | "yant0, zant0 = torch.tensor(Yant0).to(device), torch.tensor(Zant0).to(device)" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": 7, 75 | "metadata": {}, 76 | "outputs": [], 77 | "source": [ 78 | "\n", 79 | "cost = t_op.CostFunArray(yant0, zant0, ParamsArray, device)" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": 8, 85 | "metadata": {}, 86 | "outputs": [], 87 | "source": [ 88 | "cost.backward()" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 9, 94 | "metadata": {}, 95 | "outputs": [ 96 | { 97 | "name": "stdout", 98 | "output_type": "stream", 99 | "text": [ 100 | "None None\n" 101 | ] 102 | } 103 | ], 104 | "source": [ 105 | "print(yant0.grad, zant0.grad)" 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "execution_count": 9, 111 | "metadata": {}, 112 | "outputs": [], 113 | "source": [ 114 | "ParamsArray = InitializeParamsArray()" 115 | ] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": 10, 120 | "metadata": {}, 121 | "outputs": [ 122 | { 123 | "data": { 124 | "text/plain": [ 125 | "-12131.25785906924" 126 | ] 127 | }, 128 | "execution_count": 10, 129 | "metadata": {}, 130 | "output_type": "execute_result" 131 | } 132 | ], 133 | "source": [ 134 | "CostFunArray(Yant0, Zant0, ParamsArray)" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": 3, 140 | "metadata": {}, 141 | "outputs": [], 142 | "source": [ 143 | "import op_true_func as op" 144 | ] 145 | }, 146 | { 147 | "cell_type": "code", 148 | "execution_count": 5, 149 | "metadata": {}, 150 | "outputs": [], 151 | "source": [ 152 | "from torch.utils.data import DataLoader\n", 153 | "from datasets.AntDataset import *" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": 7, 159 | "metadata": {}, 160 | "outputs": [], 161 | "source": [ 162 | "train_loader = DataLoader(AntDataset('data/large/YZ_Large_70.npz'))" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": 8, 168 | "metadata": {}, 169 | "outputs": [], 170 | "source": [ 171 | "def reformat_ant_format(ant):\n", 172 | " \"\"\"\n", 173 | " Reformats the 2048 to 2 distinct arrays, trimming the 0\n", 174 | " \"\"\"\n", 175 | " Yant, Zant = ant[:1024], ant[1024:]\n", 176 | " trim_yant, trim_zant = np.trim_zeros(Yant, 'b'), np.trim_zeros(Zant, 'b')\n", 177 | " return trim_yant, trim_zant" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": 10, 183 | "metadata": {}, 184 | "outputs": [ 185 | { 186 | "data": { 187 | "text/plain": [ 188 | "[tensor([[-30.9829, -30.3919, -29.8009, ..., 0.0000, 0.0000, 0.0000]]),\n", 189 | " tensor([-12131.3057])]" 190 | ] 191 | }, 192 | "execution_count": 10, 193 | "metadata": {}, 194 | "output_type": "execute_result" 195 | } 196 | ], 197 | "source": [ 198 | "sample = next(iter(train_loader))\n", 199 | "sample" 200 | ] 201 | }, 202 | { 203 | "cell_type": "code", 204 | "execution_count": 13, 205 | "metadata": {}, 206 | "outputs": [], 207 | "source": [ 208 | "ParamsArray = InitializeParamsArray()" 209 | ] 210 | }, 211 | { 212 | "cell_type": "code", 213 | "execution_count": 26, 214 | "metadata": {}, 215 | "outputs": [ 216 | { 217 | "name": "stdout", 218 | "output_type": "stream", 219 | "text": [ 220 | "-4.368310549902555\n", 221 | "-12131.259246393902\n" 222 | ] 223 | } 224 | ], 225 | "source": [ 226 | "inp, cost = sample\n", 227 | "inp = inp.squeeze(0).numpy()\n", 228 | "trimmed = reformat_ant_format(inp)\n", 229 | "print(CostFunArray(inp[:1024], inp[1024:], ParamsArray))\n", 230 | "print(CostFunArray(trimmed[0], trimmed[1], ParamsArray))" 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": 39, 236 | "metadata": {}, 237 | "outputs": [ 238 | { 239 | "data": { 240 | "text/plain": [ 241 | "-12131.3056640625" 242 | ] 243 | }, 244 | "execution_count": 39, 245 | "metadata": {}, 246 | "output_type": "execute_result" 247 | } 248 | ], 249 | "source": [ 250 | "cost.item()" 251 | ] 252 | }, 253 | { 254 | "cell_type": "code", 255 | "execution_count": 42, 256 | "metadata": {}, 257 | "outputs": [], 258 | "source": [ 259 | "import time\n", 260 | "results = np.zeros(shape = (1000, 5)) # true cost (from the data), true_cost func, op function cost, true cost time, op func time, 1000 examples\n", 261 | "device = 'cuda' if torch.cuda.is_available() else 'cpu'\n", 262 | "ParamsArray = InitializeParamsArray()\n", 263 | "OP_ParamsArray = t_op.InitializeParamsArray(device=device)" 264 | ] 265 | }, 266 | { 267 | "cell_type": "code", 268 | "execution_count": 43, 269 | "metadata": {}, 270 | "outputs": [ 271 | { 272 | "name": "stdout", 273 | "output_type": "stream", 274 | "text": [ 275 | "1 Iteration\n", 276 | "2 Iteration\n", 277 | "3 Iteration\n", 278 | "4 Iteration\n", 279 | "5 Iteration\n", 280 | "6 Iteration\n", 281 | "7 Iteration\n", 282 | "8 Iteration\n", 283 | "9 Iteration\n", 284 | "10 Iteration\n", 285 | "11 Iteration\n", 286 | "12 Iteration\n", 287 | "13 Iteration\n", 288 | "14 Iteration\n", 289 | "15 Iteration\n", 290 | "16 Iteration\n", 291 | "17 Iteration\n", 292 | "18 Iteration\n", 293 | "19 Iteration\n", 294 | "20 Iteration\n", 295 | "21 Iteration\n", 296 | "22 Iteration\n", 297 | "23 Iteration\n", 298 | "24 Iteration\n", 299 | "25 Iteration\n", 300 | "26 Iteration\n", 301 | "27 Iteration\n", 302 | "28 Iteration\n", 303 | "29 Iteration\n", 304 | "30 Iteration\n", 305 | "31 Iteration\n", 306 | "32 Iteration\n", 307 | "33 Iteration\n", 308 | "34 Iteration\n", 309 | "35 Iteration\n", 310 | "36 Iteration\n", 311 | "37 Iteration\n", 312 | "38 Iteration\n", 313 | "39 Iteration\n", 314 | "40 Iteration\n", 315 | "41 Iteration\n", 316 | "42 Iteration\n", 317 | "43 Iteration\n", 318 | "44 Iteration\n", 319 | "45 Iteration\n", 320 | "46 Iteration\n", 321 | "47 Iteration\n", 322 | "48 Iteration\n", 323 | "49 Iteration\n", 324 | "50 Iteration\n", 325 | "51 Iteration\n", 326 | "52 Iteration\n", 327 | "53 Iteration\n", 328 | "54 Iteration\n", 329 | "55 Iteration\n", 330 | "56 Iteration\n", 331 | "57 Iteration\n", 332 | "58 Iteration\n", 333 | "59 Iteration\n", 334 | "60 Iteration\n", 335 | "61 Iteration\n", 336 | "62 Iteration\n", 337 | "63 Iteration\n", 338 | "64 Iteration\n", 339 | "65 Iteration\n", 340 | "66 Iteration\n", 341 | "67 Iteration\n", 342 | "68 Iteration\n", 343 | "69 Iteration\n", 344 | "70 Iteration\n", 345 | "71 Iteration\n", 346 | "72 Iteration\n", 347 | "73 Iteration\n", 348 | "74 Iteration\n", 349 | "75 Iteration\n", 350 | "76 Iteration\n", 351 | "77 Iteration\n", 352 | "78 Iteration\n", 353 | "79 Iteration\n", 354 | "80 Iteration\n", 355 | "81 Iteration\n", 356 | "82 Iteration\n", 357 | "83 Iteration\n", 358 | "84 Iteration\n", 359 | "85 Iteration\n", 360 | "86 Iteration\n", 361 | "87 Iteration\n", 362 | "88 Iteration\n", 363 | "89 Iteration\n", 364 | "90 Iteration\n", 365 | "91 Iteration\n", 366 | "92 Iteration\n", 367 | "93 Iteration\n", 368 | "94 Iteration\n", 369 | "95 Iteration\n", 370 | "96 Iteration\n", 371 | "97 Iteration\n", 372 | "98 Iteration\n", 373 | "99 Iteration\n", 374 | "100 Iteration\n", 375 | "101 Iteration\n", 376 | "102 Iteration\n", 377 | "103 Iteration\n", 378 | "104 Iteration\n", 379 | "105 Iteration\n", 380 | "106 Iteration\n", 381 | "107 Iteration\n", 382 | "108 Iteration\n", 383 | "109 Iteration\n", 384 | "110 Iteration\n", 385 | "111 Iteration\n", 386 | "112 Iteration\n", 387 | "113 Iteration\n", 388 | "114 Iteration\n", 389 | "115 Iteration\n", 390 | "116 Iteration\n", 391 | "117 Iteration\n", 392 | "118 Iteration\n", 393 | "119 Iteration\n", 394 | "120 Iteration\n", 395 | "121 Iteration\n", 396 | "122 Iteration\n", 397 | "123 Iteration\n", 398 | "124 Iteration\n", 399 | "125 Iteration\n", 400 | "126 Iteration\n", 401 | "127 Iteration\n", 402 | "128 Iteration\n", 403 | "129 Iteration\n", 404 | "130 Iteration\n", 405 | "131 Iteration\n", 406 | "132 Iteration\n", 407 | "133 Iteration\n", 408 | "134 Iteration\n", 409 | "135 Iteration\n", 410 | "136 Iteration\n", 411 | "137 Iteration\n", 412 | "138 Iteration\n", 413 | "139 Iteration\n", 414 | "140 Iteration\n", 415 | "141 Iteration\n", 416 | "142 Iteration\n", 417 | "143 Iteration\n", 418 | "144 Iteration\n", 419 | "145 Iteration\n", 420 | "146 Iteration\n", 421 | "147 Iteration\n", 422 | "148 Iteration\n", 423 | "149 Iteration\n", 424 | "150 Iteration\n", 425 | "151 Iteration\n", 426 | "152 Iteration\n", 427 | "153 Iteration\n", 428 | "154 Iteration\n", 429 | "155 Iteration\n", 430 | "156 Iteration\n", 431 | "157 Iteration\n", 432 | "158 Iteration\n", 433 | "159 Iteration\n", 434 | "160 Iteration\n", 435 | "161 Iteration\n", 436 | "162 Iteration\n", 437 | "163 Iteration\n", 438 | "164 Iteration\n", 439 | "165 Iteration\n", 440 | "166 Iteration\n", 441 | "167 Iteration\n", 442 | "168 Iteration\n", 443 | "169 Iteration\n", 444 | "170 Iteration\n", 445 | "171 Iteration\n", 446 | "172 Iteration\n", 447 | "173 Iteration\n", 448 | "174 Iteration\n", 449 | "175 Iteration\n", 450 | "176 Iteration\n", 451 | "177 Iteration\n", 452 | "178 Iteration\n", 453 | "179 Iteration\n", 454 | "180 Iteration\n", 455 | "181 Iteration\n", 456 | "182 Iteration\n", 457 | "183 Iteration\n", 458 | "184 Iteration\n", 459 | "185 Iteration\n", 460 | "186 Iteration\n", 461 | "187 Iteration\n", 462 | "188 Iteration\n", 463 | "189 Iteration\n", 464 | "190 Iteration\n", 465 | "191 Iteration\n", 466 | "192 Iteration\n", 467 | "193 Iteration\n", 468 | "194 Iteration\n", 469 | "195 Iteration\n", 470 | "196 Iteration\n", 471 | "197 Iteration\n", 472 | "198 Iteration\n", 473 | "199 Iteration\n", 474 | "200 Iteration\n", 475 | "201 Iteration\n", 476 | "202 Iteration\n", 477 | "203 Iteration\n", 478 | "204 Iteration\n", 479 | "205 Iteration\n", 480 | "206 Iteration\n", 481 | "207 Iteration\n", 482 | "208 Iteration\n", 483 | "209 Iteration\n", 484 | "210 Iteration\n", 485 | "211 Iteration\n", 486 | "212 Iteration\n", 487 | "213 Iteration\n", 488 | "214 Iteration\n", 489 | "215 Iteration\n", 490 | "216 Iteration\n", 491 | "217 Iteration\n", 492 | "218 Iteration\n", 493 | "219 Iteration\n", 494 | "220 Iteration\n", 495 | "221 Iteration\n", 496 | "222 Iteration\n", 497 | "223 Iteration\n", 498 | "224 Iteration\n", 499 | "225 Iteration\n", 500 | "226 Iteration\n", 501 | "227 Iteration\n", 502 | "228 Iteration\n", 503 | "229 Iteration\n", 504 | "230 Iteration\n", 505 | "231 Iteration\n", 506 | "232 Iteration\n", 507 | "233 Iteration\n", 508 | "234 Iteration\n", 509 | "235 Iteration\n", 510 | "236 Iteration\n", 511 | "237 Iteration\n", 512 | "238 Iteration\n", 513 | "239 Iteration\n", 514 | "240 Iteration\n", 515 | "241 Iteration\n", 516 | "242 Iteration\n", 517 | "243 Iteration\n", 518 | "244 Iteration\n", 519 | "245 Iteration\n", 520 | "246 Iteration\n", 521 | "247 Iteration\n", 522 | "248 Iteration\n", 523 | "249 Iteration\n", 524 | "250 Iteration\n", 525 | "251 Iteration\n", 526 | "252 Iteration\n", 527 | "253 Iteration\n", 528 | "254 Iteration\n", 529 | "255 Iteration\n", 530 | "256 Iteration\n", 531 | "257 Iteration\n", 532 | "258 Iteration\n", 533 | "259 Iteration\n", 534 | "260 Iteration\n", 535 | "261 Iteration\n", 536 | "262 Iteration\n", 537 | "263 Iteration\n", 538 | "264 Iteration\n", 539 | "265 Iteration\n", 540 | "266 Iteration\n", 541 | "267 Iteration\n", 542 | "268 Iteration\n", 543 | "269 Iteration\n", 544 | "270 Iteration\n", 545 | "271 Iteration\n", 546 | "272 Iteration\n", 547 | "273 Iteration\n", 548 | "274 Iteration\n", 549 | "275 Iteration\n", 550 | "276 Iteration\n", 551 | "277 Iteration\n", 552 | "278 Iteration\n", 553 | "279 Iteration\n", 554 | "280 Iteration\n", 555 | "281 Iteration\n", 556 | "282 Iteration\n", 557 | "283 Iteration\n", 558 | "284 Iteration\n", 559 | "285 Iteration\n", 560 | "286 Iteration\n", 561 | "287 Iteration\n", 562 | "288 Iteration\n", 563 | "289 Iteration\n", 564 | "290 Iteration\n", 565 | "291 Iteration\n", 566 | "292 Iteration\n", 567 | "293 Iteration\n", 568 | "294 Iteration\n", 569 | "295 Iteration\n", 570 | "296 Iteration\n", 571 | "297 Iteration\n", 572 | "298 Iteration\n", 573 | "299 Iteration\n", 574 | "300 Iteration\n", 575 | "301 Iteration\n", 576 | "302 Iteration\n", 577 | "303 Iteration\n", 578 | "304 Iteration\n", 579 | "305 Iteration\n", 580 | "306 Iteration\n", 581 | "307 Iteration\n", 582 | "308 Iteration\n", 583 | "309 Iteration\n", 584 | "310 Iteration\n", 585 | "311 Iteration\n", 586 | "312 Iteration\n", 587 | "313 Iteration\n", 588 | "314 Iteration\n", 589 | "315 Iteration\n", 590 | "316 Iteration\n", 591 | "317 Iteration\n", 592 | "318 Iteration\n", 593 | "319 Iteration\n", 594 | "320 Iteration\n", 595 | "321 Iteration\n", 596 | "322 Iteration\n", 597 | "323 Iteration\n", 598 | "324 Iteration\n", 599 | "325 Iteration\n", 600 | "326 Iteration\n", 601 | "327 Iteration\n", 602 | "328 Iteration\n", 603 | "329 Iteration\n", 604 | "330 Iteration\n", 605 | "331 Iteration\n", 606 | "332 Iteration\n", 607 | "333 Iteration\n", 608 | "334 Iteration\n", 609 | "335 Iteration\n", 610 | "336 Iteration\n", 611 | "337 Iteration\n", 612 | "338 Iteration\n", 613 | "339 Iteration\n", 614 | "340 Iteration\n", 615 | "341 Iteration\n", 616 | "342 Iteration\n", 617 | "343 Iteration\n", 618 | "344 Iteration\n", 619 | "345 Iteration\n", 620 | "346 Iteration\n", 621 | "347 Iteration\n", 622 | "348 Iteration\n", 623 | "349 Iteration\n", 624 | "350 Iteration\n", 625 | "351 Iteration\n", 626 | "352 Iteration\n", 627 | "353 Iteration\n", 628 | "354 Iteration\n", 629 | "355 Iteration\n", 630 | "356 Iteration\n", 631 | "357 Iteration\n", 632 | "358 Iteration\n", 633 | "359 Iteration\n", 634 | "360 Iteration\n", 635 | "361 Iteration\n", 636 | "362 Iteration\n", 637 | "363 Iteration\n", 638 | "364 Iteration\n", 639 | "365 Iteration\n", 640 | "366 Iteration\n", 641 | "367 Iteration\n", 642 | "368 Iteration\n", 643 | "369 Iteration\n", 644 | "370 Iteration\n", 645 | "371 Iteration\n", 646 | "372 Iteration\n", 647 | "373 Iteration\n", 648 | "374 Iteration\n", 649 | "375 Iteration\n", 650 | "376 Iteration\n", 651 | "377 Iteration\n", 652 | "378 Iteration\n", 653 | "379 Iteration\n", 654 | "380 Iteration\n", 655 | "381 Iteration\n", 656 | "382 Iteration\n", 657 | "383 Iteration\n", 658 | "384 Iteration\n", 659 | "385 Iteration\n", 660 | "386 Iteration\n", 661 | "387 Iteration\n", 662 | "388 Iteration\n", 663 | "389 Iteration\n", 664 | "390 Iteration\n", 665 | "391 Iteration\n", 666 | "392 Iteration\n", 667 | "393 Iteration\n", 668 | "394 Iteration\n", 669 | "395 Iteration\n", 670 | "396 Iteration\n", 671 | "397 Iteration\n", 672 | "398 Iteration\n", 673 | "399 Iteration\n", 674 | "400 Iteration\n", 675 | "401 Iteration\n", 676 | "402 Iteration\n", 677 | "403 Iteration\n", 678 | "404 Iteration\n", 679 | "405 Iteration\n", 680 | "406 Iteration\n", 681 | "407 Iteration\n", 682 | "408 Iteration\n", 683 | "409 Iteration\n", 684 | "410 Iteration\n", 685 | "411 Iteration\n", 686 | "412 Iteration\n", 687 | "413 Iteration\n", 688 | "414 Iteration\n", 689 | "415 Iteration\n", 690 | "416 Iteration\n", 691 | "417 Iteration\n", 692 | "418 Iteration\n", 693 | "419 Iteration\n", 694 | "420 Iteration\n", 695 | "421 Iteration\n", 696 | "422 Iteration\n", 697 | "423 Iteration\n", 698 | "424 Iteration\n", 699 | "425 Iteration\n", 700 | "426 Iteration\n", 701 | "427 Iteration\n", 702 | "428 Iteration\n", 703 | "429 Iteration\n", 704 | "430 Iteration\n", 705 | "431 Iteration\n", 706 | "432 Iteration\n", 707 | "433 Iteration\n", 708 | "434 Iteration\n", 709 | "435 Iteration\n", 710 | "436 Iteration\n", 711 | "437 Iteration\n", 712 | "438 Iteration\n", 713 | "439 Iteration\n", 714 | "440 Iteration\n", 715 | "441 Iteration\n", 716 | "442 Iteration\n", 717 | "443 Iteration\n", 718 | "444 Iteration\n", 719 | "445 Iteration\n", 720 | "446 Iteration\n", 721 | "447 Iteration\n", 722 | "448 Iteration\n", 723 | "449 Iteration\n", 724 | "450 Iteration\n", 725 | "451 Iteration\n", 726 | "452 Iteration\n", 727 | "453 Iteration\n", 728 | "454 Iteration\n", 729 | "455 Iteration\n", 730 | "456 Iteration\n", 731 | "457 Iteration\n", 732 | "458 Iteration\n", 733 | "459 Iteration\n", 734 | "460 Iteration\n", 735 | "461 Iteration\n", 736 | "462 Iteration\n", 737 | "463 Iteration\n", 738 | "464 Iteration\n", 739 | "465 Iteration\n", 740 | "466 Iteration\n", 741 | "467 Iteration\n", 742 | "468 Iteration\n", 743 | "469 Iteration\n", 744 | "470 Iteration\n", 745 | "471 Iteration\n", 746 | "472 Iteration\n", 747 | "473 Iteration\n", 748 | "474 Iteration\n", 749 | "475 Iteration\n", 750 | "476 Iteration\n", 751 | "477 Iteration\n", 752 | "478 Iteration\n", 753 | "479 Iteration\n", 754 | "480 Iteration\n", 755 | "481 Iteration\n", 756 | "482 Iteration\n", 757 | "483 Iteration\n", 758 | "484 Iteration\n", 759 | "485 Iteration\n", 760 | "486 Iteration\n", 761 | "487 Iteration\n", 762 | "488 Iteration\n", 763 | "489 Iteration\n", 764 | "490 Iteration\n", 765 | "491 Iteration\n", 766 | "492 Iteration\n", 767 | "493 Iteration\n", 768 | "494 Iteration\n", 769 | "495 Iteration\n", 770 | "496 Iteration\n", 771 | "497 Iteration\n", 772 | "498 Iteration\n", 773 | "499 Iteration\n", 774 | "500 Iteration\n", 775 | "501 Iteration\n", 776 | "502 Iteration\n", 777 | "503 Iteration\n", 778 | "504 Iteration\n", 779 | "505 Iteration\n", 780 | "506 Iteration\n", 781 | "507 Iteration\n", 782 | "508 Iteration\n", 783 | "509 Iteration\n", 784 | "510 Iteration\n", 785 | "511 Iteration\n", 786 | "512 Iteration\n", 787 | "513 Iteration\n", 788 | "514 Iteration\n", 789 | "515 Iteration\n", 790 | "516 Iteration\n", 791 | "517 Iteration\n", 792 | "518 Iteration\n", 793 | "519 Iteration\n", 794 | "520 Iteration\n", 795 | "521 Iteration\n", 796 | "522 Iteration\n", 797 | "523 Iteration\n", 798 | "524 Iteration\n", 799 | "525 Iteration\n", 800 | "526 Iteration\n", 801 | "527 Iteration\n", 802 | "528 Iteration\n", 803 | "529 Iteration\n", 804 | "530 Iteration\n", 805 | "531 Iteration\n", 806 | "532 Iteration\n", 807 | "533 Iteration\n", 808 | "534 Iteration\n", 809 | "535 Iteration\n", 810 | "536 Iteration\n", 811 | "537 Iteration\n", 812 | "538 Iteration\n", 813 | "539 Iteration\n", 814 | "540 Iteration\n", 815 | "541 Iteration\n", 816 | "542 Iteration\n", 817 | "543 Iteration\n", 818 | "544 Iteration\n", 819 | "545 Iteration\n", 820 | "546 Iteration\n", 821 | "547 Iteration\n", 822 | "548 Iteration\n", 823 | "549 Iteration\n", 824 | "550 Iteration\n", 825 | "551 Iteration\n", 826 | "552 Iteration\n", 827 | "553 Iteration\n", 828 | "554 Iteration\n", 829 | "555 Iteration\n", 830 | "556 Iteration\n", 831 | "557 Iteration\n", 832 | "558 Iteration\n", 833 | "559 Iteration\n", 834 | "560 Iteration\n", 835 | "561 Iteration\n", 836 | "562 Iteration\n", 837 | "563 Iteration\n", 838 | "564 Iteration\n", 839 | "565 Iteration\n", 840 | "566 Iteration\n", 841 | "567 Iteration\n", 842 | "568 Iteration\n", 843 | "569 Iteration\n", 844 | "570 Iteration\n", 845 | "571 Iteration\n", 846 | "572 Iteration\n", 847 | "573 Iteration\n", 848 | "574 Iteration\n", 849 | "575 Iteration\n", 850 | "576 Iteration\n", 851 | "577 Iteration\n", 852 | "578 Iteration\n", 853 | "579 Iteration\n", 854 | "580 Iteration\n", 855 | "581 Iteration\n", 856 | "582 Iteration\n", 857 | "583 Iteration\n", 858 | "584 Iteration\n", 859 | "585 Iteration\n", 860 | "586 Iteration\n", 861 | "587 Iteration\n", 862 | "588 Iteration\n", 863 | "589 Iteration\n", 864 | "590 Iteration\n", 865 | "591 Iteration\n", 866 | "592 Iteration\n", 867 | "593 Iteration\n", 868 | "594 Iteration\n", 869 | "595 Iteration\n", 870 | "596 Iteration\n", 871 | "597 Iteration\n", 872 | "598 Iteration\n", 873 | "599 Iteration\n", 874 | "600 Iteration\n", 875 | "601 Iteration\n", 876 | "602 Iteration\n", 877 | "603 Iteration\n", 878 | "604 Iteration\n", 879 | "605 Iteration\n", 880 | "606 Iteration\n", 881 | "607 Iteration\n", 882 | "608 Iteration\n", 883 | "609 Iteration\n", 884 | "610 Iteration\n", 885 | "611 Iteration\n", 886 | "612 Iteration\n", 887 | "613 Iteration\n", 888 | "614 Iteration\n", 889 | "615 Iteration\n", 890 | "616 Iteration\n", 891 | "617 Iteration\n", 892 | "618 Iteration\n", 893 | "619 Iteration\n", 894 | "620 Iteration\n", 895 | "621 Iteration\n", 896 | "622 Iteration\n", 897 | "623 Iteration\n", 898 | "624 Iteration\n", 899 | "625 Iteration\n", 900 | "626 Iteration\n", 901 | "627 Iteration\n", 902 | "628 Iteration\n", 903 | "629 Iteration\n", 904 | "630 Iteration\n", 905 | "631 Iteration\n", 906 | "632 Iteration\n", 907 | "633 Iteration\n", 908 | "634 Iteration\n", 909 | "635 Iteration\n", 910 | "636 Iteration\n", 911 | "637 Iteration\n", 912 | "638 Iteration\n", 913 | "639 Iteration\n", 914 | "640 Iteration\n", 915 | "641 Iteration\n", 916 | "642 Iteration\n", 917 | "643 Iteration\n", 918 | "644 Iteration\n", 919 | "645 Iteration\n", 920 | "646 Iteration\n", 921 | "647 Iteration\n", 922 | "648 Iteration\n", 923 | "649 Iteration\n", 924 | "650 Iteration\n", 925 | "651 Iteration\n", 926 | "652 Iteration\n", 927 | "653 Iteration\n", 928 | "654 Iteration\n", 929 | "655 Iteration\n", 930 | "656 Iteration\n", 931 | "657 Iteration\n", 932 | "658 Iteration\n", 933 | "659 Iteration\n", 934 | "660 Iteration\n", 935 | "661 Iteration\n", 936 | "662 Iteration\n", 937 | "663 Iteration\n", 938 | "664 Iteration\n", 939 | "665 Iteration\n", 940 | "666 Iteration\n", 941 | "667 Iteration\n", 942 | "668 Iteration\n", 943 | "669 Iteration\n", 944 | "670 Iteration\n", 945 | "671 Iteration\n", 946 | "672 Iteration\n", 947 | "673 Iteration\n", 948 | "674 Iteration\n", 949 | "675 Iteration\n", 950 | "676 Iteration\n", 951 | "677 Iteration\n", 952 | "678 Iteration\n", 953 | "679 Iteration\n", 954 | "680 Iteration\n", 955 | "681 Iteration\n", 956 | "682 Iteration\n", 957 | "683 Iteration\n", 958 | "684 Iteration\n", 959 | "685 Iteration\n", 960 | "686 Iteration\n", 961 | "687 Iteration\n", 962 | "688 Iteration\n", 963 | "689 Iteration\n", 964 | "690 Iteration\n", 965 | "691 Iteration\n", 966 | "692 Iteration\n", 967 | "693 Iteration\n", 968 | "694 Iteration\n", 969 | "695 Iteration\n", 970 | "696 Iteration\n", 971 | "697 Iteration\n", 972 | "698 Iteration\n", 973 | "699 Iteration\n", 974 | "700 Iteration\n", 975 | "701 Iteration\n", 976 | "702 Iteration\n", 977 | "703 Iteration\n", 978 | "704 Iteration\n", 979 | "705 Iteration\n", 980 | "706 Iteration\n", 981 | "707 Iteration\n", 982 | "708 Iteration\n", 983 | "709 Iteration\n", 984 | "710 Iteration\n", 985 | "711 Iteration\n", 986 | "712 Iteration\n", 987 | "713 Iteration\n", 988 | "714 Iteration\n", 989 | "715 Iteration\n", 990 | "716 Iteration\n", 991 | "717 Iteration\n", 992 | "718 Iteration\n", 993 | "719 Iteration\n", 994 | "720 Iteration\n", 995 | "721 Iteration\n", 996 | "722 Iteration\n", 997 | "723 Iteration\n", 998 | "724 Iteration\n", 999 | "725 Iteration\n", 1000 | "726 Iteration\n", 1001 | "727 Iteration\n", 1002 | "728 Iteration\n", 1003 | "729 Iteration\n", 1004 | "730 Iteration\n", 1005 | "731 Iteration\n", 1006 | "732 Iteration\n", 1007 | "733 Iteration\n", 1008 | "734 Iteration\n", 1009 | "735 Iteration\n", 1010 | "736 Iteration\n", 1011 | "737 Iteration\n", 1012 | "738 Iteration\n", 1013 | "739 Iteration\n", 1014 | "740 Iteration\n", 1015 | "741 Iteration\n", 1016 | "742 Iteration\n", 1017 | "743 Iteration\n", 1018 | "744 Iteration\n", 1019 | "745 Iteration\n", 1020 | "746 Iteration\n", 1021 | "747 Iteration\n", 1022 | "748 Iteration\n", 1023 | "749 Iteration\n", 1024 | "750 Iteration\n", 1025 | "751 Iteration\n", 1026 | "752 Iteration\n", 1027 | "753 Iteration\n", 1028 | "754 Iteration\n", 1029 | "755 Iteration\n", 1030 | "756 Iteration\n", 1031 | "757 Iteration\n", 1032 | "758 Iteration\n", 1033 | "759 Iteration\n", 1034 | "760 Iteration\n", 1035 | "761 Iteration\n", 1036 | "762 Iteration\n", 1037 | "763 Iteration\n", 1038 | "764 Iteration\n", 1039 | "765 Iteration\n", 1040 | "766 Iteration\n", 1041 | "767 Iteration\n", 1042 | "768 Iteration\n", 1043 | "769 Iteration\n", 1044 | "770 Iteration\n", 1045 | "771 Iteration\n", 1046 | "772 Iteration\n", 1047 | "773 Iteration\n", 1048 | "774 Iteration\n", 1049 | "775 Iteration\n", 1050 | "776 Iteration\n", 1051 | "777 Iteration\n", 1052 | "778 Iteration\n", 1053 | "779 Iteration\n", 1054 | "780 Iteration\n", 1055 | "781 Iteration\n", 1056 | "782 Iteration\n", 1057 | "783 Iteration\n", 1058 | "784 Iteration\n", 1059 | "785 Iteration\n", 1060 | "786 Iteration\n", 1061 | "787 Iteration\n", 1062 | "788 Iteration\n", 1063 | "789 Iteration\n", 1064 | "790 Iteration\n", 1065 | "791 Iteration\n", 1066 | "792 Iteration\n", 1067 | "793 Iteration\n", 1068 | "794 Iteration\n", 1069 | "795 Iteration\n", 1070 | "796 Iteration\n", 1071 | "797 Iteration\n", 1072 | "798 Iteration\n", 1073 | "799 Iteration\n", 1074 | "800 Iteration\n", 1075 | "801 Iteration\n", 1076 | "802 Iteration\n", 1077 | "803 Iteration\n", 1078 | "804 Iteration\n", 1079 | "805 Iteration\n", 1080 | "806 Iteration\n", 1081 | "807 Iteration\n", 1082 | "808 Iteration\n", 1083 | "809 Iteration\n", 1084 | "810 Iteration\n", 1085 | "811 Iteration\n", 1086 | "812 Iteration\n", 1087 | "813 Iteration\n", 1088 | "814 Iteration\n", 1089 | "815 Iteration\n", 1090 | "816 Iteration\n", 1091 | "817 Iteration\n", 1092 | "818 Iteration\n", 1093 | "819 Iteration\n", 1094 | "820 Iteration\n", 1095 | "821 Iteration\n", 1096 | "822 Iteration\n", 1097 | "823 Iteration\n", 1098 | "824 Iteration\n", 1099 | "825 Iteration\n", 1100 | "826 Iteration\n", 1101 | "827 Iteration\n", 1102 | "828 Iteration\n", 1103 | "829 Iteration\n", 1104 | "830 Iteration\n", 1105 | "831 Iteration\n", 1106 | "832 Iteration\n", 1107 | "833 Iteration\n", 1108 | "834 Iteration\n", 1109 | "835 Iteration\n", 1110 | "836 Iteration\n", 1111 | "837 Iteration\n", 1112 | "838 Iteration\n", 1113 | "839 Iteration\n", 1114 | "840 Iteration\n", 1115 | "841 Iteration\n", 1116 | "842 Iteration\n", 1117 | "843 Iteration\n", 1118 | "844 Iteration\n", 1119 | "845 Iteration\n", 1120 | "846 Iteration\n", 1121 | "847 Iteration\n", 1122 | "848 Iteration\n", 1123 | "849 Iteration\n", 1124 | "850 Iteration\n", 1125 | "851 Iteration\n", 1126 | "852 Iteration\n", 1127 | "853 Iteration\n", 1128 | "854 Iteration\n", 1129 | "855 Iteration\n", 1130 | "856 Iteration\n", 1131 | "857 Iteration\n", 1132 | "858 Iteration\n", 1133 | "859 Iteration\n", 1134 | "860 Iteration\n", 1135 | "861 Iteration\n", 1136 | "862 Iteration\n", 1137 | "863 Iteration\n", 1138 | "864 Iteration\n", 1139 | "865 Iteration\n", 1140 | "866 Iteration\n", 1141 | "867 Iteration\n", 1142 | "868 Iteration\n", 1143 | "869 Iteration\n", 1144 | "870 Iteration\n", 1145 | "871 Iteration\n", 1146 | "872 Iteration\n", 1147 | "873 Iteration\n", 1148 | "874 Iteration\n", 1149 | "875 Iteration\n", 1150 | "876 Iteration\n", 1151 | "877 Iteration\n", 1152 | "878 Iteration\n", 1153 | "879 Iteration\n", 1154 | "880 Iteration\n", 1155 | "881 Iteration\n", 1156 | "882 Iteration\n", 1157 | "883 Iteration\n", 1158 | "884 Iteration\n", 1159 | "885 Iteration\n", 1160 | "886 Iteration\n", 1161 | "887 Iteration\n", 1162 | "888 Iteration\n", 1163 | "889 Iteration\n", 1164 | "890 Iteration\n", 1165 | "891 Iteration\n", 1166 | "892 Iteration\n", 1167 | "893 Iteration\n", 1168 | "894 Iteration\n", 1169 | "895 Iteration\n", 1170 | "896 Iteration\n", 1171 | "897 Iteration\n", 1172 | "898 Iteration\n", 1173 | "899 Iteration\n", 1174 | "900 Iteration\n", 1175 | "901 Iteration\n", 1176 | "902 Iteration\n", 1177 | "903 Iteration\n", 1178 | "904 Iteration\n", 1179 | "905 Iteration\n", 1180 | "906 Iteration\n", 1181 | "907 Iteration\n", 1182 | "908 Iteration\n", 1183 | "909 Iteration\n", 1184 | "910 Iteration\n", 1185 | "911 Iteration\n", 1186 | "912 Iteration\n", 1187 | "913 Iteration\n", 1188 | "914 Iteration\n", 1189 | "915 Iteration\n", 1190 | "916 Iteration\n", 1191 | "917 Iteration\n", 1192 | "918 Iteration\n", 1193 | "919 Iteration\n", 1194 | "920 Iteration\n", 1195 | "921 Iteration\n", 1196 | "922 Iteration\n", 1197 | "923 Iteration\n", 1198 | "924 Iteration\n", 1199 | "925 Iteration\n", 1200 | "926 Iteration\n", 1201 | "927 Iteration\n", 1202 | "928 Iteration\n", 1203 | "929 Iteration\n", 1204 | "930 Iteration\n", 1205 | "931 Iteration\n", 1206 | "932 Iteration\n", 1207 | "933 Iteration\n", 1208 | "934 Iteration\n", 1209 | "935 Iteration\n", 1210 | "936 Iteration\n", 1211 | "937 Iteration\n", 1212 | "938 Iteration\n", 1213 | "939 Iteration\n", 1214 | "940 Iteration\n", 1215 | "941 Iteration\n", 1216 | "942 Iteration\n", 1217 | "943 Iteration\n", 1218 | "944 Iteration\n", 1219 | "945 Iteration\n", 1220 | "946 Iteration\n", 1221 | "947 Iteration\n", 1222 | "948 Iteration\n", 1223 | "949 Iteration\n", 1224 | "950 Iteration\n", 1225 | "951 Iteration\n", 1226 | "952 Iteration\n", 1227 | "953 Iteration\n", 1228 | "954 Iteration\n", 1229 | "955 Iteration\n", 1230 | "956 Iteration\n", 1231 | "957 Iteration\n", 1232 | "958 Iteration\n", 1233 | "959 Iteration\n", 1234 | "960 Iteration\n", 1235 | "961 Iteration\n", 1236 | "962 Iteration\n", 1237 | "963 Iteration\n", 1238 | "964 Iteration\n", 1239 | "965 Iteration\n", 1240 | "966 Iteration\n", 1241 | "967 Iteration\n", 1242 | "968 Iteration\n", 1243 | "969 Iteration\n", 1244 | "970 Iteration\n", 1245 | "971 Iteration\n", 1246 | "972 Iteration\n", 1247 | "973 Iteration\n", 1248 | "974 Iteration\n", 1249 | "975 Iteration\n", 1250 | "976 Iteration\n", 1251 | "977 Iteration\n", 1252 | "978 Iteration\n", 1253 | "979 Iteration\n", 1254 | "980 Iteration\n", 1255 | "981 Iteration\n", 1256 | "982 Iteration\n", 1257 | "983 Iteration\n", 1258 | "984 Iteration\n", 1259 | "985 Iteration\n", 1260 | "986 Iteration\n", 1261 | "987 Iteration\n", 1262 | "988 Iteration\n", 1263 | "989 Iteration\n", 1264 | "990 Iteration\n", 1265 | "991 Iteration\n", 1266 | "992 Iteration\n", 1267 | "993 Iteration\n", 1268 | "994 Iteration\n", 1269 | "995 Iteration\n", 1270 | "996 Iteration\n", 1271 | "997 Iteration\n", 1272 | "998 Iteration\n", 1273 | "999 Iteration\n", 1274 | "1000 Iteration\n" 1275 | ] 1276 | } 1277 | ], 1278 | "source": [ 1279 | "for i, (inp, cost) in enumerate(train_loader):\n", 1280 | " if i == 1000: break\n", 1281 | " \n", 1282 | " print(f'{i + 1} Iteration')\n", 1283 | " results[i, 0] = cost.item() # true cost (from the data)\n", 1284 | " cloned = inp.clone()\n", 1285 | " trim_yant, trim_zant = reformat_ant_format(inp.squeeze(0).numpy())\n", 1286 | " \n", 1287 | " # Time the execution of CostFunArray\n", 1288 | " start_time = time.time()\n", 1289 | " results[i, 1] = CostFunArray(trim_yant, trim_zant, ParamsArray)\n", 1290 | " end_time = time.time()\n", 1291 | " results[i, 3] = end_time - start_time # true cost time\n", 1292 | " \n", 1293 | " op_yant, op_zant = torch.from_numpy(trim_yant.copy()).to(device), torch.from_numpy(trim_zant.copy()).to(device)\n", 1294 | " \n", 1295 | " # Time the execution of t_op.CostFunArray\n", 1296 | " start_time = time.time()\n", 1297 | " results[i, 2] = t_op.CostFunArray(op_yant, op_zant, OP_ParamsArray, device)\n", 1298 | " end_time = time.time()\n", 1299 | " results[i, 4] = end_time - start_time # op func time" 1300 | ] 1301 | }, 1302 | { 1303 | "cell_type": "code", 1304 | "execution_count": 45, 1305 | "metadata": {}, 1306 | "outputs": [ 1307 | { 1308 | "data": { 1309 | "text/html": [ 1310 | "
| \n", 1328 | " | True Cost (from Data) | \n", 1329 | "True Cost (from fun) | \n", 1330 | "Op True Cost (from Torch) | \n", 1331 | "True Cost Time | \n", 1332 | "Torch True Cost Time | \n", 1333 | "
|---|---|---|---|---|---|
| 0 | \n", 1338 | "-12131.305664 | \n", 1339 | "-12131.259246 | \n", 1340 | "-12131.267578 | \n", 1341 | "6.646008 | \n", 1342 | "0.028911 | \n", 1343 | "
| 1 | \n", 1346 | "-753.547546 | \n", 1347 | "-753.546092 | \n", 1348 | "-753.547424 | \n", 1349 | "6.703403 | \n", 1350 | "0.030354 | \n", 1351 | "
| 2 | \n", 1354 | "-30103.195312 | \n", 1355 | "-30103.135886 | \n", 1356 | "-30103.134766 | \n", 1357 | "6.525104 | \n", 1358 | "0.029823 | \n", 1359 | "
| 3 | \n", 1362 | "-5349.999512 | \n", 1363 | "-5349.972089 | \n", 1364 | "-5349.973145 | \n", 1365 | "6.375337 | \n", 1366 | "0.029623 | \n", 1367 | "
| 4 | \n", 1370 | "-5900.174805 | \n", 1371 | "-5900.169258 | \n", 1372 | "-5900.175293 | \n", 1373 | "6.441304 | \n", 1374 | "0.029924 | \n", 1375 | "
| ... | \n", 1378 | "... | \n", 1379 | "... | \n", 1380 | "... | \n", 1381 | "... | \n", 1382 | "... | \n", 1383 | "
| 995 | \n", 1386 | "-4333.630371 | \n", 1387 | "-4333.614120 | \n", 1388 | "-4333.617676 | \n", 1389 | "6.173140 | \n", 1390 | "0.027165 | \n", 1391 | "
| 996 | \n", 1394 | "-29530.310547 | \n", 1395 | "-29530.279616 | \n", 1396 | "-29530.275391 | \n", 1397 | "6.119851 | \n", 1398 | "0.027621 | \n", 1399 | "
| 997 | \n", 1402 | "-273.087128 | \n", 1403 | "-273.086487 | \n", 1404 | "-273.087036 | \n", 1405 | "6.407505 | \n", 1406 | "0.028393 | \n", 1407 | "
| 998 | \n", 1410 | "-597.462708 | \n", 1411 | "-597.459965 | \n", 1412 | "-597.460693 | \n", 1413 | "6.370972 | \n", 1414 | "0.028132 | \n", 1415 | "
| 999 | \n", 1418 | "-6.804787 | \n", 1419 | "-6.804786 | \n", 1420 | "-6.804805 | \n", 1421 | "6.499063 | \n", 1422 | "0.029063 | \n", 1423 | "
1000 rows × 5 columns
\n", 1427 | "