Trying to construct a greedy algorithm with python - python

So i'm trying to create a greedy algorithm for a knapsack problem. The txt file below is the knap20.txt file. The first line gives the number of items, in this case 20. The last line gives the capacity of the knapsack, in this case 524. The remaining lines give the index, value and weight of each item.
My function is to ideally return the solution in a list and the value of the weights
From what I can tell by my results, my program is working correctly. Is it working as you would expect, and how can i improve it?
txt file
20
1 91 29
2 60 65
3 61 71
4 9 60
5 79 45
6 46 71
7 19 22
8 57 97
9 8 6
10 84 91
11 20 57
12 72 60
13 32 49
14 31 89
15 28 2
16 81 30
17 55 90
18 43 25
19 100 82
20 27 19
524
python file
import os
import matplotlib.pyplot as plt
def get_optimal_value(capacity, weights, values):
value = 0.
numItems = len(values)
valuePerWeight = sorted([[values[i] / weights[i], weights[i]] for i in range(numItems)], reverse=True)
while capacity > 0 and numItems > 0:
maxi = 0
idx = None
for i in range(numItems):
if valuePerWeight[i][1] > 0 and maxi < valuePerWeight[i][0]:
maxi = valuePerWeight[i][0]
idx = i
if idx is None:
return 0.
if valuePerWeight[idx][1] <= capacity:
value += valuePerWeight[idx][0]*valuePerWeight[idx][1]
capacity -= valuePerWeight[idx][1]
else:
if valuePerWeight[idx][1] > 0:
value += (capacity / valuePerWeight[idx][1]) * valuePerWeight[idx][1] * valuePerWeight[idx][0]
return values, value
valuePerWeight.pop(idx)
numItems -= 1
return value
def read_kfile(fname):
print('file started')
with open(fname) as kfile:
print('fname found', fname)
lines = kfile.readlines() # reads the whole file
n = int(lines[0])
c = int(lines[n+1])
vs = []
ws = []
lines = lines[1:n+1] # Removes the first and last line
for l in lines:
numbers = l.split() # Converts the string into a list
vs.append(int(numbers[1])) # Appends value, need to convert to int
ws.append(int(numbers[2])) # Appends weigth, need to convert to int
return n, c, vs, ws
dir_path = os.path.dirname(os.path.realpath(__file__)) # Get the directory where the file is located
os.chdir(dir_path) # Change the working directory so we can read the file
knapfile = 'knap20.txt'
nitems, capacity, values, weights = read_kfile(knapfile)
val1,val2 = get_optimal_value(capacity, weights, values)
print ('values',val1)
print('value',val2)
result
values [91, 60, 61, 9, 79, 46, 19, 57, 8, 84, 20, 72, 32, 31, 28, 81, 55, 43, 100, 27]
value 733.2394366197183

Related

Converting input with XOR 15

I'm trying to cipher input with three different type or ciphers, and I am completely stuck on XOR 15.
import string
def caesar(text, shift, alphabets):
def shift_alphabet(alphabet):
return alphabet[shift:] + alphabet[:shift]
shifted_alphabets = tuple(map(shift_alphabet, alphabets))
final_alphabet = ''.join(alphabets)
final_shifted_alphabet = ''.join(shifted_alphabets)
table = str.maketrans(final_alphabet, final_shifted_alphabet)
return text.translate(table)
plaintext = input("Enter a sentence to encode: >")
shifted = int(input("Shift by how much? >"))
print("Caesar results:")
print("Original: ", plaintext)
print("Cipher: ",(caesar(plaintext, shifted, [string.printable])))
def rot13(text):
return ''.join([chr((ord(letter) - 97 + 13) % 26 + 97)
if 97 <= ord(letter) <= 122
else letter
for letter in text.lower()])
print("Rot13 results: ")
print("Original: ", plaintext)
print("Rot13:",(rot13(plaintext)))
def xor(plaintext,number):
L = list(plaintext)
L2 = [ord(value) ^ number for value in L]
return L2
i = plaintext.encode('utf-8')
xor_number = 00;
results = xor(plaintext,xor_number)
print ("XOR 15 results:")
print ("Original hex:", i.hex(' '))
print ("XOR 15 hex:", results)
When I get my results back after the user input I am only getting the regular ascii value instead of an XOR 15 of the original hex. Where am I going wrong?
Current Results:
XOR 15 results:
Original hex: 41 42 44 20 78 79 7a 20 31 32 33 21
XOR 15 hex: [65, 66, 68, 32, 120, 121, 122, 32, 49, 50, 51, 33]
Expected Results:
XOR 15 results:
Original hex: 41 42 44 20 78 79 7a 20 31 32 33 21
XOR 15 hex: [be, bd, bc, df, 87, 86, 85, df, ce, cd, cc, de]

