Skip to content

Commit 5aa4073

Browse files
Added AI sources
Assignments written in Python
1 parent e958db2 commit 5aa4073

File tree

5 files changed

+1176
-0
lines changed

5 files changed

+1176
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
10000
2+
0.5
3+
0 0
4+
0 1
5+
1 0
6+
1 1
7+
0 0 0 1
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import numpy
2+
from matplotlib import pyplot
3+
4+
5+
def add_ones(samples):
6+
"""
7+
:param samples: array of input arrays
8+
:return: array of training arrays to which 1 was added at the end for bias
9+
"""
10+
sample_number, inputs = numpy.shape(samples)
11+
ones = numpy.ones((sample_number, 1))
12+
return numpy.hstack((samples, ones))
13+
14+
15+
def create_weights(inputs=2, hidden_layer_neurons=2, outputs=1):
16+
"""
17+
:param inputs: number of input (default 2)
18+
:param hidden_layer_neurons: number of neurons in hidden layer (default 2)
19+
:param outputs: number of output (default 1)
20+
:return: randomly generated weights for hidden layer and output layer
21+
"""
22+
hidden_layer_weights = numpy.random.uniform(0.1, 0.9, (inputs + 1, hidden_layer_neurons))
23+
output_layer_weights = numpy.random.uniform(0.1, 0.9, (hidden_layer_neurons + 1, outputs))
24+
return {"hidden": hidden_layer_weights, "output": output_layer_weights}
25+
26+
27+
def sigmoid(inputs):
28+
"""
29+
:param inputs: array of arrays
30+
:return: sigmoid value of each input
31+
"""
32+
return 1 / (1 + numpy.exp(-inputs))
33+
34+
35+
def derivative(inputs):
36+
"""
37+
:param inputs: array of arrays
38+
:return: sigmoid derivative value of each input
39+
"""
40+
return inputs * (1 - inputs)
41+
42+
43+
def mean_squared_error(errors, samples=4, outputs=1):
44+
"""
45+
:param errors: array of differences between expected output and computed output
46+
:param samples: number of samples (default 4)
47+
:param outputs: number of output values (default 1)
48+
:return: mean squared error value of each error
49+
"""
50+
return numpy.sum(numpy.power(errors, 2)) / (samples * outputs)
51+
52+
53+
def train(samples, labels, epochs=10000, learning_rate=0.5, minimum_loss=0.001, sample_number=4,
54+
input_number=2, hidden_layer_neurons=2, output_number=1):
55+
"""
56+
:param samples: array of input arrays
57+
:param labels: expected output array
58+
:param epochs: number of iterations (default 10000)
59+
:param learning_rate: step size (default 0.5)
60+
:param minimum_loss: minimum mean squared error value (default 0.001)
61+
:param sample_number: number of samples
62+
:param input_number: number of inputs (default 2)
63+
:param hidden_layer_neurons: number of neurons in hidden layer (default 2)
64+
:param output_number: number of outputs (default 1)
65+
:return: mean squared error value for each iteration and computed output values
66+
"""
67+
losses = list()
68+
outputs = None
69+
weights = create_weights(input_number, hidden_layer_neurons, output_number)
70+
for epoch in range(epochs):
71+
"""
72+
Computes outputs and mean squared error (feed forward).
73+
"""
74+
hidden_outputs = add_ones(sigmoid(numpy.dot(samples, weights["hidden"])))
75+
outputs = sigmoid(numpy.dot(hidden_outputs, weights["output"]))
76+
errors = labels - outputs
77+
losses.append(mean_squared_error(errors, sample_number, output_number))
78+
"""
79+
Computes gradients and updates weights (backpropagation).
80+
"""
81+
output_errors = derivative(outputs) * errors
82+
weights["output"] += numpy.transpose(numpy.sum(learning_rate * hidden_outputs * output_errors,
83+
axis=0, keepdims=True))
84+
hidden_errors = derivative(hidden_outputs[:, :-1]) * output_errors * numpy.transpose(weights["output"][:-1, :])
85+
for neuron in range(hidden_layer_neurons):
86+
weights["hidden"][:, neuron:neuron + 1] += numpy.transpose(numpy.sum(learning_rate * samples *
87+
hidden_errors[:, neuron:neuron + 1],
88+
axis=0, keepdims=True))
89+
if losses[-1] < minimum_loss:
90+
break
91+
return losses, outputs
92+
93+
94+
def show_performance(losses):
95+
"""
96+
Plots loss versus epoch graph.
97+
:param losses: array of loss values
98+
"""
99+
pyplot.figure()
100+
pyplot.plot(losses)
101+
pyplot.xlabel("Epochs")
102+
pyplot.ylabel("Loss")
103+
pyplot.show()
104+
105+
106+
def main():
107+
"""
108+
Reads information from file.
109+
Shows performance and result of algorithm.
110+
"""
111+
with open("data.txt") as file:
112+
data = file.read()
113+
data = data.split('\n')
114+
epochs = int(data[0])
115+
learning_rate = float(data[1])
116+
samples = add_ones(numpy.array([numpy.array(list(map(int, line.split()))) for line in data[2:6]]))
117+
labels = numpy.array([numpy.array([int(label)]) for label in data[6].split()])
118+
losses, outputs = train(samples, labels, epochs, learning_rate)
119+
show_performance(losses)
120+
print(str(numpy.transpose(outputs)).replace('[', '').replace(']', ''))
121+
122+
123+
if __name__ == '__main__':
124+
main()
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
from collections import deque
2+
3+
4+
def satisfies_constraint(start_value, end_values):
5+
"""
6+
:param start_value: color of start node
7+
:param end_values: color list of end node
8+
:return: True if end node has another color, False otherwise
9+
"""
10+
for end_value in end_values:
11+
if start_value != end_value:
12+
return True
13+
return False
14+
15+
16+
def remove_inconsistent_values(arc, domain):
17+
"""
18+
:param arc: current arc
19+
:param domain: list of color lists for each node
20+
:return: True if at least one color was removed from color list of start node, False otherwise
21+
"""
22+
start, end = arc
23+
removed = False
24+
for value in domain[start]:
25+
if not satisfies_constraint(value, domain[end]):
26+
domain[start].remove(value)
27+
removed = True
28+
return removed
29+
30+
31+
def get_entering_arcs(end_node, graph):
32+
"""
33+
:param end_node: start node of current arc
34+
:param graph: list of neighbor lists for each node
35+
:return: list of arcs that enter in specified node
36+
"""
37+
next_list = []
38+
for start_node in graph:
39+
if start_node == end_node:
40+
continue
41+
for neighbor in graph.get(start_node):
42+
if neighbor == end_node:
43+
next_list += [(start_node, end_node)]
44+
return next_list
45+
46+
47+
def is_inconsistent(arc, domain):
48+
"""
49+
:param arc: current arc
50+
:param domain: color lists
51+
:return: True if start node or end node has no color, False otherwise
52+
"""
53+
start, end = arc
54+
if len(domain[start]) == 0 or len(domain[end]) == 0:
55+
return True
56+
return False
57+
58+
59+
def arc_consistency(graph, domain):
60+
"""
61+
:param graph: list of neighbor lists for each node
62+
:param domain: list of color lists for each node
63+
:return: (True, graph coloring) if exists, (False, first inconsistent arc) otherwise
64+
"""
65+
queue = deque([(start, end) for start in graph for end in graph.get(start)])
66+
while len(queue):
67+
arc = queue.popleft()
68+
if remove_inconsistent_values(arc, domain):
69+
queue += get_entering_arcs(arc[0], graph)
70+
if is_inconsistent(arc, domain):
71+
return False, arc
72+
return True, domain
73+
74+
75+
def first_example():
76+
"""
77+
Applies algorithm on valid graph.
78+
:return: (True, graph coloring) if exists, (False, first inconsistent arc) otherwise
79+
"""
80+
graph = {
81+
"WA": ["SA", "NT"],
82+
"SA": ["WA", "NT"],
83+
"NT": ["WA", "SA"]
84+
}
85+
domain = {
86+
"WA": ["red", "green", "blue"],
87+
"SA": ["red", "green"],
88+
"NT": ["green"]
89+
}
90+
return arc_consistency(graph, domain)
91+
92+
93+
def second_example():
94+
"""
95+
Applies algorithm on invalid graph.
96+
:return: (True, graph coloring) if exists, (False, first inconsistent arc) otherwise
97+
"""
98+
graph = {
99+
"T": ["V"],
100+
"WA": ["NT", "SA"],
101+
"NT": ["WA", "Q", "SA"],
102+
"SA": ["WA", "NT", "Q", "NSW", "V"],
103+
"Q": ["NT", "SA", "NSW"],
104+
"NSW": ["Q", "SA", "V"],
105+
"V": ["SA", "NSW", "T"]
106+
}
107+
domain = {
108+
"WA": ["red"],
109+
"NT": ["red", "blue", "green"],
110+
"SA": ["red", "blue", "green"],
111+
"Q": ["green"],
112+
"NSW": ["red", "blue", "green"],
113+
"V": ["red", "blue", "green"],
114+
"T": ["red", "blue", "green"]
115+
}
116+
return arc_consistency(graph, domain)
117+
118+
119+
def test(result):
120+
"""
121+
Prints the result.
122+
:param result: (True, graph coloring) if exists, (False, first inconsistent arc) otherwise
123+
"""
124+
if result[0]:
125+
print("The coloring of the map should be: {}.".format(result[1]))
126+
else:
127+
print("Failed to remove inconsistent values, the first inconsistency found is: {}.".format(result[1]))
128+
129+
130+
def main():
131+
"""
132+
Exemplifies functionality of program.
133+
"""
134+
test(first_example())
135+
test(second_example())
136+
137+
138+
if __name__ == '__main__':
139+
main()

0 commit comments

Comments
 (0)