Simple Mutation with a Probability - python

As per the section of code below, I am trying to implement an automatic and random mutation process.
data = [0,1,0,0,0,0,0,1,0,0,1,1,0,0,1]
data[random.randint(0,len(data)-1)]=random.randrange(0,1)
print(data)
The code is an adaptation of some other posts I have found, although it is randomly mutating a value every time with either a 0 or 1. I require this to occur with only a certain probability (such as a 0.05 chance of mutation) rather than always being guaranteed.
Additionally, often a 0 is being replaced with a 0 and therefore there is no change to the output, so I would like to limit it in a way that a 0 will only mutate to a 1 and a 1 mutates to a 0.
I would really appreciate the assistance in resolving these two issues.

Resume
mutate any value with a choosen probability
randomly choose the position
when the position is choosen, switch between 0 and 1
def mutate(data, proba=0.05):
if random.random() < proba:
data[random.randrange(len(data))] ^= 1
if __name__ == '__main__':
data = [0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1]
for i in range(10):
mutate(data)
print(data)

import random
def changeData(data):
seed = random.randint(0,1000)
# probability of 0.05 (50 / 1000)
if seed <= 50:
indexToChange = random.randint(0,len(data)-1)
# change 0 with 1 and viceversa
data[indexToChange] = 1 if data[indexToChange] == 0 else 0
if __name__== '__main__':
data = [0,1,0,0,0,0,0,1,0,0,1,1,0,0,1]
for i in range(0,100):
changeData(data)
print(data)

You can do as following:
For each element in data, mutate it (1 - val) only if a random value generated by random() function is less than the defined mutation probability.
For example:
import random
mutation_prob = 0.05
data = [0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1]
mutated_data = [1 - x if random.random() < mutation_prob else x for x in data]
If the mutation should be decided regarding the data as a whole, you can do:
mutation_prob = 0.05
data = [0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1]
do_mutation = random.random() < mutation_prob
mutated_data = [1 - x if do_mutation else x for x in data]

Related

How to hide Value in array for Battleship game?

I writing a Battleship game, however I'm not sure on how to change the 1 in the first players grid to a 0, so that the player can not see where the ship is.
import random
# formatt to access certain grid point print (grid_1[1][2])
grid_1 = [[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]]
row_random = random.randint(0,3)
column_random = random.randint(0,3)
ship_1 = grid_1[row_random][column_random] = 1
# creates a random spot in the grid where the ship will be
def Player_1():
for i in grid_1:
print (i)
#loops through grid so the output is in row and column form
x = int(input("Enter row:"))
y = int(input("Enter column:"))
co_ordinates_1 = (grid_1[x][y])
# user guses where the ship will be
if co_ordinates_1 == 1:
print("BATTLESHIP HIT")
elif co_ordinates_1 != 1:
print("You missed!")
# shows the user if they hit the target or not
Player_1()
You need to check if a value is equal to 1 (ship). Here is the code below
for i in grid_1:
row = i.copy()
for j in range(0, 4):
if row[j] == 1:
row[j] = 0
print(row)
This code loops through each item and checks if it equal to 1. If it is, then the value is set to 0. This should print out
[0, 0, 0, 0]
[0, 0, 0, 0]
[0, 0, 0, 0]
[0, 0, 0, 0]

How to solve partial Knight's Tour with special constraints

