I'm working in python and I'm specifically using sympy summations. I have an iterator that just goes up by 1 by using next(). For all of the values of my sympy summation, I want to keep going up by 1 by using next().
What I mean by this is that when x is 1 then it should be 1 when it runs next(), then when x is 2 it should be 2 because it runs next() again and when it's 3 it should be 3 because it runs next() again and so on.
The code I'm using is:
from sympy import symbols, summation, gcdex, Piecewise, Eq, Abs, Mul, Le, mod_inverse, solve, invert, Mod, Max, log, \
floor, simplify, And, Ge
import random
x = symbols('x')
#just a placeholder function that I was trying to change how next() operates so it can go up by 1 each tine i call next()
def callFunc(args):
if args:
return args
return args
class DynamicIterator:
def __init__(self, func, a, b):
self.func = func # Function to generate values
self.counter = 0 # Keeps track of the current index
self.a = a
self.b = b
self.can_advance = True # Default to allowing automatic advancement
self.advanced = False # Flag to control when to advance
def __iter__(self):
return self
def __next__(self, ):
if not self.can_advance:
raise StopIteration # Stop iteration if cannot advance
value = self.func(self.counter, self.a, self.b) # Generate the value
self.counter += 1 # Increment the counter
return value
def generate_combinations(n, a, c):
range_size = c - a + 1
l = a + (n % range_size)
return l # Only return `l`
# Create an instance of the iterator
expressions = DynamicIterator(generate_combinations, 1, 2 ** 256 + 1)
def next_expr():
iterate = next(expressions)
return iterate
def formula109(l, integer):
random_number = random.randint(integer, integer+1) + l
random_number2 = random_number - l # i removed the x so you can see how the values are the same each time without me using x.
return random_number2
logic = formula109(x, callFunc(next_expr()))
total = summation(logic, (x, 1, 900000))
print(total)
#see what numbers are for each value of x
terms = [logic.subs(x, k) for k in range(1, 10)]
print(terms)
As you can see when you run this, the values stay at 2 the entire time. I know that if I add x to it then it will go up but that's not what I want. I want to be able to use next() each time by itself to iterate up each time for every value of x. Can someone please show me what to do?
The output is:
1800000
[2, 2, 2, 2, 2, 2, 2, 2, 2]
I'm working in python and I'm specifically using sympy summations. I have an iterator that just goes up by 1 by using next(). For all of the values of my sympy summation, I want to keep going up by 1 by using next().
What I mean by this is that when x is 1 then it should be 1 when it runs next(), then when x is 2 it should be 2 because it runs next() again and when it's 3 it should be 3 because it runs next() again and so on.
The code I'm using is:
from sympy import symbols, summation, gcdex, Piecewise, Eq, Abs, Mul, Le, mod_inverse, solve, invert, Mod, Max, log, \
floor, simplify, And, Ge
import random
x = symbols('x')
#just a placeholder function that I was trying to change how next() operates so it can go up by 1 each tine i call next()
def callFunc(args):
if args:
return args
return args
class DynamicIterator:
def __init__(self, func, a, b):
self.func = func # Function to generate values
self.counter = 0 # Keeps track of the current index
self.a = a
self.b = b
self.can_advance = True # Default to allowing automatic advancement
self.advanced = False # Flag to control when to advance
def __iter__(self):
return self
def __next__(self, ):
if not self.can_advance:
raise StopIteration # Stop iteration if cannot advance
value = self.func(self.counter, self.a, self.b) # Generate the value
self.counter += 1 # Increment the counter
return value
def generate_combinations(n, a, c):
range_size = c - a + 1
l = a + (n % range_size)
return l # Only return `l`
# Create an instance of the iterator
expressions = DynamicIterator(generate_combinations, 1, 2 ** 256 + 1)
def next_expr():
iterate = next(expressions)
return iterate
def formula109(l, integer):
random_number = random.randint(integer, integer+1) + l
random_number2 = random_number - l # i removed the x so you can see how the values are the same each time without me using x.
return random_number2
logic = formula109(x, callFunc(next_expr()))
total = summation(logic, (x, 1, 900000))
print(total)
#see what numbers are for each value of x
terms = [logic.subs(x, k) for k in range(1, 10)]
print(terms)
As you can see when you run this, the values stay at 2 the entire time. I know that if I add x to it then it will go up but that's not what I want. I want to be able to use next() each time by itself to iterate up each time for every value of x. Can someone please show me what to do?
The output is:
1800000
[2, 2, 2, 2, 2, 2, 2, 2, 2]
Share
Improve this question
edited Feb 14 at 0:42
user27394478
asked Feb 13 at 23:59
user27394478user27394478
776 bronze badges
9
|
Show 4 more comments
2 Answers
Reset to default 1If I copy your code into an ipython
session (as I did last month), and look at logic
etc
In [193]: logic = formula109(x, callFunc(next_expr()))
In [194]: logic
Out[194]:
2
It's a number, not an expression (stripping x
off does that). Looking at it again doesn't change the value.
In [195]: logic
Out[195]:
2
Next look at the components that went into making logic
:
In [196]: next_expr()
Out[196]: 2
In [197]: next_expr()
Out[197]: 3
In [198]: next_expr()
Out[198]: 4
Ok, that steps the value.
In [199]: callFunc(next_expr())
Out[199]: 5
In [200]: callFunc(next_expr())
Out[200]: 6
In [201]: callFunc(next_expr())
Out[201]: 7
In [202]: callFunc(next_expr())
Out[202]: 8
and same with the callFunc
wrapper.
In [203]: formula109(x, callFunc(next_expr()))
Out[203]:
9
In [204]: formula109(x, callFunc(next_expr()))
Out[204]:
10
In [205]: formula109(x, callFunc(next_expr()))
Out[205]:
12
In [206]: formula109(x, callFunc(next_expr()))
Out[206]:
13
and with the formula109
wrapper.
In [207]: logic = formula109(x, callFunc(next_expr()))
In [208]: logic
Out[208]:
13
In [209]: logic = formula109(x, callFunc(next_expr()))
In [210]: logic
Out[210]:
15
A new logic
assignment gets the latest number.
But trying to iterate with sums
doesn't assign logic
again.
In [211]: [logic.subs(x, k) for k in range(1, 4)]
Out[211]: [15, 15, 15]
In [212]: [logic.subs(x, k) for k in range(1, 4)]
Out[212]: [15, 15, 15]
As before summation
is just Sum().doit()
.
In [213]: Sum(logic, (x,1,5))
Out[213]:
Sum(15, (x, 1, 5))
In [214]: Sum(logic, (x,1,5))
Out[214]:
Sum(15, (x, 1, 5))
Let's put x
back in so logic
is a sympy.Expr
.
In [215]: def formula109(l, integer):
...: random_number = random.randint(integer, integer+1) + l
...: return random_number
...:
In [216]: logic = formula109(x, callFunc(next_expr()))
In [217]: logic
Out[217]:
x + 16
logic
is x
plus a number, not x
plus a function call! The list comprehension is 1+16, 2+16, ...
:
In [218]: [logic.subs(x, k) for k in range(1, 4)]
Out[218]: [17, 18, 19]
The underlying 16
, the last value form callFunc(next_expr())
remains in Sum
and summation
:
In [219]: Sum(logic, (x,1,5))
Out[219]:
Sum(x + 16, (x, 1, 5))
In [220]: summation(logic, (x,1,5))
Out[220]:
95
Now if I ditch sympy
and just run your 'iterator' as plain python:
In [221]: [formula109(x, callFunc(next_expr())) for x in range(1,5)]
Out[221]: [17, 20, 22, 24]
In [222]: [formula109(x, callFunc(next_expr())) for x in range(1,5)]
Out[222]: [22, 24, 26, 28]
In [223]: callFunc(next_expr())
Out[223]: 24
In [224]: callFunc(next_expr())
Out[224]: 25
In [225]: [formula109(x, callFunc(next_expr())) for x in range(1,5)]
Out[225]: [27, 30, 32, 33]
next_expr()
steps each time it's called. But note, I have to include it in the list comprehension.
I don't get stepping with a simple value assignment
In [226]: foobar = callFunc(next_expr()); foobar
Out[226]: 30
In [227]: [foobar for i in range(3)]
Out[227]: [30, 30, 30]
I do get stepping if I include it in a function or lambda
In [231]: foobar = lambda k: callFunc(next_expr())
In [232]: foobar(1)
Out[232]: 31
In [233]: foobar(1)
Out[233]: 32
In [234]: [foobar(i) for i in range(4)]
Out[234]: [33, 34, 35, 36]
In [235]: [foobar(i) for i in range(4)]
Out[235]: [37, 38, 39, 40]
But I get an error if I try to include in a Sum
. That's probably true for any function.
In [239]: Sum(foobar, (x,1,5))
C:\Users\14256\miniconda3\lib\site-packages\sympy\concrete\expr_with_limits.py:26: SymPyDeprecationWarning:
The string fallback in sympify() is deprecated.
To explicitly convert the string form of an object, use
sympify(str(obj)). To add define sympify behavior on custom
objects, use sympy.core.sympify.converter or define obj._sympy_
(see the sympify() docstring).
sympify() performed the string fallback resulting in the following string:
'<function <lambda> at 0x000001B818FCE290>'
See https://docs.sympy./latest/explanation/active-deprecations.html#deprecated-sympify-string-fallback
for details.
This has been deprecated since SymPy version 1.6. It
will be removed in a future version of SymPy.
function = sympify(function)
ValueError: Error from parse_expr with transformed code: "<Symbol ('function' )<lambda >Symbol ('at' )Integer (0x000001B818FCE290 )>"
The above exception was the direct cause of the following exception:
File <string>:1
<Symbol ('function' )<lambda >Symbol ('at' )Integer (0x000001B818FCE290 )>
^
SyntaxError: invalid syntax
During handling of the above exception, another exception occurred:
SympifyError: Sympify of expression 'could not parse '<function <lambda> at 0x000001B818FCE290>'' failed, because of exception being raised:
SyntaxError: invalid syntax (<string>, line 1)
So I come to the same conclusion as last month. Sum/summation
is not at all like a python list comprehension or map
. It looks like it does the repeated expr.subs(x)
, but expr
cannot include function. It is not a lambda
!
sympy
runs within (or on top of) python. It does not rewrite or redefine the python syntax or interpretation.
Searching SO for [sympy] indexing
, I get many questions. The closest to your attempts is
How to evaluate SymPy expressions with indexed variables using explicit values?
The basic idea is to construct a n[1]+n[2]...
summation, and then subsitute the random values in via a dict
. As I demonstrated several times, Sum/summation
takes a sympy expr
or Function
, not a python executable. The random values have to be generated seperately, via numpy
and/or python.
In [1]: from sympy import *
In [2]: import numpy as np
In [23]: m=10
...: n = IndexedBase('n')
...: i = symbols('i', cls=Idx)
In [24]: Sum(n[i],(i,1,m))
Out[24]:
Sum(n[i], (i, 1, 10))
In [25]: sum_ = summation(n[i],(i,1,m)); sum_
Out[25]:
n[10] + n[1] + n[2] + n[3] + n[4] + n[5] + n[6] + n[7] + n[8] + n[9]
Making a simple array of random integers (it could be your checksumed strings, but those values are't obvious).
In [26]: a = np.random.randint(0,10,10); a
Out[26]: array([6, 2, 9, 3, 9, 4, 8, 5, 6, 6])
In [27]: dd = {n[i+1]:a[i] for i in range(0,10)}; dd
Out[27]:
{n[1]: 6,
n[2]: 2,
n[3]: 9,
n[4]: 3,
n[5]: 9,
n[6]: 4,
n[7]: 8,
n[8]: 5,
n[9]: 6,
n[10]: 6}
In [28]: sum_.subs(dd)
Out[28]:
58
Compare that to the direct sum of the array values:
In [29]: a.sum()
Out[29]: 58
The summation expression could be something more elaborate (even I think your piecemeal
):
In [30]: sum_ = summation(n[i]**i,(i,1,m)); sum_
Out[30]:
n[10]**10 + n[1] + n[2]**2 + n[3]**3 + n[4]**4 + n[5]**5 + n[6]**6 + n[7]**7 + n[8]**8 + n[9]**9
In [31]: sum_.subs(dd)
Out[31]:
73095614
In [33]: (a**np.arange(1,11)).sum()
Out[33]: 73095614
self.can_advance
andself.advanced
? You never set the first toFalse
, and you never use the second. – Barmar Commented Feb 14 at 0:49formula109(x, callFunc(next_expr()))
is just executed once, when you assign thelogic
variable. It's not repeated bysummation()
. When you assign a variable, the expression is evaluated completely, it's not evaluated lazily when the variable is used. – Barmar Commented Feb 14 at 0:53summation
in recent questions. He seems to think (or want) thatcallFunc(next_expr())
will be exectuted repeatedly every timex
is advanced. – hpaulj Commented Feb 14 at 6:39