最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - How can I keep going to the next number in my iterable for all the values of my sympy summation? - Stack Overflow

programmeradmin9浏览0评论

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
  • What's the point of self.can_advance and self.advanced? You never set the first to False, and you never use the second. – Barmar Commented Feb 14 at 0:49
  • formula109(x, callFunc(next_expr())) is just executed once, when you assign the logic variable. It's not repeated by summation(). 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:53
  • @Barmar listen. See the callFunc() I wanted to use that to make next_expr() run next each time for each value of x in the summation somehow. – user27394478 Commented Feb 14 at 0:58
  • @Barmar, this poster has asked about doing iterations with summation in recent questions. He seems to think (or want) that callFunc(next_expr()) will be exectuted repeatedly every time x is advanced. – hpaulj Commented Feb 14 at 6:39
  • Does a python list comprehension work? – hpaulj Commented Feb 14 at 11:45
 |  Show 4 more comments

2 Answers 2

Reset to default 1

If 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
发布评论

评论列表(0)

  1. 暂无评论