sum of the elements of a list until limit - python

I am facing a problem where I need my code to add the element of a list until the sum gets as close as possible to a constant. Once the constant is reached, I need the code to store the sum, and also the sum of indexes (count how many variables it needed to reach that sum). I am a beginner in Python and this problem is giving a very hard time.
I have tryed a while loop as well as a for loop. At that point, I am kind of stuck and not sure if my method is accurate.
here is a concrete example of the logic. Assuming demand for period 1 is 10 and demand for period 2 is 23 and Q is 12. (Q here represent an optimal quantity). What I want to figure out is whether we should place an order in period 1 that includes demand for periods1+2, or if it is better to place 1 order at period 1 and another one at period 2. Q is what determines it, if demand for period 1 is closer to Q or cumulative demand for period 1+2 is closer to Q. In this example, |10-12| < |(10+23)-12|, therefore we want to record an order for period 1, and another one for period 2.
def feeoq(q, demand):
sum = 0
prod = []
for i in demand:
sum = sum + i
if abs(sum - q) < abs(sum + i - q):
return prod.append(sum)
else:
sum = sum + i
I am not getting an error message but the function is not returning what I am expecting.

You have repeated the sum = sum + i line. Once at the start of the loop and then in the else condition. I guess you should remove the first addition line and append sum + i.

Perhaps we can talk about this as a base of discussion:
import numpy as np
np.random.seed(42)
L = np.random.randint(0, 10, 10)
q = 7
print(L)
def subs(L, q):
sum = 0
for i, e in enumerate(L):
sum += e
if sum > q:
if abs(sum - q) > abs(sum - e - q):
r = sum - e
sum = e
n = i - 1
else:
r = sum
sum = 0
n = i
yield n, r
yield i, sum
print(list(subs(L, q)))
Explanation :
Basically, this function first of all checks, if sum is bigger than q. Only if yes, you have two values of which not both are smaller or both are bigger than q. This is the prerequisite for your test, which one of both has the smaller distance to q.
Now, depending on which one is closer to q, the function returns sum or sum - e.
Now that I use here the verb return while using yield in the code: it's not a usual function but a generator. The main clue about this type of functions is, when they yield a value, you can think in a first step of the same like returning a value, with one important difference: the function itself does not return (i.e. does not end), but falls asleep, waiting for its next call, keeping its complete state including all the values calculated up to now, to then proceed right in the next line after yield, as if nothing happened before - until the next yield keyword.
In short: IMO exactly what you need if you want to sum up until whatever but do not really want to stop when whatever is reached... :)

Just my point of view to the problem, as stated in my comment below your question:
An algorithm, which calculates the number of needed orders of fixed quantities per order for every period, such that the demand is always covered.
Additionally the rest of every order, which was not covered in a certain period, is considered, so that eventually the demand of the next period can be covered with one order less.
def calcOrder(demand, Q):
result = []
rest = 0
for i, e in enumerate(demand):
current = e - rest
order = np.ceil(current/Q)
result.append(int(order))
rest = order * Q - current
return result
Example:
import numpy as np
np.random.seed(793)
demand = np.random.randint(0, 51, 5)
Q = 12
demand
# array([50, 20, 19, 48, 25])
print(f'demand\tcurrent\torder\trest')
rest = 0
for i, e in enumerate(demand):
current = e - rest
order = int(np.ceil(current/Q))
rest = order * Q - current
print(f'{e}\t{current}\t{order}\t{rest}')
# demand current order rest
# 50 50 5 10
# 20 10 1 2
# 19 17 2 7
# 48 41 4 7
# 25 18 2 6

Related

Primitive Calculator - Dynamic & Recursive approach