How to print prime numbers in a tabular format

my goal is to print prime numbers in a tabular format, instead of printing one value each line. so far all my attempts have ended in either lines, or misprinted tables.
start = int(input("Start number: "))
end = int(input("End number: "))
if start < 0 or end < 0:
print("Start and End must be positive.")
start = int(input("Start number: "))
end = int(input("End number: "))
if end < start:
print("End must be greater than Start number: ")
start = int(input("Start number: "))
end = int(input("End number: "))
prime = True
for num in range(start,end+1):
if num > 1:
for i in range(2,num):
if num % i == 0:
break
else:
num = print(num)
the one i have here can only print it line by line
#start number: 1
#end number: 100
# 2 3 5 7 11 13 17 19 23 29
#31 37 41 43 47 53 59 61 67 71
#73 79 83 89 97
This can be done with str.rjust or its friends
>>> "2".rjust(3)
' 2'
>>>
first we gather the numbers we want to print and calculate how many characters it take the biggest of them and add one to that value, that result is the one we will use for the rjust
>>> nums=[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
>>> j = len(str(max(nums))) + 1
>>>
now we pick how many we want to print per line
>>> linesize = 10
>>>
and finally we make use of print keyword-only arguments end to control when to print in the same line or not and enumerate to control how many we have already printed
>>> for i,p in enumerate(nums,1):
print( str(p).rjust(j), end="" )
if i%linesize==0:
print() #to go to the next line
2 3 5 7 11 13 17 19 23 29
31 37 41 43 47 53 59 61 67 71
73 79 83 89 97
>>>
You could use str.format and implement a reusable solution using a generator:
from math import floor
def tabular(records, line_width=42, sep_space=3):
width = len(str(max(records))) + sep_space
columns = floor(line_width/width)
for i in range(0, len(records), columns):
row_records = records[i:i+columns]
row_format = ("{:>" + str(width) + "}") * len(row_records)
yield row_format.format(*row_records)
# test data / prime numbers
numbers = [
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83,
89, 97
]
for row in tabular(numbers):
print(row)
# 2 3 5 7 11 13 17 19
# 23 29 31 37 41 43 47 53
# 59 61 67 71 73 79 83 89
# 97
Example with some other numbers:
for row in tabular(list(range(0, 1600, 50)), 79, 2):
print(row)
# 0 50 100 150 200 250 300 350 400 450 500 550 600
# 650 700 750 800 850 900 950 1000 1050 1100 1150 1200 1250
# 1300 1350 1400 1450 1500 1550
Example with str.format but without using a generator:
# test data / prime numbers
numbers = [
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83,
89, 97
]
width = len(str(max(numbers))) + 3
for i in range(0, len(numbers), 10):
row_records = numbers[i:i+10]
row_format = ("{:>" + width + "}") * len(row_records)
print(row_format.format(*row_records))
# 2 3 5 7 11 13 17 19 23 29
# 31 37 41 43 47 53 59 61 67 71
# 73 79 83 89 97

Python looping back in a range when stop is exceed a value?

I have a range in like below. What I am trying to do is to loop back to 0 if the range stop is greater that a certain value (this example 96). I can simply loop through the range as I did below, but is there a better way to do perform this in Python's range?
my_range = range(90, 100)
tmp_list=[]
for i in range(90, 100):
if i >= 96:
tmp_list.append(i-96)
else:
tmp_list.append(i)
print(tmp_list)
[90, 91, 92, 93, 94, 95, 0, 1, 2, 3]
Checkout itertools.cycle:
from itertools import cycle
def clipped_cycle(start, end):
c = cycle(range(0, 96))
# Discard till start
for _ in range(start):
next(c)
return c
c = clipped_cycle(90, 96)
for i in c:
print(i)
what you get is an infinite output stream that cycles along.
90
91
92
93
94
95
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.
.
.
to get a limited number of outputs:
n = 7
for _ in range(n):
print(next(c))
gives
90
91
92
93
94
95
0
First, I did not understand why you have defined my_range = range(90, 100), if you are never going to use it.
You can use 'mod' in these cases.
Try this, short and effective
xlist = [i%96 for i in range(90,100)]

how to fix "Sliced assignment is only supported for variables for tensors"

I am trying to define my own custom layer in keras. In the call function, where the logic of the class lies, I am dealing with the tensor object.
After finding the maximum value from a shredded slice of a tensor object, I want to assign it to a different tensor, but I am getting ERROR
"Sliced assignment is only supported for variables"
I have tried Sess.eval() in the call function of a class which does not solve the problem
mid_arr = x[i:spliti,j:splitj] #shredded slice
num = tf.reduce_max(mid_arr) #max vlaue from shred slice
res_arr = res_arr.assign( tf.where (res_arr[m][n],num, res_arr) ) #assign it
Specifying the solution here (Answer Section) even though it is present in Comments Section (thanks to jdehesa), for the benefit of the community.
Complete 2.x compatible code (work around) to perform sliced assignment of a Tensor is shown below:
import tensorflow as tf
def replace_slice(input_, replacement, begin, size=None):
inp_shape = tf.shape(input_)
if size is None:
size = tf.shape(replacement)
else:
replacement = tf.broadcast_to(replacement, size)
padding = tf.stack([begin, inp_shape - (begin + size)], axis=1)
replacement_pad = tf.pad(replacement, padding)
mask = tf.pad(tf.ones_like(replacement, dtype=tf.bool), padding)
return tf.where(mask, replacement_pad, input_)
def replace_slice_in(tensor):
return _SliceReplacer(tensor)
class _SliceReplacer:
def __init__(self, tensor):
self._tensor = tensor
def __getitem__(self, slices):
return _SliceReplacer._Inner(self._tensor, slices)
def with_value(self, replacement): # Just for convenience in case you skip the indexing
return _SliceReplacer._Inner(self._tensor, (...,)).with_value(replacement)
class _Inner:
def __init__(self, tensor, slices):
self._tensor = tensor
self._slices = slices
def with_value(self, replacement):
begin, size = _make_slices_begin_size(self._tensor, self._slices)
return replace_slice(self._tensor, replacement, begin, size)
# This computes begin and size values for a set of slices
def _make_slices_begin_size(input_, slices):
if not isinstance(slices, (tuple, list)):
slices = (slices,)
inp_rank = tf.rank(input_)
inp_shape = tf.shape(input_)
# Did we see a ellipsis already?
before_ellipsis = True
# Sliced dimensions
dim_idx = []
# Slice start points
begins = []
# Slice sizes
sizes = []
for i, s in enumerate(slices):
if s is Ellipsis:
if not before_ellipsis:
raise ValueError('Cannot use more than one ellipsis in slice spec.')
before_ellipsis = False
continue
if isinstance(s, slice):
start = s.start
stop = s.stop
if s.step is not None:
raise ValueError('Step value not supported.')
else: # Assumed to be a single integer value
start = s
stop = s + 1
# Dimension this slice refers to
i_dim = i if before_ellipsis else inp_rank - (len(slices) - i)
dim_size = inp_shape[i_dim]
# Default slice values
start = start if start is not None else 0
stop = stop if stop is not None else dim_size
# Fix negative indices
start = tf.cond(tf.convert_to_tensor(start >= 0), lambda: start, lambda: start + dim_size)
stop = tf.cond(tf.convert_to_tensor(stop >= 0), lambda: stop, lambda: stop + dim_size)
dim_idx.append([i_dim])
begins.append(start)
sizes.append(stop - start)
# For empty slice specs like [...]
if not dim_idx:
return tf.zeros_like(inp_shape), inp_shape
# Make full begin and size array (including omitted dimensions)
begin_full = tf.scatter_nd(dim_idx, begins, [inp_rank])
size_mask = tf.scatter_nd(dim_idx, tf.ones_like(sizes, dtype=tf.bool), [inp_rank])
size_full = tf.where(size_mask,
tf.scatter_nd(dim_idx, sizes, [inp_rank]),
inp_shape)
return begin_full, size_full
#with tf.Graph().as_default():
x = tf.reshape(tf.range(60), (4, 3, 5))
x2 = replace_slice_in(x)[:2, ..., -3:].with_value([100, 200, 300])
print('Tensor before Changing is \n', x)
print('\n')
print('Tensor after Changing is \n', x2)
Output of the above code is shown below:
Tensor before Changing is
tf.Tensor(
[[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
[[15 16 17 18 19]
[20 21 22 23 24]
[25 26 27 28 29]]
[[30 31 32 33 34]
[35 36 37 38 39]
[40 41 42 43 44]]
[[45 46 47 48 49]
[50 51 52 53 54]
[55 56 57 58 59]]], shape=(4, 3, 5), dtype=int32)
Tensor after Changing is
tf.Tensor(
[[[ 0 1 100 200 300]
[ 5 6 100 200 300]
[ 10 11 100 200 300]]
[[ 15 16 100 200 300]
[ 20 21 100 200 300]
[ 25 26 100 200 300]]
[[ 30 31 32 33 34]
[ 35 36 37 38 39]
[ 40 41 42 43 44]]
[[ 45 46 47 48 49]
[ 50 51 52 53 54]
[ 55 56 57 58 59]]], shape=(4, 3, 5), dtype=int32)

How to read a file word by word

I have a PPM file that I need to do certain operations on. The file is structured as in the following example. The first line, the 'P3' just says what kind of document it is. In the second line it gives the pixel dimension of an image, so in this case it's telling us that the image is 480x640. In the third line it declares the maximum value any color can take. After that there are lines of code. Every three integer group gives an rbg value for one pixel. So in this example, the first pixel has rgb value 49, 49, 49. The second pixel has rgb value 48, 48, 48, and so on.
P3
480 640
255
49 49 49 48 48 48 47 47 47 46 46 46 45 45 45 42 42 42 38 38
38 35 35 35 23 23 23 8 8 8 7 7 7 17 17 17 21 21 21 29 29
29 41 41 41 47 47 47 49 49 49 42 42 42 33 33 33 24 24 24 18 18
...
Now as you may notice, this particular picture is supposed to be 640 pixels wide which means 640*3 integers will provide the first row of pixels. But here the first row is very, very far from containing 640*3 integers. So the line-breaks in this file are meaningless, hence my problem.
The main way to read Python files is line-by-line. But I need to collect these integers into groups of 640*3 and treat that like a line. How would one do this? I know I could read the file in line-by-line and append every line to some list, but then that list would be massive and I would assume that doing so would place an unacceptable burden on a device's memory. But other than that, I'm out of ideas. Help would be appreciated.
To read three space-separated word at a time from a file:
with open(filename, 'rb') as file:
kind, dimensions, max_color = map(next, [file]*3) # read 3 lines
rgbs = zip(*[(int(word) for line in file for word in line.split())] * 3)
Output
[(49, 49, 49),
(48, 48, 48),
(47, 47, 47),
(46, 46, 46),
(45, 45, 45),
(42, 42, 42),
...
See What is the most “pythonic” way to iterate over a list in chunks?
To avoid creating the list at once, you could use itertools.izip() that would allow to read one rgb value at a time.
Probably not the most 'pythonic' way but...
Iterate through the lines containing integers.
Keep four counts - a count of 3 - color_code_count, a count of 1920 - numbers_processed, a count - col (0-639), and another - rows (0-479).
For each integer you encounter, add it to a temporary list at index of list[color_code_count]. Increment color_code_count, col, and numbers_processed.
Once color_code_count is 3, you take your temporary list and create a tuple 3 or triplet (not sure what the term is but your structure will look like (49,49,49) for the first pixel), and add that to a list of 640 columns, and 480 rows - insert your (49, 49, 49) into pixels[col][row].
Increment col.
Reset color_code_count.
'numbers_processed' will continue to increment until you get to 1920.
Once you hit 1920, you've reached the end of the first row.
Reset numbers_processed and col to zero, increment row by 1.
By this point, you should have 640 tuple3s or triplets in the row zero starting with (49,49,49), (48, 48, 48), (47, 47, 47), etc. And you're now starting to insert pixel values in row 1 column 0.
Like I said, probably not the most 'pythonic' way. There are probably better ways of doing this using join and map but I think this might work? This 'solution' if you want to call it that, shouldn't care about number of integers on any line since you're keeping count of how many numbers you expect to run through (1920) before you start a new row.
A possible way to go through each word is to iterate through each line then .split it into each word.
the_file = open("file.txt",r)
for line in the_file:
for word in line.split():
#-----Your Code-----
From there you can do whatever you want with your "words." You can add if-statements to check if there are numbers in each line with: (Though not very pythonic)
for line in the_file:
if "1" not in line or "2" not in line ...:
for word in line.split():
#-----Your Code-----
Or you can test if there is anything in each line: (Much more pythonic)
for line in the_file:
for word in line.split():
if len(word) != 0 or word != "\n":
#-----Your Code-----
I would recommend adding each of your new "lines" to a new document.
I am a C programmer. Sorry if this code looks like C Style:
f = open("pixel.ppm", "r")
type = f.readline()
height, width = f.readline().split()
height, width = int(height), int(width)
max_color = int(f.readline());
colors = []
count = 0
col_count = 0
line = []
while(col_count < height):
count = 0
i = 0
row =[]
while(count < width * 3):
temp = f.readline().strip()
if(temp == ""):
col_count = height
break
temp = temp.split()
line.extend(temp)
i = 0
while(i + 2 < len(line)):
row.append({'r':int(line[i]),'g':int(line[i+1]),'b':int(line[i+2])})
i = i+3
count = count +3
if(count >= width *3):
break
if(i < len(line)):
line = line[i:len(line)]
else:
line = []
col_count += 1
colors.append(row)
for row in colors:
for rgb in row:
print(rgb)
print("\n")
You can tweak this according to your needs. I tested it on this file:
P4
3 4
256
4 5 6 4 7 3
2 7 9 4
2 4
6 8 0
3 4 5 6 7 8 9 0
2 3 5 6 7 9 2
2 4 5 7 2
2
This seems to do the trick:
from re import findall
def _split_list(lst, i):
return lst[:i], lst[i:]
def iter_ppm_rows(path):
with open(path) as f:
ftype = f.readline().strip()
h, w = (int(s) for s in f.readline().split(' '))
maxcolor = int(f.readline())
rlen = w * 3
row = []
next_row = []
for line in f:
line_ints = [int(i) for i in findall('\d+\s+', line)]
if not row:
row, next_row = _split_list(line_ints, rlen)
else:
rest_of_row, next_row = _split_list(line_ints, rlen - len(row))
row += rest_of_row
if len(row) == rlen:
yield row
row = next_row
next_row = []
It isn't very pretty, but it allows for varying whitespace between numbers in the file, as well as varying line lengths.
I tested it on a file that looked like the following:
P3
120 160
255
0 1 2 3 4 5 6 7
8 9 10 11 12 13
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
[...]
9993 9994 9995 9996 9997 9998 9999
That file used random line lengths, but printed numbers in order so it was easy to tell at what value the rows began and stopped. Note that its dimensions are different than in the question's example file.
Using the following test code...
for row in iter_ppm_rows('mock_ppm.txt'):
print(len(row), row[0], row[-1])
...the result was the following, which seems to not be skipping over any data and returning rows of the right size.
480 0 479
480 480 959
480 960 1439
480 1440 1919
480 1920 2399
480 2400 2879
480 2880 3359
480 3360 3839
480 3840 4319
480 4320 4799
480 4800 5279
480 5280 5759
480 5760 6239
480 6240 6719
480 6720 7199
480 7200 7679
480 7680 8159
480 8160 8639
480 8640 9119
480 9120 9599
As can be seen, trailing data at the end of the file that can't represent a complete row was not yielded, which was expected but you'd likely want to account for it somehow.

Categories