Knight's tour problem described in the image here, with diagram.
A knight was initially located in a square labeled 1. It then proceeded to make a
series of moves, never re-visiting a square, and labeled the visited squares in
order. When the knight was finished, the labeled squares in each region of connected
squares had the same sum.
A short while later, many of the labels were erased. The remaining labels can be seen
above.
Complete the grid by re-entering the missing labels. The answer to this puzzle is
the sum of the squares of the largest label in each row of the completed grid, as in
the example.
[1]: E.g. the 14 and 33 are in different regions.
The picture explains it a lot more clearly, but in summary a Knight has gone around a 10 x 10 grid. The picture shows a 10 x 10 board that shows some positions in has been in, and at what point of its journey. You do not know which position the Knight started in, or how many movements it made.
The coloured groups on the board need to all sum to the same amount.
I’ve built a python solver, but it runs for ages - uses recursion. I’ve noted that the maximum sum of a group is 197, based on there being 100 squares and the smallest group is 2 adjacent squares.
My code at this link: https://pastebin.com/UMQn1HZa
import sys, numpy as np
fixedLocationsArray = [[ 12, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 5, 0, 23, 0],
[ 0, 0, 0, 0, 0, 0, 8, 0, 0, 0],
[ 0, 0, 0, 14, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 2, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 20, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 33, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 28]]
groupsArray = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0,10, 0],
[0, 0, 0, 1, 0, 0, 0, 0,10, 0],
[0, 0, 1, 1, 1, 1, 9,10,10,10],
[2, 0, 1, 0, 0,11, 9, 9, 9, 9],
[2, 0, 0, 0,11,11,11,15,15, 9],
[2, 4, 4,14,11,12,12,15,15, 8],
[2, 3, 4,14,14,13,13,13,15, 8],
[2, 3, 5,14,16,16,16, 7, 7, 8],
[3, 3, 5, 6, 6, 6, 6, 6, 7, 8]]
'''
Solver
- Noted that the maximum sum of a group is 197 since the group of only 2 can have the 100 filled and then 97 on return
'''
class KnightsTour:
def __init__(self, width, height, fixedLocations, groupsArray):
self.w = width
self.h = height
self.fixedLocationsArray = fixedLocations
self.groupsArray = groupsArray
self.npfixedLocationsArray = np.array(fixedLocations)
self.npgroupsArray = np.array(groupsArray)
self.board = [] # Contains the solution
self.generate_board()
def generate_board(self):
"""
Creates a nested list to represent the game board
"""
for i in range(self.h):
self.board.append([0]*self.w)
def print_board(self): # Prints out the final board solution
print(" ")
print("------")
for elem in self.board:
print(elem)
print("------")
print(" ")
def generate_legal_moves(self, cur_pos, n):
"""
Generates a list of legal moves for the knight to take next
"""
possible_pos = []
move_offsets = [(1, 2), (1, -2), (-1, 2), (-1, -2),
(2, 1), (2, -1), (-2, 1), (-2, -1)]
locationOfNumberInFixed = [(ix,iy) for ix, row in enumerate(self.fixedLocationsArray) for iy, i in enumerate(row) if i == n+1]
groupsizeIsNotExcessive = self.groupsNotExcessiveSize(self.board, self.groupsArray)
for move in move_offsets:
new_x = cur_pos[0] + move[0]
new_y = cur_pos[1] + move[1]
new_pos = (new_x, new_y)
if groupsizeIsNotExcessive:
if locationOfNumberInFixed:
print(f"This number {n+1} exists in the fixed grid at {locationOfNumberInFixed[0]}")
if locationOfNumberInFixed[0] == new_pos:
print(f"Next position is {new_pos} and matches location in fixed")
possible_pos.append((new_x, new_y))
else:
continue
elif not locationOfNumberInFixed: # if the current index of move is not in table, then evaluate if it is a legal move
if (new_x >= self.h): # if it is out of height of the board, continue, don't app onto the list of possible moves
continue
elif (new_x < 0):
continue
elif (new_y >= self.w):
continue
elif (new_y < 0):
continue
else:
possible_pos.append((new_x, new_y))
else:
continue
print(f"The legal moves for index {n} are {possible_pos}")
print(f"The current board looks like:")
self.print_board()
return possible_pos
def sort_lonely_neighbors(self, to_visit, n):
"""
It is more efficient to visit the lonely neighbors first,
since these are at the edges of the chessboard and cannot
be reached easily if done later in the traversal
"""
neighbor_list = self.generate_legal_moves(to_visit, n)
empty_neighbours = []
for neighbor in neighbor_list:
np_value = self.board[neighbor[0]][neighbor[1]]
if np_value == 0:
empty_neighbours.append(neighbor)
scores = []
for empty in empty_neighbours:
score = [empty, 0]
moves = self.generate_legal_moves(empty, n)
for m in moves:
if self.board[m[0]][m[1]] == 0:
score[1] += 1
scores.append(score)
scores_sort = sorted(scores, key = lambda s: s[1])
sorted_neighbours = [s[0] for s in scores_sort]
return sorted_neighbours
def groupby_perID_and_sum(self, board, groups):
# Convert into numpy arrays
npboard = np.array(board)
npgroups = np.array(groups)
# Get argsort indices, to be used to sort a and b in the next steps
board_flattened = npboard.ravel()
groups_flattened = npgroups.ravel()
sidx = groups_flattened.argsort(kind='mergesort')
board_sorted = board_flattened[sidx]
groups_sorted = groups_flattened[sidx]
# Get the group limit indices (start, stop of groups)
cut_idx = np.flatnonzero(np.r_[True,groups_sorted[1:] != groups_sorted[:-1],True])
# Create cut indices for all unique IDs in b
n = groups_sorted[-1]+2
cut_idxe = np.full(n, cut_idx[-1], dtype=int)
insert_idx = groups_sorted[cut_idx[:-1]]
cut_idxe[insert_idx] = cut_idx[:-1]
cut_idxe = np.minimum.accumulate(cut_idxe[::-1])[::-1]
# Split input array with those start, stop ones
arrayGroups = [board_sorted[i:j] for i,j in zip(cut_idxe[:-1],cut_idxe[1:])]
arraySum = [np.sum(a) for a in arrayGroups]
sumsInListSame = arraySum.count(arraySum[0]) == len(arraySum)
return sumsInListSame
def groupsNotExcessiveSize(self, board, groups):
# Convert into numpy arrays
npboard = np.array(board)
npgroups = np.array(groups)
# Get argsort indices, to be used to sort a and b in the next steps
board_flattened = npboard.ravel()
groups_flattened = npgroups.ravel()
sidx = groups_flattened.argsort(kind='mergesort')
board_sorted = board_flattened[sidx]
groups_sorted = groups_flattened[sidx]
# Get the group limit indices (start, stop of groups)
cut_idx = np.flatnonzero(np.r_[True,groups_sorted[1:] != groups_sorted[:-1],True])
# Create cut indices for all unique IDs in b
n = groups_sorted[-1]+2
cut_idxe = np.full(n, cut_idx[-1], dtype=int)
insert_idx = groups_sorted[cut_idx[:-1]]
cut_idxe[insert_idx] = cut_idx[:-1]
cut_idxe = np.minimum.accumulate(cut_idxe[::-1])[::-1]
# Split input array with those start, stop ones
arrayGroups = [board_sorted[i:j] for i,j in zip(cut_idxe[:-1],cut_idxe[1:])]
arraySum = [np.sum(a) for a in arrayGroups]
print(arraySum)
# Check if either groups aren't too large
groupSizeNotExcessive = all(sum <= 197 for sum in arraySum)
return groupSizeNotExcessive
def tour(self, n, path, to_visit):
"""
Recursive definition of knights tour. Inputs are as follows:
n = current depth of search tree
path = current path taken
to_visit = node to visit, i.e. the coordinate
"""
self.board[to_visit[0]][to_visit[1]] = n # This writes the number on the grid
path.append(to_visit) #append the newest vertex to the current point
print(f"Added {n}")
print(f"For {n+1} visiting: ", to_visit)
if self.groupby_perID_and_sum(self.board, self.npgroupsArray): #if all areas sum
self.print_board()
print(path)
print("Done! All areas sum equal")
sys.exit(1)
else:
sorted_neighbours = self.sort_lonely_neighbors(to_visit, n)
for neighbor in sorted_neighbours:
self.tour(n+1, path, neighbor)
#If we exit this loop, all neighbours failed so we reset
self.board[to_visit[0]][to_visit[1]] = 0
try:
path.pop()
print("Going back to: ", path[-1])
except IndexError:
print("No path found")
sys.exit(1)
if __name__ == '__main__':
#Define the size of grid. We are currently solving for an 8x8 grid
kt0 = KnightsTour(10, 10, fixedLocationsArray, groupsArray)
kt0.tour(1, [], (3, 0))
# kt0.tour(1, [], (7, 0))
# kt0.tour(1, [], (7,2))
# kt0.tour(1, [], (6,3))
# kt0.tour(1, [], (4,3))
# kt0.tour(1, [], (3,2))
# startingPositions = [(3, 0), (7, 0), (7,2), (6,3), (4,3), (3,2)]
kt0.print_board()
Here are some observations that you could include to be able to stop more early in your backtracking.
First of all remember that for n steps the total sum in all areas can be computed with the formula n(n+1)/2. This number has to be divisible evenly into the groups i.e. it has to be divisible by 17 which is the amount of groups.
Furthermore if we look at the 12 we can conclude that the 11 and 13 must have been in the same area so we get a lower bound on the number for each area as 2+5+8+11+12+13=51.
And lastly we have groups of size two so the largest two step numbers must make up the total sum for one group.
Using those conditions we can calculate the remaining possible amount of steps with
# the total sum is divisible by 17:
# n*(n+1)/2 % 17 == 0
# the sum for each group is at least the predictable sum for
# the biggest given group 2+5+8+11+12+13=51:
# n*(n+1)/(2*17) >= 51
# since there are groups of two elements the sum of the biggest
# two numbers must be as least as big as the sum for each group
# n+n-1 >= n*(n+1)/(2*17)
[n for n in range(101) if n*(n+1)/2 % 17 == 0 and n*(n+1)/(2*17) >= 51 and n+n-1 >= n*(n+1)/(2*17)]
giving us
[50,51].
So the knight must have taken either 50 or 51 steps and the sum for each area must be either 75 or 78.