I have tried to solve the Primitive calculator problem with dynamic and recursive approach , works fine for smaller inputs but taking long time for larger inputs (eg: 96234) .
You are given a primitive calculator that can perform the following three operations with
the current number π‘₯: multiply π‘₯ by 2, multiply π‘₯ by 3, or add 1 to π‘₯. Your goal is given a
positive integer 𝑛, find the minimum number of operations needed to obtain the number 𝑛
starting from the number 1.
import sys
def optimal_sequence(n,memo={}):
if n in memo:
return memo[n]
if (n==1):
return 0
c1 = 1+optimal_sequence(n-1,memo)
c2 = float('inf')
if n % 2 == 0 :
c2 = 1+optimal_sequence(n // 2,memo)
c3 = float('inf')
if n % 3 == 0 :
c3 = 1+optimal_sequence(n // 3,memo)
c = min(c1,c2,c3)
memo[n] = c
return c
input = sys.stdin.read()
n = int(input)
sequence = optimal_sequence(n)
print(sequence) # Only printing optimal no. of operations
Can anyone point out what is wrong in recursive solution as it works fine by using for loop.
There are a few things to consider here. The first is that you always check if you can subtract 1 away from n. This is always going to be true until n is 1. therefor with a number like 12. You will end up taking 1 away first, then calling the function again with n=11, then n=10, then n=9 etc......only once you have resolved how many steps it will take to resolve using the -1 method (in this case c1 will be 11) you then try for c2.
So for c2 you then half 12, then call the function which will start with the -1 again so you end up with n=12, n=6, n=5, n=4...etc. Even though you have n in the memo you still spend a lot of wasted time on function calls.
Instead you probably want to just shrink the problem space as fast as possible. So start with the rule that will reduce n the most. I.E divide by 3, if that doesnt work then divide by 2, only if neither of the first two worked then subtract 1.
With this method you dont even need to track n as n will always be getting smaller so there is no need to have a memo dict tracking the results.
from time import time
def optimal_sequence(n):
if n == 1:
return 0
elif n % 3 == 0:
c = optimal_sequence(n // 3)
elif n % 2 == 0:
c = optimal_sequence(n // 2)
else:
c = optimal_sequence(n - 1)
return 1 + c
n = int(input("Enter a value for N: "))
start = time()
sequence = optimal_sequence(n)
end = time()
print(f"{sequence=} took {end - start} seconds")
also input is a python function to read from teh terminal you dont need to uses stdin
OUTPUT
Enter a value for N: 96234
sequence=15 took 0.0 seconds

How to optimize (3*O(n**2)) + O(n) algorithm?

I am trying to solve the arithmetic progression problem from USACO. Here is the problem statement.
An arithmetic progression is a sequence of the form a, a+b, a+2b, ..., a+nb where n=0, 1, 2, 3, ... . For this problem, a is a non-negative integer and b is a positive integer.
Write a program that finds all arithmetic progressions of length n in the set S of bisquares. The set of bisquares is defined as the set of all integers of the form p2 + q2 (where p and q are non-negative integers).
The two lines of input are n and m, which are the length of each sequence, and the upper bound to limit the search of the bi squares respectively.
I have implemented an algorithm which correctly solves the problem, yet it takes too long. With the max constraints of n = 25 and m = 250, my program does not solve the problem in the 5 second time limit.
Here is the code:
n = 25
m = 250
bisq = set()
for i in range(m+1):
for j in range(i,m+1):
bisq.add(i**2+j**2)
seq = []
for b in range(1, max(bisq)):
for a in bisq:
x = a
for i in range(n):
if x not in bisq:
break
x += b
else:
seq.append((a,b))
The program outputs the correct answer, but it takes too long. I tried running the program with the max n/m values, and after 30 seconds, it was still going.
Disclaimer: this is not a full answer. This is more of a general direction where to look for.
For each member of a sequence, you're looking for four parameters: two numbers to be squared and summed (q_i and p_i), and two differences to be used in the next step (x and y) such that
q_i**2 + p_i**2 + b = (q_i + x)**2 + (p_i + y)**2
Subject to:
0 <= q_i <= m
0 <= p_i <= m
0 <= q_i + x <= m
0 <= p_i + y <= m
There are too many unknowns so we can't get a closed form solution.
let's fix b: (still too many unknowns)
let's fix q_i, and also state that this is the first member of the sequence. I.e., let's start searching from q_1 = 0, extend as much as possible and then extract all sequences of length n. Still, there are too many unknowns.
let's fix x: we only have p_i and y to solve for. At this point, note that the range of possible values to satisfy the equation is much smaller than full range of 0..m. After some calculus, b = x*(2*q_i + x) + y*(2*p_i + y), and there are really not many values to check.
This last step prune is what distinguishes it from the full search. If you write down this condition explicitly, you can get the range of possible p_i values and from that find the length of possible sequence with step b as a function of q_i and x. Rejecting sequences smaller than n should further prune the search.
This should get you from O(m**4) complexity to ~O(m**2). It should be enough to get into the time limit.
A couple more things that might help prune the search space:
b <= 2*m*m//n
a <= 2*m*m - b*n
An answer on math.stackexchange says that for a number x to be a bisquare, any prime factor of x of the form 3 + 4k (e.g., 3, 7, 11, 19, ...) must have an even power. I think this means that for any n > 3, b has to be even. The first item in the sequence a is a bisquare, so it has an even number of factors of 3. If b is odd, then one of a+1b or a+2b will have an odd number of factors of 3 and therefore isn't a bisquare.

Finding the sum of a geometric progression

I'm being asked to add the first 100 terms f the sequence (1 + 1/2 + 1/4 + 1/8 ...etc)
what i ve been trying is something Iike
for x in range(101):
n = ((1)/(2**x))
sum(n)
gives me an error, guess you cant put ranges to a power
print(n)
will give me a list of all the values, but i need them summed together
anyone able to give me a hand?
using qtconsole if that's of any relevance, i'm quite new to this if you haven't already guessed
You keep only one value at a time. If you want the sum, you need to aggregate the results, and for that you'd need an initial value, to which you can add each round the current term:
n = 0 # initial value
for x in range(100):
n += 1 / 2**x # add current term
print(n)
Hmm, there is actually a formula for sum of geometric series:
In your question, a is 1, r is 0.5 and n is 100
So we can do like
a = 1
r = 0.5
n = 100
print(a * (1 - r ** n) / (1 - r))
It is important to initialize sum_n to zero. With each iteration, you add (1/2**x) from your sequence/series to sum_n until you reach n_range.
n_range = 101
sum_n = 0 # initialize sum_n to zero
for x in range(n_range):
sum_n += (1/(2**x))
print(sum_n)
You are getting an error because sum takes an iterable and you are passing it a float:
sum(iterable[, start])
To solve your problem, as others have suggested, you need to init an accumulator and add your power on every iteration.
If you absolutely must use the sum function:
>>> import math
>>> sum(map(lambda x:math.pow(2,-x),range(100)))
2.0

Monte Carlo Method in Python

I've been attempting to use Python to create a script that lets me generate large numbers of points for use in the Monte Carlo method to calculate an estimate to Pi. The script I have so far is this:
import math
import random
random.seed()
n = 10000
for i in range(n):
x = random.random()
y = random.random()
z = (x,y)
if x**2+y**2 <= 1:
print z
else:
del z
So far, I am able to generate all of the points I need, but what I would like to get is the number of points that are produced when running the script for use in a later calculation. I'm not looking for incredibly precise results, just a good enough estimate. Any suggestions would be greatly appreciated.
If you're doing any kind of heavy duty numerical calculation, considering learning numpy. Your problem is essentially a one-linear with a numpy setup:
import numpy as np
N = 10000
pts = np.random.random((N,2))
# Select the points according to your condition
idx = (pts**2).sum(axis=1) < 1.0
print pts[idx], idx.sum()
Giving:
[[ 0.61255615 0.44319463]
[ 0.48214768 0.69960483]
[ 0.04735956 0.18509277]
...,
[ 0.37543094 0.2858077 ]
[ 0.43304577 0.45903071]
[ 0.30838206 0.45977162]], 7854
The last number is count of the number of events that counted, i.e. the count of the points whose radius is less than one.
Not sure if this is what you're looking for, but you can run enumerate on range and get the position in your iteration:
In [1]: for index, i in enumerate(xrange(10, 15)):
...: print index + 1, i
...:
...:
1 10
2 11
3 12
4 13
5 14
In this case, index + 1 would represent the current point being created (index itself would be the total number of points created at the beginning of a given iteration). Also, if you are using Python 2.x, xrange is generally better for these sorts of iterations as it does not load the entire list into memory but rather accesses it on an as-needed basis.
Just add hits variable before the loop, initialize it to 0 and inside your if statement increment hits by one.
Finally you can calculate PI value using hits and n.
import math
import random
random.seed()
n = 10000
hits = 0 # initialize hits with 0
for i in range(n):
x = random.random()
y = random.random()
z = (x,y)
if x**2+y**2 <= 1:
hits += 1
else:
del z
# use hits and n to compute PI

Not sure how to integrate negative number function in data generating algorithm?

I’m having a bit of trouble controlling the results from a data generating algorithm I am working on. Basically it takes values from a list and then lists all the different combinations to get to a specific sum. So far the code works fine(haven’t tested scaling it with many variables yet), but I need to allow for negative numbers to be include in the list.
The way I think I can solve this problem is to put a collar on the possible results as to prevent infinity results(if apples is 2 and oranges are -1 then for any sum, there will be an infinite solutions but if I say there is a limit of either then it cannot go on forever.)
So Here's super basic code that detects weights:
import math
data = [-2, 10,5,50,20,25,40]
target_sum = 100
max_percent = .8 #no value can exceed 80% of total(this is to prevent infinite solutions
for node in data:
max_value = abs(math.floor((target_sum * max_percent)/node))
print node, "'s max value is ", max_value
Here's the code that generates the results(first function generates a table if its possible and the second function composes the actual results. Details/pseudo code of the algo is here: Can brute force algorithms scale? ):
from collections import defaultdict
data = [-2, 10,5,50,20,25,40]
target_sum = 100
# T[x, i] is True if 'x' can be solved
# by a linear combination of data[:i+1]
T = defaultdict(bool) # all values are False by default
T[0, 0] = True # base case
for i, x in enumerate(data): # i is index, x is data[i]
for s in range(target_sum + 1): #set the range of one higher than sum to include sum itself
for c in range(s / x + 1):
if T[s - c * x, i]:
T[s, i+1] = True
coeff = [0]*len(data)
def RecursivelyListAllThatWork(k, sum): # Using last k variables, make sum
# /* Base case: If we've assigned all the variables correctly, list this
# * solution.
# */
if k == 0:
# print what we have so far
print(' + '.join("%2s*%s" % t for t in zip(coeff, data)))
return
x_k = data[k-1]
# /* Recursive step: Try all coefficients, but only if they work. */
for c in range(sum // x_k + 1):
if T[sum - c * x_k, k - 1]:
# mark the coefficient of x_k to be c
coeff[k-1] = c
RecursivelyListAllThatWork(k - 1, sum - c * x_k)
# unmark the coefficient of x_k
coeff[k-1] = 0
RecursivelyListAllThatWork(len(data), target_sum)
My problem is, I don't know where/how to integrate my limiting code to the main code inorder to restrict results and allow for negative numbers. When I add a negative number to the list, it displays it but does not include it in the output. I think this is due to it not being added to the table(first function) and I'm not sure how to have it added(and still keep the programs structure so I can scale it with more variables).
Thanks in advance and if anything is unclear please let me know.
edit: a bit unrelated(and if detracts from the question just ignore, but since your looking at the code already, is there a way I can utilize both cpus on my machine with this code? Right now when I run it, it only uses one cpu. I know the technical method of parallel computing in python but not sure how to logically parallelize this algo)
You can restrict results by changing both loops over c from
for c in range(s / x + 1):
to
max_value = int(abs((target_sum * max_percent)/x))
for c in range(max_value + 1):
This will ensure that any coefficient in the final answer will be an integer in the range 0 to max_value inclusive.
A simple way of adding negative values is to change the loop over s from
for s in range(target_sum + 1):
to
R=200 # Maximum size of any partial sum
for s in range(-R,R+1):
Note that if you do it this way then your solution will have an additional constraint.
The new constraint is that the absolute value of every partial weighted sum must be <=R.
(You can make R large to avoid this constraint reducing the number of solutions, but this will slow down execution.)
The complete code looks like:
from collections import defaultdict
data = [-2,10,5,50,20,25,40]
target_sum = 100
# T[x, i] is True if 'x' can be solved
# by a linear combination of data[:i+1]
T = defaultdict(bool) # all values are False by default
T[0, 0] = True # base case
R=200 # Maximum size of any partial sum
max_percent=0.8 # Maximum weight of any term
for i, x in enumerate(data): # i is index, x is data[i]
for s in range(-R,R+1): #set the range of one higher than sum to include sum itself
max_value = int(abs((target_sum * max_percent)/x))
for c in range(max_value + 1):
if T[s - c * x, i]:
T[s, i+1] = True
coeff = [0]*len(data)
def RecursivelyListAllThatWork(k, sum): # Using last k variables, make sum
# /* Base case: If we've assigned all the variables correctly, list this
# * solution.
# */
if k == 0:
# print what we have so far
print(' + '.join("%2s*%s" % t for t in zip(coeff, data)))
return
x_k = data[k-1]
# /* Recursive step: Try all coefficients, but only if they work. */
max_value = int(abs((target_sum * max_percent)/x_k))
for c in range(max_value + 1):
if T[sum - c * x_k, k - 1]:
# mark the coefficient of x_k to be c
coeff[k-1] = c
RecursivelyListAllThatWork(k - 1, sum - c * x_k)
# unmark the coefficient of x_k
coeff[k-1] = 0
RecursivelyListAllThatWork(len(data), target_sum)

Categories