首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >有没有办法在SymPy中一步一步地得到解决方案?

有没有办法在SymPy中一步一步地得到解决方案?
EN

Stack Overflow用户
提问于 2016-09-06 23:31:07
回答 3查看 7.9K关注 0票数 26

有没有办法在SymPy中一步一步地得到解决方案?例如:

代码语言:javascript
复制
x**2-5 = 4
  step 1 x**2-5+5=4+5
  step 2 : x**2=9
  step 3 :x = 3 or x= -3
EN

回答 3

Stack Overflow用户

发布于 2016-12-19 16:05:01

(这更多是作为回答的评论)

有一些谷歌的-soc的想法来实现

逐步表达式可视化

2014年GSoC创意:很多时候,人们都会问他们如何知道某些函数在做什么。例如,他们想一步一步地了解.对于前者,您能做的最好的是遵循代码;对于后者,算法根本不像您手工完成的那样工作,所以真的没有办法.

GSoC 2015年构想:

分步策略

许多SymPy操作背后的逻辑被分成几个小方法。例如,像sin或exp这样的对象有_eval_derivative方法,它们作为SymPy来计算复杂表达式的导数,比如sin(exp(x))。通过捕获所有这些小方法的输入和输出,我们可以收集大量关于SymPy采取的步骤的信息。我们可以看到,exp._eval_derivative接受exp(x)并返回exp(x),sin._eval_derivative接受sin(exp(x))和返回的cos(exp(x))*exp(x)。每个方法的这些输入输出对可能足以说明SymPy如何解决许多领域的问题。

这种捕获许多内部函数输入的方法类似于传统的用于分析大型代码库的日志记录系统。我们应该调查它们是如何工作的,以及它们是否会对正常运行造成任何问题。

一旦这个信息源可用,我们就可以想出有趣的可视化方法和与之交互的方法。一个好的解决方案不会不可避免地将数据流与特定的可视化技术联系在一起。

这种方法在智力上是直截了当的,但可能需要学生与大量代码库进行交互。像_eval_derivative这样的方法在整个SymPy中随处可见,但在不同的模块中往往有很小的变化。

这里是一个在线解决方案SymPy伽玛

票数 8
EN

Stack Overflow用户

发布于 2021-11-05 07:44:49

简单案例的临时解决方案可能基于消去树。在开始时,您可以创建一个表达式树,而不需要计算。之后,您可以逐级修改结果级别:

源代码:

代码语言:javascript
复制
class TraverseSolver:
    def __init__(self, expr):
        self.expr = expr
        
    def _set_graph(self):
        self.G = nx.nx_agraph.from_agraph(pygraphviz.AGraph(sp.dotprint(self.expr))) 
        
    def _set_map(self):
        self._map = dict(zip(self.G.nodes, sp.preorder_traversal(self.expr))) 
        
    def _set_baseNode(self):
        self._baseNode = next(iter(self.G.nodes))
        
    def get_levels(self, mode='draw'):
        if mode == 'draw':
            d = nx.single_source_shortest_path_length(self.G, self._baseNode)
            u, idx = np.unique(list(d.values()), return_index=True)
            levels = [[str(m) for m in n] for n in reversed(np.split(np.array(list(d.keys())), idx[1:]))]
            return levels
        elif mode == 'traverse':
            print(self.G)
    
    def set_color(self, node, color):
        self.G.nodes[node]['color'] = color

    def display_graph(self, fig, n, nshape=(2, 3)):      
        ax = fig.add_subplot(*nshape, n)
        pos = graphviz_layout(self.G, prog='dot')
        colors = nx.get_node_attributes(self.G, 'color')    
        nx.draw(self.G, pos = pos, nodelist=[])
        # draw self.G bbox by bbox:
        for i, n in enumerate(self.G.nodes()):
            nx.draw(nx.subgraph(self.G, [n]), pos={n:pos[n]}, labels = {n:f'${sp.latex(self._map[n])}$'}, nodelist=[],
                    bbox=dict(facecolor=colors[n], edgecolor='black', boxstyle='round,pad=0.7'))
            
    def solve(self, display_graph=True, nshape=(2, 3)):
        self._set_graph() #store sp.srepr+code in each node
        self._set_map() #sp.srepr+code -> expression (without evaluation)
        self._set_baseNode() #sp.srepr+code of self.
        solutionSteps = [self._map[self._baseNode]] #first step that contains initial expression
        levels = self.get_levels(mode='draw')
        if display_graph:
            fig = plt.figure(figsize=(20,10))
        #Step forward
        for i in range(len(levels)):
            if display_graph:
                for node in self.G.nodes(): 
                    self.set_color(node, 'lightblue')
            anyChanges = False
            for activeNode in levels[i]:
                beforeEval = self._map[activeNode]
                if display_graph:
                    self.set_color(activeNode, 'yellow')
                if not beforeEval.is_Atom:
                    afterEval = beforeEval.func(*beforeEval.args, evaluate=True) #is beforeEval different with afterEval
                    if beforeEval != afterEval:
                        self._map[activeNode] = afterEval
                        if display_graph:
                            self.set_color(activeNode, 'lime')
                        anyChanges = True
            # Calculate value of baseNode() using changes, no evaluation      
            if anyChanges:
                for j in range(i+1, len(levels)):
                    for editNode in levels[j]:
                        args = [self._map[node] for node in self.G[editNode]] #each ancestor
                        if not self._map[editNode].is_Atom:
                            self._map[editNode] = self._map[editNode].func(*args, evaluate=False)
                solutionSteps.append(self._map[self._baseNode])
            if display_graph:
                self.display_graph(fig, n=len(solutionSteps), nshape=nshape)
        plt.show()
        return solutionSteps

