I am trying to calculate Pollard rho number using python for very long integers such below one
65779646778470582047547160396995720887221575959770627441205850493179860146690755880473849736210807898494458426111244201404810495587574110361900128405354081638434164434968839614760264675889940272767106444249
I have tried to calculate on my intel core i9 10980HK CPU, which results for few minutes high load work without any success. I am trying to use numba with #njit decorator to connect RTX 2070 super (on laptop) but it gives below error.
- argument 0: Int value is too large:
Here the code:
import numpy as np
import datetime
def pgcd(a,b):
if b==0:
return a
else:
r=a%b
return pgcd(b,r)
def pollardrho(n):
f = lambda z: z*z+1
x, y, d = 1, 1, 1
c = 0
while d==1:
c += 1
x = f(x) % n
y = f(f(y)) % n
d = pgcd(y-x, n)
return d, c
def test_time(n):
t = datetime.datetime.now()
d, c = pollardrho(int(n))
tps = datetime.datetime.now() - t
print(tps, c, d)
file = open("some_powersmooths_large.txt", "r")
for line in file.readlines():
if not line.startswith("#"):
print(line)
print("\n")
test_time(line)
print("\n")
How can I handle this type of big number calculations.
Part 1 (of 2, see Part 2 below).
Numba works only with 64-bit integers at most, it has no big integer arithmetic, only Python has. Big integers will be supported in future versions as developers of Numba promise. You need big integer arithmetics because you have very large integers in your inputs and calculations.
One optimization suggestion for you is to use GMPY2 Python library. It is highly-optimized library of long arithmetics, considerably faster than regular Python implementation of long arithmetics. For very large integers for example it implements multiplication using Fast Fourier Transform which is fastest available algorithm of multiplication.
But GMPY2 can be a bit challenging to install. Most recent precompiled versions for Windows are available by this link. Download .whl file for your version of Python and install it through pip, e.g. for my Windows 64-bit Python 3.7 I downloaded and installed pip install gmpy2-2.0.8-cp37-cp37m-win_amd64.whl. For Linux it is easiest to install through sudo apt install -y python3-gmpy2.
After using GMPY2 your code will become as fast as possible, because this library code is almost fastest in the world. Even Numba (if it had long arithmetics) would not improve more. Only faster formulas and better algorithm can help to improve further, or smaller input integers.
But your example large integers is a way to large for your algorithm even with GMPY2. You have to choose smaller integer or faster algorithm. I've run your algorithm and number for 5 or more minutes and didn't get result. But still if before result would be in 1 hour with regular Python then after using GMPY2 it may be done in 10 minutes or faster.
Also not very sure but probably in your algorithm f(f(y)) % n should be equivalent to f(f(y) % n) % n which should be computed probably faster as it will do twice shorter multiplication. But this needs extra checking.
Also your large integer appeared to be prime, as proven by Primo elliptic curve based primality proving program, it proved primality of this integer in 3 seconds on my PC. Primo only proves primality (with 100% guarantee) but doesn't factor the number (splitting into divisors). Factoring numbers can be done by programs from this list, these programs implement fastest known factoring algorithms, if some links are dead then Google those programs names.
Just wrap all integers n into gmpy2.mpz(n). For example I improved your code a bit, wrapped into gmpy2.mpz() and also made a loop so that all divisors are printed. Also as an example I took not your large prime but a much smaller - first 25 digits of Pi, which is composite, all of its divisors are printed in 7 second on my PC:
Try it online!
import datetime, numpy as np, gmpy2
def num(n):
return gmpy2.mpz(n)
zero, one = num(0), num(1)
def pgcd(a, b):
if b == zero:
return a
else:
r = a % b
return pgcd(b, r)
def pollardrho(n):
f = lambda z: z * z + one
x, y, d = one, one, one
c = 0
while d == one:
c += 1
x = f(x) % n
y = f(f(y)) % n
d = pgcd(y - x, n)
return d, c
def test_time(n):
n = num(int(n))
divs = []
while n > 1:
t = datetime.datetime.now()
d, c = pollardrho(num(int(n)))
tps = datetime.datetime.now() - t
print(tps, c, d, flush = True)
divs.append(d)
assert n % d == 0, (n, d)
n = n // d
print('All divisors:\n', ' '.join(map(str, divs)), sep = '')
test_time(1415926535897932384626433)
#test_time(65779646778470582047547160396995720887221575959770627441205850493179860146690755880473849736210807898494458426111244201404810495587574110361900128405354081638434164434968839614760264675889940272767106444249)
Output:
0:00:00 2 7
0:00:00 10 223
0:00:00.000994 65 10739
0:00:00.001999 132 180473
0:00:07.278999 579682 468017117899
All divisors:
7 223 10739 180473 468017117899
Part 2
Reading Wikipedia articles (here and here), I decided to implement a faster version of Pollard-Rho algorithm.
My version implemented below looks more complex but does twice less divisions and multiplications, also on average does less iterations of loop in total.
This improvements result in running time of 3 minutes for my test case, compared to original OP's algorithm with running time of 7 minutes, on my laptop.
My algorithm is also randomized, meaning that instead of witness 1 or 2 it takes random witness in range [1, N - 2]. In rare cases it may fail as said in Wikipedia then I rerun algorithm with different witness. Also it uses Fermat primality test to check if the input number is prime, then doesn't search for any more divisors.
For tests I used input number p generated by code p = 1; for i in range(256): p *= random.randrange(2, 1 << 32), basically it is composed of 256 factors each 32-bits at most.
Also I improved both algorithms to output more statistics. One of statistics params is pow which shows the complexity of each step, pow of 0.25 tells that if divisor is d then current factoring step spent c = d^0.25 iterations to find this divisor d. As told in Wikipedia Pollard-Rho algorithm should have on average pow = 0.25, meaning that complexity (number of iterations) of finding any divisor d is around d^0.25.
In next code there are also other improvements like providing a lot of statistics on the way. And finding all factors in the loop.
My version of algorithm for my test case has average pow of 0.24, original previous version has 0.3. Smaller pow means doing less loop iterations on the average.
Also tested my version with and without GMPY2. Apparently GMPY2 gives not much improvement over regular Python big integer arithmetic, mainly because GMPY2 is more optimized for really big numbers (tens thousands of bits) (using Fast Fourier Transform multiplication, etc), while here number are not to big in my test. But still GMPY2 gives speedup around 1.35x times providing running time of 3 minutes compared to almost 4 minutes without GMPY2 for same algorithm. To test with or without gmpy2 you need just to change inside def num(n) function either to return gmpy2.mpz(n) or to return n.
Try it online!
import datetime, numpy as np, gmpy2, random, math
random.seed(0)
def num(n):
return gmpy2.mpz(n)
zero, one = num(0), num(1)
def gcd(a, b):
while b != zero:
a, b = b, a % b
return a
def pollard_rho_v0(n):
f = lambda z: z * z + one
n, x, y, d, c, t = num(n), one, one, one, 0, datetime.datetime.now()
while d == one:
c += 1
x = f(x) % n
y = f(f(y)) % n
d = gcd(y - x, n)
return d, {'i': c, 'n_bits': n.bit_length(), 'd_bits': round(math.log(d) / math.log(2), 2),
'pow': round(math.log(max(c, 1)) / math.log(d), 4), 'time': str(datetime.datetime.now() - t)}
def is_fermat_prp(n, trials = 32):
n = num(n)
for i in range(trials):
a = num((3, 5, 7)[i] if i < 3 else random.randint(2, n - 2))
if pow(a, n - 1, n) != 1:
return False
return True
# https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
# https://ru.wikipedia.org/wiki/%D0%A0%D0%BE-%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9F%D0%BE%D0%BB%D0%BB%D0%B0%D1%80%D0%B4%D0%B0
def pollard_rho_v1(N):
AbsD = lambda a, b: a - b if a >= b else b - a
N, fermat_prp, t = num(N), None, datetime.datetime.now()
SecsPassed = lambda: (datetime.datetime.now() - t).total_seconds()
for j in range(8):
i, stage, y, x = 0, 2, num(1), num(random.randint(1, N - 2))
while True:
if (i & 0x3FF) == 0 and fermat_prp is None and (SecsPassed() >= 15 or j > 0):
fermat_prp = is_fermat_prp(N)
if fermat_prp:
r = N
break
r = gcd(N, AbsD(x, y))
if r != one:
break
if i == stage:
y = x
stage <<= one
x = (x * x + one) % N
i += 1
if r != N or fermat_prp:
return r, {'i': i, 'j': j, 'n_bits': N.bit_length(), 'd_bits': round(math.log(r) / math.log(2), 2),
'pow': round(math.log(max(i, 1)) / math.log(r), 4), 'fermat_prp': fermat_prp, 'time': str(datetime.datetime.now() - t)}
assert False, f'Pollard-Rho failed after {j + 1} trials! N = {N}'
def factor(n, *, ver = 1):
assert n > 0, n
n, divs, pows, tt = int(n), [], 0., datetime.datetime.now()
while n != 1:
d, stats = (pollard_rho_v0, pollard_rho_v1)[ver](n)
print(d, stats)
assert d > 1, (d, n)
divs.append(d)
assert n % d == 0, (d, n)
n = n // d
pows += min(1, stats['pow'])
print('All divisors:\n', ' '.join(map(str, divs)), sep = '')
print('Avg pow', round(pows / len(divs), 3), ', total time', datetime.datetime.now() - tt)
return divs
p = 1
for i in range(256):
p *= random.randrange(2, 1 << 32)
factor(p, ver = 1)
Output:
................
267890969 {'i': 25551, 'j': 0, 'n_bits': 245, 'd_bits': 28.0, 'pow': 0.523,
'fermat_prp': None, 'time': '0:00:02.363004'}
548977049 {'i': 62089, 'j': 0, 'n_bits': 217, 'd_bits': 29.03, 'pow': 0.5484,
'fermat_prp': None, 'time': '0:00:04.912002'}
3565192801 {'i': 26637, 'j': 0, 'n_bits': 188, 'd_bits': 31.73, 'pow': 0.4633,
'fermat_prp': None, 'time': '0:00:02.011999'}
1044630971 {'i': 114866, 'j': 0, 'n_bits': 156, 'd_bits': 29.96, 'pow': 0.5611,
'fermat_prp': None, 'time': '0:00:06.666996'}
3943786421 {'i': 60186, 'j': 0, 'n_bits': 126, 'd_bits': 31.88, 'pow': 0.4981,
'fermat_prp': None, 'time': '0:00:01.594000'}
3485918759 {'i': 101494, 'j': 0, 'n_bits': 94, 'd_bits': 31.7, 'pow': 0.5247,
'fermat_prp': None, 'time': '0:00:02.161004'}
1772239433 {'i': 102262, 'j': 0, 'n_bits': 63, 'd_bits': 30.72, 'pow': 0.5417,
'fermat_prp': None, 'time': '0:00:01.802996'}
2706462217 {'i': 0, 'j': 1, 'n_bits': 32, 'd_bits': 31.33, 'pow': 0.0,
'fermat_prp': True, 'time': '0:00:00.925801'}
All divisors:
258498 4 99792 121 245864 25 81 2 238008 70 39767 23358624 79 153 27 65 1566 2 31 13 57 1776 446 20 2 3409311 814 37 595384977 2 24 5 147 3738 4514 8372 7 38 237996 430 43 240 1183 10404 11 10234 30 2615625 1263 44590 240 3 101 231 2 79488 799236 2 88059 1578 432500 134 20956 101 3589 155 2471 91 7 6 100608 1995 33 9 181 48 5033 20 16 15 305 44 927 49 76 13 1577 46 144 292 65 2 111890 300 368 430705 6 368 381 1578812 4290 10 48 565 2 2 23606 23020 267 4186 5835 33 4 899 6288 3534 129064 34 315 36190 16900 6 60291 2 12 111631 463 2500 1405 1959 22 112 2 228 3 2192 2 28 321618 4 44 125924200164 9 17956 4224 2848 16 7 162 4 573 843 48 101 224460324 4 768 3 2 8 154 256 2 3 51 784 34 48 14 369 218 9 12 27 152 2 256 2 51 9 9411903 2 131 9 71 6 3 13307904 85608 35982 121669 93 3 3 121 7967 11 20851 19 289 4237 3481 289 89 11 11 121 841 5839 2071 59 29 17293 9367 110801 196219 2136917 631 101 3481 323 101 19 32129 29 19321 19 19 29 19 6113 509 193 1801 347 71 83 1373 191 239 109 1039 2389 1867 349 353 1566871 349 561971 199 1429 373 1231 103 1048871 83 1681 1481 3673 491 691 1709 103 49043 911 673 1427 4147027 569 292681 2153 6709 821 641 569 461 239 2111 2539 6163 3643 5881 2143 7229 593 4391 1531 937 1721 1873 3761 1229 919 178207 54637831 8317 17903 3631 6841 2131 4157 3467 2393 7151 56737 1307 10663 701 2522350423 4253 1303 13009 7457 271549 12391 36131 4943 6899 27077 4943 7723 4567 26959 9029 2063 6607 4721 14563 8783 38803 1889 1613 20479 16231 1847 41131 52201 37507 224351 13757 36299 3457 21739 107713 51169 17981 29173 2287 16253 386611 132137 9181 29123 740533 114769 2287 61553 21121 10501 47269 59077 224951 377809 499729 6257 5903 59999 126823 85199 29501 34589 518113 39409 411667 146603 1044091 312979 291569 158303 41777 115133 508033 154799 13184621 167521 3037 317711 206827 1254059 455381 152639 95531 1231201 494381 237689 163327 651331 351053 152311 103669 245683 1702901 46337 151339 6762257 57787 38959 366343 609179 219749 2058253 634031 263597 540517 1049051 710527 2343527 280967 485647 1107497 822763 862031 583139 482837 1586621 782107 371143 763549 10740361 1372963 62589077 1531627 31991 1206173 678901 4759373 5877959 178439 1736369 687083 53508439 99523 10456609 942943 2196619 376081 802453 10254457 2791597 3231757 2464793 66598351 1535867 16338167 1138639 882953 1483693 12624373 35717041 6427979 5653181 6421873 1434131 1258889 108462803 859667 64298779 261810191 5743483 32314969 5080721 8961767 68011043 7528799 2086957 41618389 19999663 118428929 45556487 40462109 22478363 29039737 17366957 77805557 12775951 50890837 22666991 14892133 691979 133920733 115526921 29092501 2332124099 16835209 101301479 29987047 160734341 35904857 12376361 17774983 2397907 525367681 245240591 48159641 45590383 87274531 69160309 256092673 7430783 588029137 91286513 75817271 393556847 1183839551 71513537 593809903 200299807 161799857 537099259 21510427 335791301 382965337 156133297 180373937 75136921 364790017 174932509 117559207 601612421 54539711 2107325149 566372699 102467207 321156893 1024847609 1250224901 1038888437 3029169139 345512147 4127597891 1043830063 267890969 548977049 3565192801 1044630971 3943786421 3485918759 1772239433 2706462217
Avg pow 0.238 , total time 0:03:48.193658
PS. Also decided to implement minimalistic but fast version of Pollard-Rho factorization algorithm, pure Pythonic, ready for copy-pasting into any project (for example of factoring first 25 digits of Pi):
Try it online!
def factor(n):
import itertools, math
if n <= 1:
return []
x = 2
for cycle in itertools.count(1):
y = x
for i in range(1 << cycle):
x = (x * x + 1) % n
d = math.gcd(x - y, n)
if d > 1:
return [d] + factor(n // d)
print(factor(1415926535897932384626433))
# [7, 223, 180473, 10739, 468017117899]
Given that the operation in pollardrho is very inefficient, I am not surprised that the operation takes a while.
However, I don't know that particular function, so I don't know if it could be made more efficient.
In Python, integers have an arbitrary length.
What this means is that they can be of any length, and Python itself will handle storing it properly using 64-bit integers (by spreading them over multiple of them).
(You can test this for yourself by for example creating an integer that cannot be stored in a 64-bit unsigned integer, like a = 2**64, and then checking the output of the a.bit_length() method, which should say 65)
So, theoretically speaking, you should be able to calculate any integer.
However, because you are using Numba, you are limited to integers that can actually be stored within a 64-bit unsigned integer due to the way Numba works.
The error you are getting is simply the number becoming too large to store in a 64-bit unsigned integer.
Bottom line: Without Numba, you can calculate that number just fine. With Numba, you cannot.
Of course, if you only want to know roughly what the number is, and not precisely, you can instead just use floats.
I have range of number 132-149
And i have to print 2 horizontal lines
first for even numbers and second for odd numbers
I can print odd and even numbers separately using:
>>> for num in range (132, 150):
if num % 2 == 0:
print (num, end = ' ')
132 134 136 138 140 142 144 146 148
>>> for num in range (132, 150):
if num % 2 != 0:
print (num, end = ' ')
133 135 137 139 141 143 145 147 149
want these two to combine and printe something like this:
132 134 136 138 140 142 144 146 148
133 135 137 139 141 143 145 147 149
Thanks for your edit.
First of all you don't need to iterate over your numbers multiple times. You just can use pythons if/else construct.
even_list = []
odd_list = []
for num in range(132, 150):
if num % 2 == 0:
even_list.append(str(num)) # casted to string to use join function later
else:
odd_list.append(str(num))
print(" ".join(even_list))
print(" ".join(odd_list))
Output
132 134 136 138 140 142 144 146 148
133 135 137 139 141 143 145 147 149
You can do this by appending to 2 different lists:
line1=[]
line2=[]
for num in range (132, 150):
if num % 2 == 0:
line1.append(num)
else:
line2.append(num)
print(line1)
print(line2)
def print_even_odd(start, end):
e_o = []
if start % 2 != 0:
e_o.append(('', start))
for i in range((start + 1) / 2, (end + 1) / 2):
e_o.append((i * 2, i * 2 + 1))
if end % 2 == 0:
e_o.append((end, ''))
for i in e_o:
print("\t%5s\t\t%5s" % i)
for j in [0, 1]:
result = "".join(["%5s" % i[j] for i in e_o])
print(result)
print_even_odd(1, 20)
result is:
1
2 3
4 5
6 7
8 9
10 11
12 13
14 15
16 17
18 19
20
2 4 6 8 10 12 14 16 18 20
1 3 5 7 9 11 13 15 17 19
I hope that, this is what you need
Use:
print '*' * n
where n is the number of asterisks you wish to display.
Here is a more complete example:
lens = [3, 5, 10, 1]
for i, l in enumerate(lens):
print '%02d:%s' % (i + 1, '*' * l)
This displays:
01:***
02:*****
03:**********
I have an array of strings that i read from file ,i want to compare each line of my file to a specific string..the file is too large (about 200 MB of lines)
i have followed this tutorial https://nyu-cds.github.io/python-numba/05-cuda/ but it doesn't show exactly how to deal with array of strings/characters.
import numpy as np
from numba import cuda
#cuda.jit
def my_kernel(io_array):
tx = cuda.threadIdx.x
ty = cuda.blockIdx.x
bw = cuda.blockDim.x
pos = tx + ty * bw
if pos < io_array.size: # Check array boundaries
io_array[pos] # i want here to compare each line of the string array to a specific line
def main():
a = open("test.txt", 'r') # open file in read mode
print("the file contains:")
data = country = np.array(a.read())
# Set the number of threads in a block
threadsperblock = 32
# Calculate the number of thread blocks in the grid
blockspergrid = (data.size + (threadsperblock - 1)) // threadsperblock
# Now start the kernel
my_kernel[blockspergrid, threadsperblock](data)
# Print the result
print(data)
if __name__ == '__main__':
main()
I have two problems.
First: how to send my sentence (string) that i want to compare each line of my file to it to the kernal function. (in the io_array without affecting the threads computation)
Second: it how to deal with string array? i get this error when i run the above code
this error is usually caused by passing an argument of a type that is unsupported by the named function.
[1] During: typing of intrinsic-call at test2.py (18)
File "test2.py", line 18:
def my_kernel(io_array):
<source elided>
if pos < io_array.size: # Check array boundaries
io_array[pos] # do the computation
P.S i'm new to Cuda and have just started learning it.
First of all this:
data = country = np.array(a.read())
doesn't do what you think it does. It does not yield a numpy array that you can index like this:
io_array[pos]
If you don't believe me, just try that in ordinary python code with something like:
print(data[0])
and you'll get an error. If you want help with that, just ask your question on the python or numpy tag.
So we need a different method to load the string data from disk. For simplicity, I choose to use numpy.fromfile(). This method will require that all lines in your file are of the same width. I like that concept. There's more information you would have to describe if you want to handle lines of varying lengths.
If we start out that way, we can load the data as an array of bytes, and use that:
$ cat test.txt
the quick brown fox.............
jumped over the lazy dog........
repeatedly......................
$ cat t43.py
import numpy as np
from numba import cuda
#cuda.jit
def my_kernel(str_array, check_str, length, lines, result):
col,line = cuda.grid(2)
pos = (line*(length+1))+col
if col < length and line < lines: # Check array boundaries
if str_array[pos] != check_str[col]:
result[line] = 0
def main():
a = np.fromfile("test.txt", dtype=np.byte)
print("the file contains:")
print(a)
print("array length is:")
print(a.shape[0])
print("the check string is:")
b = a[33:65]
print(b)
i = 0
while a[i] != 10:
i=i+1
line_length = i
print("line length is:")
print(line_length)
print("number of lines is:")
line_count = a.shape[0]/(line_length+1)
print(line_count)
res = np.ones(line_count)
# Set the number of threads in a block
threadsperblock = (32,32)
# Calculate the number of thread blocks in the grid
blocks_x = (line_length/32)+1
blocks_y = (line_count/32)+1
blockspergrid = (blocks_x,blocks_y)
# Now start the kernel
my_kernel[blockspergrid, threadsperblock](a, b, line_length, line_count, res)
# Print the result
print("matching lines (match = 1):")
print(res)
if __name__ == '__main__':
main()
$ python t43.py
the file contains:
[116 104 101 32 113 117 105 99 107 32 98 114 111 119 110 32 102 111
120 46 46 46 46 46 46 46 46 46 46 46 46 46 10 106 117 109
112 101 100 32 111 118 101 114 32 116 104 101 32 108 97 122 121 32
100 111 103 46 46 46 46 46 46 46 46 10 114 101 112 101 97 116
101 100 108 121 46 46 46 46 46 46 46 46 46 46 46 46 46 46
46 46 46 46 46 46 46 46 10]
array length is:
99
the check string is:
[106 117 109 112 101 100 32 111 118 101 114 32 116 104 101 32 108 97
122 121 32 100 111 103 46 46 46 46 46 46 46 46]
line length is:
32
number of lines is:
3
matching lines (match = 1):
[ 0. 1. 0.]
$
I'm trying to convert an AMPL model to Pyomo (something I have no experience with using). I'm finding the syntax hard to adapt to, especially the constraint and objective sections. I've already linked my computer together with python, anaconda, Pyomo, and GLPK, and just need to get the actual code down. I'm a beginner coder so forgive me if my code is poorly written. Still trying to get the hang of this!
Here is the data from the AMPL code:
set PROD := 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;
set PROD1:= 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;
ProdCost 414 3 46 519 876 146 827 996 922 308 568 176 58 13 20 974 121 751 130 844 280 123 275 843 717 694 72 413 65 631
HoldingCost 606 308 757 851 148 867 336 44 364 960 69 428 778 485 285 938 980 932 199 175 625 513 536 965 366 950 632 88 698 744
Demand 105 70 135 67 102 25 147 69 23 84 32 41 81 133 180 22 174 80 24 156 28 125 23 137 180 151 39 138 196 69
And here is the model:
set PROD; # set of production amounts
set PROD1; # set of holding amounts
param ProdCost {PROD} >= 0; # parameter set of production costs
param Demand {PROD} >= 0; # parameter set of demand at each time
param HoldingCost {PROD} >= 0; # parameter set of holding costs
var Inventory {PROD1} >= 0; # variable that sets inventory amount at each time
var Make {p in PROD} >= 0; # variable of amount produced at each time
minimize Total_Cost: sum {p in PROD} ((ProdCost[p] * Make[p]) + (Inventory[p] * HoldingCost[p]));
# Objective: minimize total cost from all production and holding cost
subject to InventoryConstraint {p in PROD}: Inventory[p] = Inventory[p-1] + Make[p] - Demand[p];
# excess production transfers to inventory
subject to MeetDemandConstraint {p in PROD}: Make[p] >= Demand[p] - Inventory[p-1];
# Constraint: holding and production must exceed demand
subject to InitialInventoryConstraint: Inventory[0] = 0;
# Constraint: Inventory must start at 0
Here's what I have so far. Not sure if it's right or not:
from pyomo.environ import *
demand=[105,70,135,67,102,25,147,69,23,84,32,41,81,133,180,22,174,80,24,156,28,125,23,137,180,151,39,138,196,69]
holdingcost=[606,308,757,851,148,867,336,44,364,960,69,428,778,485,285,938,980,932,199,175,625,513,536,965,366,950,632,88,698,744]
productioncost=[414,3,46,519,876,146,827,996,922,308,568,176,58,13,20,974,121,751,130,844,280,123,275,843,717,694,72,413,65,631]
model=ConcreteModel()
model.I=RangeSet(1,30)
model.J=RangeSet(0,30)
model.x=Var(model.I, within=NonNegativeIntegers)
model.y=Var(model.J, within=NonNegativeIntegers)
model.obj = Objective(expr = sum(model.x[i]*productioncost[i]+model.y[i]*holdingcost[i] for i in model.I))
def InventoryConstraint(model, i):
return model.y[i-1] + model.x[i] - demand[i] <= model.y[i]
InvCont = Constraint(model, rule=InventoryConstraint)
def MeetDemandConstraint(model, i):
return model.x[i] >= demand[i] - model.y[i-1]
DemCont = Constraint(model, rule=MeetDemandConstraint)
def Initial(model):
return model.y[0] == 0
model.Init = Constraint(rule=Initial)
opt = SolverFactory('glpk')
results = opt.solve(model,load_solutions=True)
model.solutions.store_to(results)
results.write()
Thanks!
The only issues I see are in some of your constraint declarations. You need to attach the constraints to the model and the first argument passed in should be the indexing set (which I'm assuming should be model.I).
def InventoryConstraint(model, i):
return model.y[i-1] + model.x[i] - demand[i] <= model.y[i]
model.InvCont = Constraint(model.I, rule=InventoryConstraint)
def MeetDemandConstraint(model, i):
return model.x[i] >= demand[i] - model.y[i-1]
model.DemCont = Constraint(model.I, rule=MeetDemandConstraint)
The syntax that you're using to solve the model is a little out-dated but should work. Another option would be:
opt = SolverFactory('glpk')
opt.solve(model,tee=True) # The 'tee' option prints the solver output to the screen
model.display() # This will print a summary of the model solution
Another command that is useful for debugging is model.pprint(). This will display the entire model including the expressions for Constraints and Objectives.