compare two arrays to make an accuracy of KNN prediction

I have two arrays from which I have to find the accuracy of my prediction.
predictions = [1, 0, 0, 1, 1, 1, 0, 1, 1, 0]
y_test = [1, 0, 0, 1, 0, 1, 0, 1, 1, 1]
so in this case, the accuracy is = (8/10)*100 = 80%
I have written a method to do this task. Here is my code, but I dont get the accuracy of 80% in this case.
def getAccuracy(y_test, predictions):
correct = 0
for x in range(len(y_test)):
if y_test[x] is predictions[x]:
correct += 1
return (correct/len(y_test)) * 100.0
Thanks for helping me.
You're code should work, if the numbers in the arrays are in a specific range that are not recreated by the python interpreter. This is because you used is which is an identity check and not an equality check. So, you are checking memory addresses, which are only equal for a specific range of numbers. So, use == instead and it will always work.
For a more Pythonic solution you can also take a look at list comprehensions:
assert len(predictions) == len(y_test), "Unequal arrays"
identity = sum([p == y for p, y in zip(predictions, y_test)]) / len(predictions) * 100
if you want to take 80.0 as result for your example, It's doing that.
Your code gives 80.0 as you wanted, however you should use == instead of is, see the reason.
def getAccuracy(y_test, predictions):
n = len(y_test)
correct = 0
for x in range(n):
if y_test[x] == predictions[x]:
correct += 1
return (correct/n) * 100.0
predictions = [1, 0, 0, 1, 1, 1, 0, 1, 1, 0]
y_test = [1, 0, 0, 1, 0, 1, 0, 1, 1, 1]
print(getAccuracy(y_test, predictions))
80.0
Here's an implementation using Numpy:
import numpy as np
n = len(y_test)
100*np.sum(np.isclose(predictions, y_test))/n
or if you convert your lists to numpy arrays, then
100*np.sum(predictions == y_test)/n