expr = sp.sympify('-1*(2*3-5*7)', evaluate=False)
steps = TraverseSolver(expr).solve(display_graph=True, nshape=(2, 3))

print('INPUT:', sp.srepr(expr))
print('SOLUTION 1:', ' = '. join([str(step) for step in steps]))
print('SOLUTION 2:', ' = '. join([sp.StrPrinter(dict(order='none'))._print(step) for step in steps])) 

输出:

代码语言:javascript
复制
INPUT: Mul(Integer(-1), Add(Mul(Integer(-1), Mul(Integer(5), Integer(7))), Mul(Integer(2), Integer(3))))
SOLUTION 1: -(-5*7 + 2*3) = -(-1*35 + 2*3) = -(-35 + 6) = -1*(-29) = 29
SOLUTION 2: -(2*3 - 5*7) = -(2*3 - 1*35) = -(6 - 35) = -1*(-29) = 29

要求:networkxmatplotlibpython-graphviz

票数 2
EN

Stack Overflow用户

发布于 2022-04-25 15:29:08

关于graphviz的答案,下面是对源代码的更正。还请注意pygraphviz是pip中的pygraphviz:

代码语言:javascript
复制
import networkx as nx
import matplotlib
import pygraphviz
import sympy as sp
import numpy as np
from matplotlib import pyplot as plt


class TraverseSolver:
    def __init__(self, expr):
        self.expr = expr

    def _set_graph(self):
        self.G = nx.nx_agraph.from_agraph(pygraphviz.AGraph(sp.dotprint(self.expr)))

    def _set_map(self):
        self._map = dict(zip(self.G.nodes, sp.preorder_traversal(self.expr)))

    def _set_baseNode(self):
        self._baseNode = next(iter(self.G.nodes))

    def get_levels(self, mode='draw'):
        if mode == 'draw':
            d = nx.single_source_shortest_path_length(self.G, self._baseNode)
            u, idx = np.unique(list(d.values()), return_index=True)
            levels = [[str(m) for m in n] for n in reversed(np.split(np.array(list(d.keys())), idx[1:]))]
            return levels
        elif mode == 'traverse':
            print(self.G)

    def set_color(self, node, color):
        self.G.nodes[node]['color'] = color

    def display_graph(self, fig, n, nshape=(2, 3)):
        ax = fig.add_subplot(*nshape, n)
        pos = nx.nx_pydot.graphviz_layout(self.G, prog='dot')
        colors = nx.get_node_attributes(self.G, 'color')
        nx.draw(self.G, pos = pos, nodelist=[])
        # draw self.G bbox by bbox:
        for i, n in enumerate(self.G.nodes()):
            nx.draw(nx.subgraph(self.G, [n]), pos={n:pos[n]}, labels = {n:f'${sp.latex(self._map[n])}$'}, nodelist=[],
                    bbox=dict(facecolor=colors[n], edgecolor='black', boxstyle='round,pad=0.7'))

    def solve(self, display_graph=True, nshape=(2, 3)):
        self._set_graph() #store sp.srepr+code in each node
        self._set_map() #sp.srepr+code -> expression (without evaluation)
        self._set_baseNode() #sp.srepr+code of self.
        solutionSteps = [self._map[self._baseNode]] #first step that contains initial expression
        levels = self.get_levels(mode='draw')
        if display_graph:
            fig = plt.figure(figsize=(20,10))
        #Step forward
        for i in range(len(levels)):
            if display_graph:
                for node in self.G.nodes():
                    self.set_color(node, 'lightblue')
            anyChanges = False
            for activeNode in levels[i]:
                beforeEval = self._map[activeNode]
                if display_graph:
                    self.set_color(activeNode, 'yellow')
                if not beforeEval.is_Atom:
                    afterEval = beforeEval.func(*beforeEval.args, evaluate=True) #is beforeEval different with afterEval
                    if beforeEval != afterEval:
                        self._map[activeNode] = afterEval
                        if display_graph:
                            self.set_color(activeNode, 'lime')
                        anyChanges = True
            # Calculate value of baseNode() using changes, no evaluation
            if anyChanges:
                for j in range(i+1, len(levels)):
                    for editNode in levels[j]:
                        args = [self._map[node] for node in self.G[editNode]] #each ancestor
                        if not self._map[editNode].is_Atom:
                            self._map[editNode] = self._map[editNode].func(*args, evaluate=False)
                solutionSteps.append(self._map[self._baseNode])
            if display_graph:
                self.display_graph(fig, n=len(solutionSteps), nshape=nshape)
        plt.show()
        return solutionSteps

expr = sp.simplify('-1*(2*3-5*7)', evaluate=False)
steps = TraverseSolver(expr).solve(display_graph=True, nshape=(2, 3))

print('INPUT:', sp.srepr(expr))
print('SOLUTION 1:', ' = '. join([str(step) for step in steps]))
print('SOLUTION 2:', ' = '. join([sp.StrPrinter(dict(order='none'))._print(step) for step in steps]))
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39359220

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档