Experiment no :1
Program :
import numpy as np
import [Link] as plt
def mean_squared_error(y_true, y_predicted):
# Calculating the loss or cost
cost = [Link]((y_true-y_predicted)**2) / len(y_true)
return cost
# Gradient Descent Function
# Here iterations, learning_rate, stopping_threshold
# are hyperparameters that can be tuned
def gradient_descent(x, y, iterations = 1000, learning_rate = 0.0001,
stopping_threshold = 1e-6):
# Initializing weight, bias, learning rate and iterations
current_weight = 0.1
current_bias = 0.01
iterations = iterations
learning_rate = learning_rate
n = float(len(x))
costs = []
weights = []
previous_cost = None
# Estimation of optimal parameters
for i in range(iterations):
# Making predictions
y_predicted = (current_weight * x) + current_bias
# Calculating the current cost
current_cost = mean_squared_error(y, y_predicted)
# If the change in cost is less than or equal to
# stopping_threshold we stop the gradient descent
if previous_cost and abs(previous_cost-current_cost)<=stopping_threshold:
break
previous_cost = current_cost
[Link](current_cost)
[Link](current_weight)
# Calculating the gradients
weight_derivative = -(2/n) * sum(x * (y-y_predicted))
bias_derivative = -(2/n) * sum(y-y_predicted)
# Updating weights and bias
current_weight = current_weight - (learning_rate * weight_derivative)
current_bias = current_bias - (learning_rate * bias_derivative)
# Printing the parameters for each 1000th iteration
print(f"Iteration {i+1}: Cost {current_cost}, Weight \
{current_weight}, Bias {current_bias}")
# Visualizing the weights and cost at for all iterations
[Link](figsize = (8,6))
[Link](weights, costs)
[Link](weights, costs, marker='o', color='red')
[Link]("Cost vs Weights")
[Link]("Cost")
[Link]("Weight")
[Link]()
return current_weight, current_bias
def main():
# Data
X = [Link]([32.50234527, 53.42680403, 61.53035803, 47.47563963, 59.81320787,
55.14218841, 52.21179669, 39.29956669, 48.10504169, 52.55001444,
45.41973014, 54.35163488, 44.1640495 , 58.16847072, 56.72720806,
48.95588857, 44.68719623, 60.29732685, 45.61864377, 38.81681754])
Y = [Link]([31.70700585, 68.77759598, 62.5623823 , 71.54663223, 87.23092513,
78.21151827, 79.64197305, 59.17148932, 75.3312423 , 71.30087989,
55.16567715, 82.47884676, 62.00892325, 75.39287043, 81.43619216,
60.72360244, 82.89250373, 97.37989686, 48.84715332, 56.87721319])
# Estimating weight and bias using gradient descent
estimated_weight, estimated_bias = gradient_descent(X, Y, iterations=2000)
print(f"Estimated Weight: {estimated_weight}\nEstimated Bias: {estimated_bias}")
# Making predictions using estimated parameters
Y_pred = estimated_weight*X + estimated_bias
# Plotting the regression line
[Link](figsize = (8,6))
[Link](X, Y, marker='o', color='red')
[Link]([min(X), max(X)], [min(Y_pred), max(Y_pred)], color='blue',markerfacecolor='red',
markersize=10,linestyle='dashed')
[Link]("X")
[Link]("Y")
[Link]()
if __name__=="__main__":
main()
Output:
Iteration 1: Cost 4352.088931274409, Weight 0.7593291142562117, Bias
0.02288558130709
Iteration 2: Cost 1114.8561474350017, Weight 1.081602958862324, Bias
0.02918014748569513
Iteration 3: Cost 341.42912086804455, Weight 1.2391274084945083, Bias
0.03225308846928192
Iteration 4: Cost 156.64495290904443, Weight 1.3161239281746984, Bias
0.03375132986012604
Iteration 5: Cost 112.49704004742098, Weight 1.3537591652024805, Bias
0.034479873154934775
Iteration 6: Cost 101.9493925395456, Weight 1.3721549833978113, Bias
0.034832195392868505
Iteration 7: Cost 99.4293893333546, Weight 1.3811467575154601, Bias
0.03500062439068245
Iteration 8: Cost 98.82731958262897, Weight 1.3855419247507244, Bias
0.03507916814736111
Iteration 9: Cost 98.68347500997261, Weight 1.3876903144657764, Bias
0.035113776874486774
Iteration 10: Cost 98.64910780902792, Weight 1.3887405007983562, Bias
0.035126910596389935
Iteration 11: Cost 98.64089651459352, Weight 1.389253895811451, Bias
0.03512954755833985
Iteration 12: Cost 98.63893428729509, Weight 1.38950491235671, Bias
0.035127053821718185
Iteration 13: Cost 98.63846506273883, Weight 1.3896276808137857, Bias
0.035122052266051224
Iteration 14: Cost 98.63835254057648, Weight 1.38968776283053, Bias
0.03511582492978764
Iteration 15: Cost 98.63832524036214, Weight 1.3897172043139192, Bias
0.03510899846107016
Iteration 16: Cost 98.63831830104695, Weight 1.389731668997059, Bias
0.035101879159522745
Iteration 17: Cost 98.63831622628217, Weight 1.389738813163012, Bias
0.03509461674147458
Estimated Weight: 1.389738813163012
Estimated Bias: 0.03509461674147458
Experiment no .2
Program code
import numpy as np
def sgd(
gradient, x, y, start, learn_rate=0.1, decay_rate=0.0, batch_size=1,
n_iter=50, tolerance=1e-06, dtype="float64", random_state=None
):
# Checking if the gradient is callable
if not callable(gradient):
raise TypeError("'gradient' must be callable")
# Setting up the data type for NumPy arrays
dtype_ = [Link](dtype)
# Converting x and y to NumPy arrays
x, y = [Link](x, dtype=dtype_), [Link](y, dtype=dtype_)
n_obs = [Link][0]
if n_obs != [Link][0]:
raise ValueError("'x' and 'y' lengths do not match")
xy = np.c_[[Link](n_obs, -1), [Link](n_obs, 1)]
# Initializing the random number generator
seed = None if random_state is None else int(random_state)
rng = [Link].default_rng(seed=seed)
# Initializing the values of the variables
vector = [Link](start, dtype=dtype_)
# Setting up and checking the learning rate
learn_rate = [Link](learn_rate, dtype=dtype_)
if [Link](learn_rate <= 0):
raise ValueError("'learn_rate' must be greater than zero")
# Setting up and checking the decay rate
decay_rate = [Link](decay_rate, dtype=dtype_)
if [Link](decay_rate < 0) or [Link](decay_rate > 1):
raise ValueError("'decay_rate' must be between zero and one")
# Setting up and checking the size of minibatches
batch_size = int(batch_size)
if not 0 < batch_size <= n_obs:
raise ValueError(
"'batch_size' must be greater than zero and less than "
"or equal to the number of observations"
)
# Setting up and checking the maximal number of iterations
n_iter = int(n_iter)
if n_iter <= 0:
raise ValueError("'n_iter' must be greater than zero")
# Setting up and checking the tolerance
tolerance = [Link](tolerance, dtype=dtype_)
if [Link](tolerance <= 0):
raise ValueError("'tolerance' must be greater than zero")
# Setting the difference to zero for the first iteration
diff = 0
# Performing the gradient descent loop
for _ in range(n_iter):
# Shuffle x and y
[Link](xy)
# Performing minibatch moves
for start in range(0, n_obs, batch_size):
stop = start + batch_size
x_batch, y_batch = xy[start:stop, :-1], xy[start:stop, -1:]
# Recalculating the difference
grad = [Link](gradient(x_batch, y_batch, vector), dtype_)
diff = decay_rate * diff - learn_rate * grad
# Checking if the absolute difference is small enough
if [Link]([Link](diff) <= tolerance):
break
# Updating the values of the variables
vector += diff
return vector if [Link] else [Link]()
Experiment no:3
Program :
# Python3 code for implementation of Newton
# Raphson Method for solving equations
# An example function whose solution
# is determined using Bisection Method.
# The function is x^3 - x^2 + 2
def func( x ):
return x * x * x - x * x + 2
# Derivative of the above function
# which is 3*x^x - 2*x
def derivFunc( x ):
return 3 * x * x - 2 * x
# Function to find the root
def newtonRaphson( x ):
h = func(x) / derivFunc(x)
while abs(h) >= 0.0001:
h = func(x)/derivFunc(x)
# x(i+1) = x(i) - f(x) / f'(x)
x=x-h
print("The value of the root is : ",
"%.4f"% x)
# Driver program to test above
x0 = -20 # Initial values assumed
newtonRaphson(x0)
Output : The value of root is : -1.00
Experiment no:4
Program
import random
# Number of individuals in each generation
POPULATION_SIZE = 100
# Valid genes
GENES = '''abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP
QRSTUVWXYZ 1234567890, .-;:_!"#%&/()=?@${[]}'''
# Target string to be generated
TARGET = "I love GeeksforGeeks"
class Individual(object):
'''
Class representing individual in population
'''
def __init__(self, chromosome):
[Link] = chromosome
[Link] = self.cal_fitness()
@classmethod
def mutated_genes(self):
'''
create random genes for mutation
'''
global GENES
gene = [Link](GENES)
return gene
@classmethod
def create_gnome(self):
'''
create chromosome or string of genes
'''
global TARGET
gnome_len = len(TARGET)
return [self.mutated_genes() for _ in range(gnome_len)]
def mate(self, par2):
'''
Perform mating and produce new offspring
'''
# chromosome for offspring
child_chromosome = []
for gp1, gp2 in zip([Link], [Link]):
# random probability
prob = [Link]()
# if prob is less than 0.45, insert gene
# from parent 1
if prob < 0.45:
child_chromosome.append(gp1)
# if prob is between 0.45 and 0.90, insert
# gene from parent 2
elif prob < 0.90:
child_chromosome.append(gp2)
# otherwise insert random gene(mutate),
# for maintaining diversity
else:
child_chromosome.append(self.mutated_genes())
# create new Individual(offspring) using
# generated chromosome for offspring
return Individual(child_chromosome)
def cal_fitness(self):
'''
Calculate fitness score, it is the number of
characters in string which differ from target
string.
'''
global TARGET
fitness = 0
for gs, gt in zip([Link], TARGET):
if gs != gt: fitness+= 1
return fitness
# Driver code
def main():
global POPULATION_SIZE
#current generation
generation = 1
found = False
population = []
# create initial population
for _ in range(POPULATION_SIZE):
gnome = Individual.create_gnome()
[Link](Individual(gnome))
while not found:
# sort the population in increasing order of fitness score
population = sorted(population, key = lambda x:[Link])
# if the individual having lowest fitness score ie.
# 0 then we know that we have reached to the target
# and break the loop
if population[0].fitness <= 0:
found = True
break
# Otherwise generate new offsprings for new generation
new_generation = []
# Perform Elitism, that mean 10% of fittest population
# goes to the next generation
s = int((10*POPULATION_SIZE)/100)
new_generation.extend(population[:s])
# From 50% of fittest population, Individuals
# will mate to produce offspring
s = int((90*POPULATION_SIZE)/100)
for _ in range(s):
parent1 = [Link](population[:50])
parent2 = [Link](population[:50])
child = [Link](parent2)
new_generation.append(child)
population = new_generation
print("Generation: {}\tString: {}\tFitness: {}".\
format(generation,
"".join(population[0].chromosome),
population[0].fitness))
generation += 1
print("Generation: {}\tString: {}\tFitness: {}".\
format(generation,
"".join(population[0].chromosome),
population[0].fitness))
Output :
Generation: 1 String: tO{"-?=jH[k8=B4]Oe@} Fitness: 18
Generation: 2 String: tO{"-?=jH[k8=B4]Oe@} Fitness: 18
Generation: 3 String: .#lRWf9k_Ifslw #O$k_ Fitness: 17
Generation: 4 String: .-1Rq?9mHqk3Wo]3rek_ Fitness: 16
Generation: 5 String: .-1Rq?9mHqk3Wo]3rek_ Fitness: 16
Generation: 6 String: A#ldW) #lIkslw cVek) Fitness: 14
Generation: 7 String: A#ldW) #lIkslw cVek) Fitness: 14
Generation: 8 String: (, o x _x%Rs=, 6Peek3 Fitness: 13
.
.
.
Generation: 29 String: I lope Geeks#o, Geeks Fitness: 3
Generation: 30 String: I loMe GeeksfoBGeeks Fitness: 2
Generation: 31 String: I love Geeksfo0Geeks Fitness: 1
Generation: 32 String: I love Geeksfo0Geeks Fitness: 1
Generation: 33 String: I love Geeksfo0Geeks Fitness: 1
Generation: 34 String: I love GeeksforGeeks Fitness: 0
Experiment no 5
import random
# Example Fitness Function (Replace with your own)
def fitness_function(chromosome):
return sum(chromosome)
# Roulette Wheel Selection
def roulette_wheel_selection(population, fitnesses):
total_fitness = sum(fitnesses)
selection_point = [Link](0, total_fitness)
cumulative_fitness = 0
for i, individual in enumerate(population):
cumulative_fitness += fitnesses[i]
if cumulative_fitness > selection_point:
return individual
# Tournament Selection
def tournament_selection(population, fitnesses, tournament_size=2):
tournament = [Link](list(zip(population, fitnesses)), tournament_size)
return max(tournament, key=lambda x: x[1])[0]
# Rank Selection
def rank_selection(population, fitnesses):
ranked_population = sorted(list(zip(population, fitnesses)), key=lambda x:
x[1])
selection_probabilities = [i / len(population) for i in range(1,
len(population) + 1)]
selected_individual = [Link](ranked_population,
weights=selection_probabilities)[0]
return selected_individual[0]
# Advanced Roulette Wheel Selection with Stochastic Universal Sampling (SUS)
def sus_selection(population, fitnesses, num_parents):
total_fitness = sum(fitnesses)
average_fitness = total_fitness / len(population)
start_point = [Link](0, average_fitness)
pointers = [start_point + i * average_fitness for i in range(num_parents)]
selected_parents = []
cumulative_fitness = 0
i = 0
for fitness in fitnesses:
cumulative_fitness += fitness
while pointers and cumulative_fitness > pointers[0]:
selected_parents.append(population[i])
[Link](0)
i += 1
return selected_parents
# Example Usage
population = [[[Link](0, 1) for _ in range(10)] for _ in range(20)]
fitnesses = [fitness_function(individual) for individual in population]
# Roulette Wheel Selection
selected_individual = roulette_wheel_selection(population, fitnesses)
print("Roulette Wheel Selection:", selected_individual)
# Tournament Selection
selected_individual = tournament_selection(population, fitnesses)
print("Tournament Selection:", selected_individual)
# Rank Selection
selected_individual = rank_selection(population, fitnesses)
print("Rank Selection:", selected_individual)
# Stochastic Universal Sampling Selection
selected_parents = sus_selection(population, fitnesses, num_parents=5)
print("Stochastic Universal Sampling Selection:", selected_parents)
Output:
Experiment no 6
import random
# Mutation Mechanisms
def bit_flip_mutation(individual, mutation_rate):
mutated_individual = individual[:]
for i in range(len(mutated_individual)):
if [Link]() < mutation_rate:
mutated_individual[i] = 1 - mutated_individual[i] # Flips the bit
return mutated_individual
def gaussian_mutation(individual, mutation_rate, sigma=0.1):
mutated_individual = individual[:]
for i in range(len(mutated_individual)):
if [Link]() < mutation_rate:
mutated_individual[i] += [Link](0, sigma)
return mutated_individual
def uniform_mutation(individual, mutation_rate, min_val, max_val):
mutated_individual = individual[:]
for i in range(len(mutated_individual)):
if [Link]() < mutation_rate:
mutated_individual[i] = [Link](min_val, max_val)
return mutated_individual
# Crossover Mechanisms
def single_point_crossover(parent1, parent2):
crossover_point = [Link](1, len(parent1) - 1)
child1 = parent1[:crossover_point] + parent2[crossover_point:]
child2 = parent2[:crossover_point] + parent1[crossover_point:]
return child1, child2
def two_point_crossover(parent1, parent2):
point1 = [Link](1, len(parent1) - 2)
point2 = [Link](point1, len(parent1) - 1)
child1 = parent1[:point1] + parent2[point1:point2] + parent1[point2:]
child2 = parent2[:point1] + parent1[point1:point2] + parent2[point2:]
return child1, child2
def uniform_crossover(parent1, parent2):
child1 = []
child2 = []
for i in range(len(parent1)):
if [Link]() < 0.5:
[Link](parent1[i])
[Link](parent2[i])
else:
[Link](parent2[i])
[Link](parent1[i])
return child1, child2
# Example Genetic Algorithm
def initial_population(population_size, chromosome_length):
return [[[Link](0, 1) for _ in range(chromosome_length)] for _ in
range(population_size)]
def fitness_function(chromosome):
return sum(chromosome)
def select_parents(population):
return [Link](population, k=2)
def genetic_algorithm(population_size, chromosome_length, mutation_rate,
generations):
population = initial_population(population_size, chromosome_length)
for _ in range(generations):
new_population = []
for _ in range(population_size // 2):
parent1, parent2 = select_parents(population)
child1, child2 = single_point_crossover(parent1, parent2)
child1 = bit_flip_mutation(child1, mutation_rate)
child2 = gaussian_mutation(child2, mutation_rate)
new_population.extend([child1, child2])
population = new_population
best_individual = max(population, key=fitness_function)
print("Generation:", _, "Best Individual:", best_individual, "Fitness:",
fitness_function(best_individual))
# Example Usage
genetic_algorithm(population_size=20, chromosome_length=10, mutation_rate=0.1,
generations=50)
Output:
Experiment no 7
import random
import math
import copy
import sys
#-------fitness functions---------
# rastrigin function
def fitness_rastrigin(position):
fitnessVal = 0.0
for i in range(len(position)):
xi = position[i]
fitnessVal += (xi * xi) - (10 * [Link](2 * [Link] * xi)) + 10
return fitnessVal
#sphere function
def fitness_sphere(position):
fitnessVal = 0.0
for i in range(len(position)):
xi = position[i]
fitnessVal += (xi*xi)
return fitnessVal
#-------------------------
#particle class
class Particle:
def __init__(self, fitness, dim, minx, maxx, seed):
[Link] = [Link](seed)
# initialize position of the particle with 0.0 value
[Link] = [0.0 for i in range(dim)]
# initialize velocity of the particle with 0.0 value
[Link] = [0.0 for i in range(dim)]
# initialize best particle position of the particle with 0.0 value
self.best_part_pos = [0.0 for i in range(dim)]
# loop dim times to calculate random position and velocity
# range of position and velocity is [minx, max]
for i in range(dim):
[Link][i] = ((maxx - minx) * [Link]() + minx)
[Link][i] = ((maxx - minx) * [Link]() + minx)
# compute fitness of particle
[Link] = fitness([Link]) # curr fitness
# initialize best position and fitness of this particle
self.best_part_pos = [Link]([Link])
self.best_part_fitnessVal = [Link] # best fitness
# particle swarm optimization function
def pso(fitness, max_iter, n, dim, minx, maxx):
# hyper parameters
w = 0.729 # inertia
c1 = 1.49445 # cognitive (particle)
c2 = 1.49445 # social (swarm)
rnd = [Link](0)
# create n random particles
swarm = [Particle(fitness, dim, minx, maxx, i) for i in range(n)]
# compute the value of best_position and best_fitness in swarm
best_swarm_pos = [0.0 for i in range(dim)]
best_swarm_fitnessVal = sys.float_info.max # swarm best
# computer best particle of swarm and it's fitness
for i in range(n): # check each particle
if swarm[i].fitness < best_swarm_fitnessVal:
best_swarm_fitnessVal = swarm[i].fitness
best_swarm_pos = [Link](swarm[i].position)
# main loop of pso
Iter = 0
while Iter < max_iter:
# after every 10 iterations
# print iteration number and best fitness value so far
if Iter % 10 == 0 and Iter > 1:
print("Iter = " + str(Iter) + " best fitness = %.3f" %
best_swarm_fitnessVal)
for i in range(n): # process each particle
# compute new velocity of curr particle
for k in range(dim):
r1 = [Link]() # randomizations
r2 = [Link]()
swarm[i].velocity[k] = (
(w * swarm[i].velocity[k]) +
(c1 * r1 * (swarm[i].best_part_pos[k] -
swarm[i].position[k])) +
(c2 * r2 * (best_swarm_pos[k] -
swarm[i].position[k]))
)
# if velocity[k] is not in [minx, max]
# then clip it
if swarm[i].velocity[k] < minx:
swarm[i].velocity[k] = minx
elif swarm[i].velocity[k] > maxx:
swarm[i].velocity[k] = maxx
# compute new position using new velocity
for k in range(dim):
swarm[i].position[k] += swarm[i].velocity[k]
# compute fitness of new position
swarm[i].fitness = fitness(swarm[i].position)
# is new position a new best for the particle?
if swarm[i].fitness < swarm[i].best_part_fitnessVal:
swarm[i].best_part_fitnessVal = swarm[i].fitness
swarm[i].best_part_pos = [Link](swarm[i].position)
# is new position a new best overall?
if swarm[i].fitness < best_swarm_fitnessVal:
best_swarm_fitnessVal = swarm[i].fitness
best_swarm_pos = [Link](swarm[i].position)
# for-each particle
Iter += 1
#end_while
return best_swarm_pos
# end pso
#----------------------------
# Driver code for rastrigin function
print("\nBegin particle swarm optimization on rastrigin function\n")
dim = 3
fitness = fitness_rastrigin
print("Goal is to minimize Rastrigin's function in " + str(dim) + " variables")
print("Function has known min = 0.0 at (", end="")
for i in range(dim-1):
print("0, ", end="")
print("0)")
num_particles = 50
max_iter = 100
print("Setting num_particles = " + str(num_particles))
print("Setting max_iter = " + str(max_iter))
print("\nStarting PSO algorithm\n")
best_position = pso(fitness, max_iter, num_particles, dim, -10.0, 10.0)
print("\nPSO completed\n")
print("\nBest solution found:")
print(["%.6f"%best_position[k] for k in range(dim)])
fitnessVal = fitness(best_position)
print("fitness of best solution = %.6f" % fitnessVal)
print("\nEnd particle swarm for rastrigin function\n")
print()
print()
# Driver code for Sphere function
print("\nBegin particle swarm optimization on sphere function\n")
dim = 3
fitness = fitness_sphere
print("Goal is to minimize sphere function in " + str(dim) + " variables")
print("Function has known min = 0.0 at (", end="")
for i in range(dim-1):
print("0, ", end="")
print("0)")
num_particles = 50
max_iter = 100
print("Setting num_particles = " + str(num_particles))
print("Setting max_iter = " + str(max_iter))
print("\nStarting PSO algorithm\n")
best_position = pso(fitness, max_iter, num_particles, dim, -10.0, 10.0)
print("\nPSO completed\n")
print("\nBest solution found:")
print(["%.6f"%best_position[k] for k in range(dim)])
fitnessVal = fitness(best_position)
print("fitness of best solution = %.6f" % fitnessVal)
print("\nEnd particle swarm for sphere function\n")
Output:
Experiment no 8
import numpy as np
import [Link] as plt
from mpl_toolkits.mplot3d import Axes3D
def distance(point1, point2):
return [Link]([Link]((point1 - point2)**2))
def ant_colony_optimization(points, n_ants, n_iterations, alpha, beta,
evaporation_rate, Q):
n_points = len(points)
pheromone = [Link]((n_points, n_points))
best_path = None
best_path_length = [Link]
for iteration in range(n_iterations):
paths = []
path_lengths = []
for ant in range(n_ants):
visited = [False]*n_points
current_point = [Link](n_points)
visited[current_point] = True
path = [current_point]
path_length = 0
while False in visited:
unvisited = [Link](np.logical_not(visited))[0]
probabilities = [Link](len(unvisited))
for i, unvisited_point in enumerate(unvisited):
probabilities[i] = pheromone[current_point,
unvisited_point]**alpha / distance(points[current_point],
points[unvisited_point])**beta
probabilities /= [Link](probabilities)
next_point = [Link](unvisited, p=probabilities)
[Link](next_point)
path_length += distance(points[current_point], points[next_point])
visited[next_point] = True
current_point = next_point
[Link](path)
path_lengths.append(path_length)
if path_length < best_path_length:
best_path = path
best_path_length = path_length
pheromone *= evaporation_rate
for path, path_length in zip(paths, path_lengths):
for i in range(n_points-1):
pheromone[path[i], path[i+1]] += Q/path_length
pheromone[path[-1], path[0]] += Q/path_length
fig = [Link](figsize=(8, 6))
ax = fig.add_subplot(111, projection='3d')
[Link](points[:,0], points[:,1], points[:,2], c='r', marker='o')
for i in range(n_points-1):
[Link]([points[best_path[i],0], points[best_path[i+1],0]],
[points[best_path[i],1], points[best_path[i+1],1]],
[points[best_path[i],2], points[best_path[i+1],2]],
c='g', linestyle='-', linewidth=2, marker='o')
[Link]([points[best_path[0],0], points[best_path[-1],0]],
[points[best_path[0],1], points[best_path[-1],1]],
[points[best_path[0],2], points[best_path[-1],2]],
c='g', linestyle='-', linewidth=2, marker='o')
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')
[Link]()
# Example usage:
points = [Link](10, 3) # Generate 10 random 3D points
ant_colony_optimization(points, n_ants=10, n_iterations=100, alpha=1, beta=1,
evaporation_rate=0.5, Q=1)
Output: