SCA_merged
SCA_merged
The aim of this experiment is to perform basic operations like union, intersection, Min-Max product,
complement, and difference on fuzzy sets. Fuzzy logic expands classical set theory, allowing partial
membership between 0 and 1. This is essential for real-world scenarios where binary outcomes
aren't sufficient. For instance, union calculates the maximum membership value, while intersection
computes the minimum. Complement is the inverse, and difference involves finding the minimum of
a value and its complement. This understanding is foundational for applications in uncertain
environments like weather prediction, decision-making, and machine learning.
6 Implementing gradient
algorithm for finding the optimal
set of weights and biases
2
Experiment 1
Theory:
Code:
def union(A,B):
result={}
for i in A:
if(A[i]>B[i]):
3
result[i]=A[i]
else:
result[i]=B[i]
print('Union Of Two Sets : ',result)
def intersect(A,B):
result={}
for i in A:
if(A[i]>B[i]):
result[i]=A[i]
else:
result[i]=B[i]
print('Intersection Of Two Sets : ',result)
def complement(A):
result={}
result1={}
for i in A:
result[i]=round(1-A[i],2)
for i in B:
result1[i]=round(1-B[i],2)
print('Complement of Set A : ',result)
print('Complement of Set B : ',result1)
def difference(A,B):
result={}
for i in A:
result[i]=round(min(A[i],1-B[i]),2)
print('Difference is :',result)
def sum(A,B):
result = {}
for key in A:
if key in B:
result[key] = round(A[key] + B[key] - (A[key] * B[key]), 2)
print('Sum is : ', result)
def dot_product(A, B):
result = 0
for key in A:
if key in B:
result += A[key] * B[key]
print("Dot product is:", result)
def scalar_a(A,C):
result = {}
for key in A:
result[key] = A[key] * C
print("Set A multiplied by",C,"is",result)
4
def scalar_b(B,C):
result = {}
for key in B:
result[key] = B[key] * C
print("Set B multiplied by",C,"is",result)
def cart_product(A,B):
cart_prod={}
for elem_A,mem_A in A.items():
for elem_B,mem_B in B.items():
cart_prod[(elem_A,elem_B)]=min(mem_A,mem_B)
print('Cartesian Product is : ',cart_prod)
def cart_product(A,B):
cart_prod={}
for elem_A,mem_A in A.items():
for elem_B,mem_B in B.items():
cart_prod[(elem_A,elem_B)]=min(mem_A,mem_B)
print('Cartesian Product is : ',cart_prod)
Asking user for the choosing the operation they want to perform
5
print("5.Sum")
print("6.Dot Products")
print("7.Product of integer with set A")
print("8.Product of integer with set B")
print("9.Cartesian Product")
print("10.Print All")
if choice==1:
union(A,B)
elif choice==2:
intersect(A,B)
elif choice==3:
complement(A)
elif choice==4:
difference(A,B)
elif choice==5:
sum(A,B)
elif choice==6:
dot_product(A,B)
elif choice==7:
alpha=int(input("Enter The Value you want to multiply SET A with :
"))
scalar_a(A,alpha)
elif choice==8:
beta=int(input("Enter The Value you want to multiply SET B with :
"))
scalar_b(B,beta)
elif choice==9:
import numpy as np
cart_product(A,B)
elements_A = list(A.keys())
elements_B = list(B.keys())
relation_matrix = np.zeros((len(elements_A), len(elements_B)))
for i, elem_A in enumerate(elements_A):
for j, elem_B in enumerate(elements_B):
relation_matrix[i, j] = min(A[elem_A], B[elem_B])
print("Relation Matrix:")
header = " " + " ".join(f"{elem_B:>4}" for elem_B in
elements_B)
print(header)
for i, elem_A in enumerate(elements_A):
6
row = f"{elem_A:>4}: " + " ".join(f"{relation_matrix[i,
j]:>4.1f}" for j in range(len(elements_B)))
print(row)
elif choice==10:
union(A,B)
intersect(A,B)
complement(A)
difference(A,B)
sum(A,B)
dot_product(A,B)
alpha=int(input("Enter The Value you want to multiply SET A with :
"))
scalar_a(A,alpha)
beta=int(input("Enter The Value you want to multiply SET B with :
"))
scalar_b(B,beta)
elif choice==0:
exit
else:
print("Invalid Choice")
Output:
import numpy as np
7
def get_fuzzy_relation(name):
relation = {}
print(f"Enter pairs and membership values for {name} (format:
'element1 element2 value'). Type 'done' when finished:")
while True:
user_input = input()
if user_input.lower() == 'done':
break
try:
element1, element2, value = user_input.split()
relation[(element1, element2)] = float(value)
except ValueError:
print("Invalid input. Please enter in the format: 'element1
element2 value'")
return relation
for i, a in enumerate(elements_A):
for j, c in enumerate(elements_C):
max_min = 0
for b in elements_B:
if (a, b) in R and (b, c) in S:
max_min = max(max_min, min(R[(a, b)], S[(b, c)]))
composition_matrix[ i, j] = max_min
8
Output
9
Experiment 2
Theory:
Implementation
Input Variables: Common inputs include the current speed of the
vehicle, the distance to the vehicle ahead, and acceleration. These
inputs are fuzzified using membership functions to categorize them
into linguistic variables like "slow," "medium," and "fast."
Fuzzy Rule Base: A set of rules is defined, such as:
10
Code:
import numpy as np
Speed = 80
Acceleration = 105
# Fuzzy Partition
def partition(x):
NL = NM = NS = ZE = PS = PM = PL = 0
11
if 90 < x < 150:
ZE = triangular(x, 90, 120, 150)
if 120 < x < 180:
PS = triangular(x, 120, 150, 180)
if 150 < x < 210:
PM = triangular(x, 120, 150, 180)
if 180 < x < 240:
PL = openRight(x, 180, 210)
# Getting fuzzy values for all the inputs for all the fuzzy sets
NLSD, NMSD, NSSD, ZESD, PSSD, PMSD, PLSD = partition(Speed)
NLAC, NMAC, NSAC, ZEAC, PSAC, PMAC, PLAC = partition(Acceleration)
# Rules implementation
def compare(TC1, TC2):
TC = 0
if TC1>TC2 and TC1 !=0 and TC2 !=0:
TC = TC2
else:
TC = TC1
if TC1 == 0 and TC2 !=0:
TC = TC2
if TC2 == 0 and TC1 !=0:
TC = TC1
return TC
def rule(NLSD, NMSD, NSSD, ZESD, PSSD, PMSD, PLSD, NLAC, NMAC, NSAC,
ZEAC, PSAC, PMAC, PLAC):
PLTC1 = min(NLSD, ZEAC)
PLTC2 = min(ZESD, NLAC)
PLTC = compare(PLTC1, PLTC2)
12
PMTC2 = min(ZESD, NMAC)
PMTC = compare(PMTC1, PMTC2)
PLTC, PMTC, PSTC, NSTC, NLTC = rule(NLSD, NMSD, NSSD, ZESD, PSSD, PMSD,
PLSD, NLAC, NMAC, NSAC, ZEAC, PSAC, PMAC, PLAC)
print("\n")
# Display the fuzzy values for all rules
outPutRules = [[PLTC, PMTC, PSTC, NSTC, NLTC]]
print("The fuzzy output: ")
print(["PLTC", "PMTC", "PSTC", "NSTC", "NLTC"])
print(np.round(outPutRules, 2))
# De-fuzzyfication
def areaTR(mu, a, b, c):
x1 = mu * (b - a) + a
x2 = c - mu * (c - b)
d1 = c - a
d2 = x2 - x1
aTR = (1 / 2) * mu * (d1 + d2)
return aTR
13
if PLTC != 0:
areaPL, cPL = areaOR(PLTC, 180, 210)
if PMTC != 0:
areaPM = areaTR(PMTC, 150, 180, 210)
cPM = 180
if PSTC != 0:
areaPS = areaTR(PSTC, 120, 150, 180)
cPS = 150
if NSTC != 0:
areaNS = areaTR(NSTC, 60, 90, 120)
cNS = 90
if NLTC != 0:
areaNL, cNL = areaOL(NLTC, 30, 60)
if denominator == 0:
print("No rules exist to give the result")
return 0
else:
crispOutput = numerator / denominator
return crispOutput
if crispOutputFinal != 0:
print("\nThe crisp TC value is: ", crispOutputFinal)
14
Output
15
Experiment 3
Theory:
16
Code:
17
c = a[2:7:1]; print("a[2:7:1] = ", c)
# access 3 elements separated by two
c = a[2:7:2]; print("a[2:7:2] = ", c)
# access all elements index 3 and above
c = a[3:]; print("a[3:] = ", c)
# access all elements below index 3 c = a[:3]; print("a[:3] = ", c)
# access all elements
c = a[:]; print("a[:] = ", c)
Output
a = np.array([1,2,3,4])
print(f"a : {a}") # negate elements of a
b = -a
print(f"b = -a : {b}") # sum all elements of a, returns a scalar
b = np.sum(a)
print(f"b = np.sum(a) : {b}")
b = np.mean(a)
print(f"b = np.mean(a): {b}")
b = a**2
print(f"b = a**2 : {b}")
Output
a = np.array([1, 2, 3, 4])
# multiply a by a scalar
b = 5 * a
print(f"b = 5 * a : {b}")
def my_dot(a, b):
"""
Compute the dot product of two vectors
Args:
a (ndarray (n,)): input vector
b (ndarray (n,)): input vector with same dimension as a
18
Returns:
x (scalar):
"""
x=0
for i in range(a.shape[0]):
x = x + a[i] * b[i]
return x # test 1-D
a = np.array([1, 2, 3, 4])
b = np.array([-1, 4, 3, 2])
print(f"my_dot(a, b) = {my_dot(a, b)}")
a = np.array([1, 2, 3, 4])
b = np.array([-1, 4, 3, 2])
c = np.dot(a, b)
print(f"NumPy 1-D np.dot(a, b) = {c}, np.dot(a, b).shape = {c.shape} ")
c = np.dot(b, a)
print(f"NumPy 1-D np.dot(b, a) = {c}, np.dot(a, b).shape = {c.shape} ")
np.random.seed(1)
a = np.random.rand(10000000) # very large arrays
b = np.random.rand(10000000)
tic = time.time() # capture start time
c = np.dot(a, b)
toc = time.time() # capture end time
print(f"np.dot(a, b) = {c:.4f}")
print(f"Vectorized version duration: {1000*(toc-tic):.4f} ms ")
tic = time.time() # capture start time
c = my_dot(a,b)
toc = time.time() # capture end time
print(f"my_dot(a, b) = {c:.4f}")
print(f"loop version duration: {1000*(toc-tic):.4f} ms ")
del(a)
del(b) #remove these big arrays from memory
X = np.array([[1],[2],[3],[4]])
w = np.array([2])
c = np.dot(X[1], w)
print(f"X[1] has shape {X[1].shape}")
print(f"w has shape {w.shape}")
print(f"c has shape {c.shape}")
19
a = np.zeros((1, 5))
print(f"a shape = {a.shape}, a = {a}")
a = np.zeros((2, 1))
print(f"a shape = {a.shape}, a = {a}")
a = np.random.random_sample((1, 1))
print(f"a shape = {a.shape}, a = {a}")
20
a = np.arange(6).reshape(-1, 2)
print(a)
a = np.arange(20).reshape(-1, 10)
print(f"a = \n{a}")
#access 5 consecutive elements (start:stop:step)
print("a[0, 2:7:1] = ", a[0, 2:7:1], ", a[0, 2:7:1].shape =", a[0,
2:7:1].shape, "a 1-D array")
#access 5 consecutive elements (start:stop:step) in two rows
print("a[:, 2:7:1] = \n", a[:, 2:7:1], ", a[:, 2:7:1].shape =", a[:,
2:7:1].shape, "a 2-D array") # access all elements
print("a[:,:] = \n", a[:,:], ", a[:,:].shape =", a[:,:].shape)
# access all elements in one row (very common usage)
print("a[1,:] = ", a[1,:], ", a[1,:].shape =", a[1,:].shape, "a 1-D
array") # same as
print("a[1] = ", a[1], ", a[1].shape =", a[1].shape, "a 1-D array")
21
Experiment 4
Theory:
22
Code:
23
Output of AND Gate
Implementing OR Gate:
# OR Logic Function
# w1 = 1, w2 = 1, b = -0.5
def OR_logicFunction(x):
w = np.array([1, 1])
b = -0.5
return perceptronModel(x, w, b)
24
Output of OR Gate
# OR Logic Function
# w1 = 1, w2 = 1, bOR = -0.5
def OR_logicFunction(x):
w = np.array([1, 1])
bOR = -0.5
return perceptronModel(x, w, bOR)
25
output_NOT = NOT_logicFunction(output_OR)
return output_NOT
26
wNOT = 1
bNOT = 0.5
return perceptronModel(x, wNOT, bNOT)
27
return 1
else:
return 0
# OR Logic Function
# w1 = 1, w2 = 1, bOR = -0.5
def OR_logicFunction(x):
w = np.array([1, 1])
bOR = -0.5
return perceptronModel(x, w, bOR)
28
# testing the Perceptron Model
test1 = np.array([0, 1])
test2 = np.array([1, 1])
test3 = np.array([0, 0])
test4 = np.array([1, 0])
29
# AND Logic Function
# w1 = 1, w2 = 1, bAND = -0.5
def AND_logicFunction(x):
w = np.array([1, 1])
bAND = -0.5
return perceptronModel(x, w, bAND)
# OR Logic Function
# here w1 = wOR1 = 1,
# w2 = wOR2 = 1, bOR = -0.5
def OR_logicFunction(x):
w = np.array([1, 1])
bOR = -0.5
return perceptronModel(x, w, bOR)
30
Output of XNOR
31
Experiment 5
Aim: Implementing the model fw,b for linear regression with one
variable
Theory:
Model Representation
1. Data Preparation
2. Initialize Parameters
3. Define the Loss Function:
4. Gradient Descent Optimization:
5. Iterate
6. Prediction
32
Code:
import numpy as np
import matplotlib.pyplot as plt
w = 200
b = 100
33
w,b (scalar): model parameters
Returns
f_wb (ndarray (m,)): model prediction
"""
m = x.shape[0]
f_wb = np.zeros(m)
for i in range(m):
f_wb[i] = w * x[i] + b
return f_wb
34
Output:
35
Experiment 6
Theory:
Data Preparation:
Gather the dataset that includes input features and their corresponding
target values.
Split the dataset into training and testing sets.
Initialize Parameters:
Start with small random values or zeros for the weights and biases.
Define the Loss Function:
Calculate how much the loss function would change if you slightly
adjusted the weights and biases. This gives you the direction to update
them.
Update Parameters:
Adjust the weights and biases based on the gradients. Move them in
the direction that reduces the loss.
Iterate:
36
Repeat the gradient calculation and parameter updates for a set
number of iterations or until the changes become very small.
Make Predictions:
Use the final weights and biases to predict outcomes for new input
data.
Code:
import math,copy
x_train = np.array([1.0, 2.0])
y_train = np.array([300.0, 500.0])
def compute_cost(x, y, w, b):
m = x.shape[0]
cost = 0
for i in range(m):
f_wb = w * x[i] + b
cost = cost + (f_wb - y[i]) ** 2
total_cost = 1 / (2 * m) * cost
return total_cost
dj_dw = 0
dj_db = 0
for i in range(m):
f_wb = w * x[i] + b
dj_dw_i = (f_wb - y[i]) * x[i]
dj_db_i = f_wb - y[i]
dj_db += dj_db_i
dj_dw += dj_dw_i
dj_dw = dj_dw / m
dj_db = dj_db / m
37
x, y, w_in, b_in, alpha, num_iters, cost_function,
gradient_function
):
# An array to store cost J and w's at each iteration primarily for
graphing later
J_history = []
p_history = []
b = b_in
w = w_in
for i in range(num_iters):
# Calculate the gradient and update the parameters using
gradient_function
dj_dw, dj_db = gradient_function(x, y, w, b)
if i<100000:
J_history.append(cost_function(x,y,w,b))
p_history.append([w,b])
if i% math.ceil(num_iters / 10) == 0:
print(
f"Iteration {i:4}: Cost {J_history[-1]:0.2e} ",
f"dj_dw: {dj_dw: 0.3e}, dj_db: {dj_db: 0.5e} ")
w_init = 0
b_init = 0
# some gradient descent settings
iterations = 100000
tmp_alpha = 9.0e-2
# run gradient descent
w_final, b_final, J_hist, p_hist = gradient_descent(
x_train,
38
y_train,
w_init,
b_init,
tmp_alpha,
iterations,
compute_cost,
compute_gradient,
)
print(f"(w,b) found by gradient descent:
({w_final:.4f},{b_final:.4f})")
fig,(ax1,ax2)=plt.subplots(1,2,constrained_layout=True, figsize=(12,6))
ax1.plot(J_hist[:100])
ax2.plot(1000 + np.arange(len(J_hist[1000:])), J_hist[1000:])
ax1.set_title("Cost vs. iteration(start)");ax2.set_title("Cost vs.
iteration (end)")
ax1.set_ylabel('Cost')
ax2.set_xlabel("Iteration")
plt.show()
Output:
39
Result: Successfully found optimal sets of weight and bias using
Gradient Descent Algorithm
40
Experiment 7
Theory:
The Knapsack problem is a classic optimization problem that involves
selecting a subset of items, each with a given weight and value, to
maximize the total value while staying within a weight limit. Here's a
concise overview of how to solve it:
Problem Definition
Inputs:
A list of items, each with a weight and value.
A maximum weight capacity of the knapsack.
Goal: Maximize the total value of items in the knapsack without
exceeding its weight capacity.
41
Explore all combinations of items to find the optimal solution.
Inefficient for large datasets due to exponential time complexity.
Code:
import numpy as np
return K[n][max_capacity]
max_capacity = 10
values = [50, 40, 80, 10]
weights = [3, 4, 6, 2]
n = len(values)
print("Maximum value that can be obtained:", knapsack(max_capacity,
weights, values, n))
Output
42
Result: Successfully solved the Knapsack problem
43
Experiment 8
Theory:
Crossover is a genetic algorithm operation where two parent solutions
are selected from the population to create offspring. First, a random
crossover point is chosen along the length of the parent solutions,
indicating where genetic material will be exchanged. In a single-point
crossover, the parents are split at this point, and the first part of one
parent is combined with the second part of the other parent to
generate two new offspring. Multi-point crossover involves selecting
multiple points, allowing segments from each parent to be alternated,
further enhancing genetic diversity in the offspring.
Code:
import random
44
def single_point_crossover(parent1, parent2):
# Ensure parents are of the same length
assert len(parent1) == len(parent2)
# Create offspring
offspring1 = parent1[:crossover_point] + parent2[crossover_point:]
offspring2 = parent2[:crossover_point] + parent1[crossover_point:]
# Example usage
parent1 = "101010"
parent2 = "110011"
offspring1, offspring2 = single_point_crossover(parent1, parent2)
print("Offspring 1:", offspring1)
print("Offspring 2:", offspring2)
# Create offspring
offspring1 = parent1[:point1] + parent2[point1:point2] +
parent1[point2:]
offspring2 = parent2[:point1] + parent1[point1:point2] +
parent2[point2:]
# Example usage
parent1 = "101010"
parent2 = "110011"
offspring1, offspring2 = double_point_crossover(parent1, parent2)
print("Offspring 1:", offspring1)
print("Offspring 2:", offspring2)
45
def multi_point_crossover(parent1, parent2, num_points):
assert len(parent1) == len(parent2)
offspring1 = ''
offspring2 = ''
last_point = 0
for i in range(num_points):
# Take from parent1 for even indices and from parent2 for odd
indices
if i % 2 == 0:
offspring1 += parent1[last_point:points[i]]
offspring2 += parent2[last_point:points[i]]
else:
offspring1 += parent2[last_point:points[i]]
offspring2 += parent1[last_point:points[i]]
# Example usage
parent1 = "101010"
parent2 = "110011"
offspring1, offspring2 = multi_point_crossover(parent1, parent2, 3)
print("Offspring 1:", offspring1)
print("Offspring 2:", offspring2)
46
if random.random() < mutation_rate: # Flip with the given
mutation rate
mutated_chromosome += '1' if gene == '0' else '0'
else:
mutated_chromosome += gene
return mutated_chromosome
# Example usage
chromosome = "101010"
mutated_chromosome = bit_flip_mutation(chromosome)
print("Original Chromosome:", chromosome)
print("Mutated Chromosome:", mutated_chromosome)
def swap_mutation(chromosome):
# Convert string to list for easy swapping
chromosome_list = list(chromosome)
return ''.join(chromosome_list)
# Example usage
chromosome = "abcdef"
mutated_chromosome = swap_mutation(chromosome)
print("Original Chromosome:", chromosome)
print("Mutated Chromosome:", mutated_chromosome)
def scramble_mutation(chromosome):
chromosome_list = list(chromosome)
47
# Place the scrambled genes back
chromosome_list[start:end + 1] = subset
return ''.join(chromosome_list)
# Example usage
chromosome = "abcdef"
mutated_chromosome = scramble_mutation(chromosome)
print("Original Chromosome:", chromosome)
print("Scrambled Chromosome:", mutated_chromosome)
def inversion_mutation(chromosome):
chromosome_list = list(chromosome)
return ''.join(chromosome_list)
# Example usage
chromosome = "abcdef"
mutated_chromosome = inversion_mutation(chromosome)
print("Original Chromosome:", chromosome)
print("Inverted Chromosome:", mutated_chromosome)
48
Output:
49
Experiment 9
Theory:
In the genetic algorithm process is as follows
Step 1. Determine the number of chromosomes, generation, and
mutation rate and crossover rate value
Step 2. Generate chromosome-chromosome number of the population,
and the initialization value of the genes chromosome-chromosome
with a random value
Step 3. Process steps 4-7 until the number of generations is met
Step 4. Evaluation of fitness value of chromosomes by calculating
objective function
Step 5. Chromosomes selection
Step 6. Crossover
Step 7. Mutation Step
8. Solution (Best Chromosomes)
50
Code:
import random
def objective_function(chromosome):
return abs((chromosome[0] + 2 * chromosome[1] + 3 * chromosome[2] +
4 * chromosome[3]) - 30)
def fitness_value(f_obj):
return 1 / (1 + f_obj)
for p in probabilities:
cumulative_sum += p
cumulative_probabilities.append(cumulative_sum)
new_population = []
for _ in range(len(population)):
R = random.random()
51
for i, cp in enumerate(cumulative_probabilities):
if R <= cp:
new_population.append(population[i])
break
return new_population
return new_population
for _ in range(num_mutations):
position = random.randint(0, total_genes - 1)
chromosome_index = position // 4
gene_index = position % 4
population[chromosome_index][gene_index] = random.randint(0,
30)
return population
best_chromosome_overall = None
best_objective_value_overall = float('inf')
52
for generation in range(num_generations):
# Step 4: Evaluation
fitness_values = [fitness_value(objective_function(chrom)) for
chrom in population]
# Step 5: Selection
population = select_chromosomes(population, fitness_values)
# Step 6: Crossover
population = crossover(population, crossover_rate)
# Step 7: Mutation
population = mutate(population, mutation_rate)
53
print("Overall Objective Function Value:",
best_objective_value_overall)
Output:
54
Result: Using genetic algorithm solved the problem of
combination
55