Python3 list index Error

Recently, I have started learning Python. I'd like to make a cosine distribution simulation.
"Index Error:list index out of range" is shown on my display. but I think I define a length of list, and I write 0 < key < len(thickness). why the Error is shown on my display??
import math
def main():
height = 20
thickness = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
with open('output/output.csv', 'w', encoding = 'utf-8' ) as f:
f.write('x,thikcness\n')
for t in range(90):
deg = t
rad = math.radians(deg)
x = height * math.tan(rad)
key = round(x)
if 0 < key <= len(thickness):
thickness[key] += 1
for t in len(thickness):
f.write(str(thickness[t]) + '\n')
if __name__ == "__main__":
main()
It should be if 0 <= key < len(thickness):. This is because array indices go from 0 to len(thickness)-1, not 1 to len(thickness).

Multidimensional Array sets multiple rows/columns

So I am having a strange problem in python. I am using the code below to create a plot of places where the object has been. Here is my code:
def GoForward(self, duration):
if (self.TowardsX - self.X == 0):
Myro.robot.motors(self.Speed, self.Speed)
Myro.wait(abs(duration))
Myro.robot.stop()
#get the amount of points forward
divisible = (int) (duration / self.Scale)
#add them to the direction
self.TowardsY += divisible
tempY = self.Y
for y in xrange(self.Y, divisible + tempY):
if (y % self.Scale == 0):
self.Plot[(int) (self.X)][y] = 1
return
#calc slope
slope = (self.TowardsY - self.Y) / (self.TowardsX - self.X)
tempX = self.X
tempY = self.Y
#go forward
#get the amount of points forward
divisible = duration / self.Scale
#add them to the direction
self.TowardsX += divisible
self.TowardsY += divisible
Xs = []
Ys = []
for x in xrange(self.X, tempX + divisible):
#find out if it is a plottable point
if (((slope * (x - self.X)) + self.Y) % self.Scale == 0.0):
Xs.append(x)
Ys.append((int)((slope * (x - self.X)) + self.Y))
#Plot the points
for i in xrange(0, len(Xs)):
for j in xrange(0, len(Ys)):
if (self.Plot[Xs[i]][Ys[j]] == 0):
self.Plot[Xs[i]][Ys[j]] = 1
self.X += divisible
self.Y += divisible
But, when I call GoForward(2) it fills five columns with ones, instead of the few points. Example:
[[0,0,0,0,1,1,0,0,0,0]
[0,0,0,0,1,1,0,0,0,0]
[0,0,0,0,1,1,0,0,0,0]
[0,0,0,0,1,1,0,0,0,0]
[0,0,0,0,1,1,0,0,0,0]
[0,0,0,0,1,1,0,0,0,0]
[0,0,0,0,1,1,0,0,0,0]
[0,0,0,0,1,1,0,0,0,0]
[0,0,0,0,1,1,0,0,0,0]
[0,0,0,0,1,1,0,0,0,0]]
Based off the parameter given to GoForward(n) it creates that many columns full of 0s... Why is this behavior happening? My code should not produce this effect, but I am inexperienced with python so is that why this is happening? Thanks in advance
EDIT
So I have changed the code for plotting the points to
for i in xrange(0, len(Xs)):
if (self.Plot[Xs[i]][Ys[i]] == 0):
self.Plot[Xs[i]][Ys[i]] = 1
Which will have the correct values, however it is still producing this strange behavior, and the problem lies in this code here.
EDIT 2
When I use the code:
self.Plot[3][3] = 1
It still produces an array of:
[[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]]
So to produce that grid you are showing you are printing self.Plot? And your saying this grid gets initialized to 0? What exactly is self.Plot? A list of lists and that's it? When you print self.Plot before running that loop does it print what you expect (which I assume should be all zeros)?
So if Xs and Ys are the points that should be 1 you could simplify the code to using one list of plottable points:
plottable_points = []
# for loop
plottable_points.append( (x, int((slope * (x - self.X)) + self.Y)) )
for x, y in plottable_points:
self.Plot[x][y] = 1
I'm not sure exactly how self.Plot is being initialized or used, but if you print things before and after each step you should be able to figure out where your logic is wrong.
Edit 1:
Extra little python tip:
for x, y in zip(Xs, Ys):
self.Plot[x][y] = 1
Does the same thing as my first code example does, but with your variables.
Edit 2:
The problem is actually with how you are initializing self.Plot. When you repeat a list like that, your outer list becomes a list of pointers...all pointing to the same object (in this case a list). So when you say self.Plot[3][3] = 1, you are actually setting that column in each row. Try initializing self.Plot with something like this (there may be a better way to do this, but I'm tired):
self.Plot = []
for col in range(height * multiplyBy):
self.Plot.append([0] * width * multiplyBy)
# or:
self.Plot = [ [0] * width * multiply for col in range(height * multiplyBy) ]
I would say that you should do a simple import (from future import division) before doing any more modifications. To me it seems the problem is the division. In Python 2.7 it returns you an integer.
Take a look at this:
>>> 4/3
1
>>> 4//3
1
But if you import the new division functionality...
>>> from __future__ import division
>>> 4/3
1.3333333333333333

Categories