Taylor polynomial calculation - python
I am currently doing a python exercise for my University studies. I am very stuck at this task:
The taylor polynomial of degree N for the exponential function e^x is given by:
N
p(x) = Sigma x^k/k!
k = 0
Make a program that (i) imports class Polynomial (found under), (ii) reads x and a series of N values from the command line, (iii) creates a Polynomial instance representing the Taylor polynomial, and (iv) prints the values of p(x) for the given N values as well as the exact value e^x. Try the program out with x = 0.5, 3, 10 and N = 2, 5, 10, 15, 25.
Polynomial.py
import numpy
class Polynomial:
def __init__(self, coefficients):
self.coeff = coefficients
def __call__(self, x):
"""Evaluate the polynomial."""
s = 0
for i in range(len(self.coeff)):
s += self.coeff[i]*x**i
return s
def __add__(self, other):
# Start with the longest list and add in the other
if len(self.coeff) > len(other.coeff):
result_coeff = self.coeff[:] # copy!
for i in range(len(other.coeff)):
result_coeff[i] += other.coeff[i]
else:
result_coeff = other.coeff[:] # copy!
for i in range(len(self.coeff)):
result_coeff[i] += self.coeff[i]
return Polynomial(result_coeff)
def __mul__(self, other):
c = self.coeff
d = other.coeff
M = len(c) - 1
N = len(d) - 1
result_coeff = numpy.zeros(M+N+1)
for i in range(0, M+1):
for j in range(0, N+1):
result_coeff[i+j] += c[i]*d[j]
return Polynomial(result_coeff)
def differentiate(self):
"""Differentiate this polynomial in-place."""
for i in range(1, len(self.coeff)):
self.coeff[i-1] = i*self.coeff[i]
del self.coeff[-1]
def derivative(self):
"""Copy this polynomial and return its derivative."""
dpdx = Polynomial(self.coeff[:]) # make a copy
dpdx.differentiate()
return dpdx
def __str__(self):
s = ''
for i in range(0, len(self.coeff)):
if self.coeff[i] != 0:
s += ' + %g*x^%d' % (self.coeff[i], i)
# Fix layout
s = s.replace('+ -', '- ')
s = s.replace('x^0', '1')
s = s.replace(' 1*', ' ')
s = s.replace('x^1 ', 'x ')
#s = s.replace('x^1', 'x') # will replace x^100 by x^00
if s[0:3] == ' + ': # remove initial +
s = s[3:]
if s[0:3] == ' - ': # fix spaces for initial -
s = '-' + s[3:]
return s
def simplestr(self):
s = ''
for i in range(0, len(self.coeff)):
s += ' + %g*x^%d' % (self.coeff[i], i)
return s
def _test():
p1 = Polynomial([1, -1])
p2 = Polynomial([0, 1, 0, 0, -6, -1])
p3 = p1 + p2
print p1, ' + ', p2, ' = ', p3
p4 = p1*p2
print p1, ' * ', p2, ' = ', p4
print 'p2(3) =', p2(3)
p5 = p2.derivative()
print 'd/dx', p2, ' = ', p5
print 'd/dx', p2,
p2.differentiate()
print ' = ', p5
p4 = p2.derivative()
print 'd/dx', p2, ' = ', p4
if __name__ == '__main__':
_test()
Now I'm really stuck at this, and I would love to get an explaination! I am supposed to write my code in a separate file. I'm thinking about making an instance of the Polynomial class, and sending in the list in argv[2:], but that doesn't seem to be working. Do I have to make a def to calculate the taylor polynomial for the different values of N before sending it in to the Polynomial class?
Any help is great, thanks in advance :)
Not quite finished, but this answers your main question I believe. Put class Polynomial in poly.p and import it.
from poly import Polynomial as p
from math import exp,factorial
def get_input(n):
''' get n numbers from stdin '''
entered = list()
for i in range(n):
print 'input number '
entered.append(raw_input())
return entered
def some_input():
return [[2,3,4],[4,3,2]]
get input from cmd line
n = 3
a = get_input(n)
b = get_input(n)
#a,b = some_input()
ap = p(a)
bp = p(b)
print 'entered : ',a,b
c = ap+bp
print 'a + b = ',c
print exp(3)
x = ap
print x
sum = p([0])
for k in range(1,5):
el = x
for j in range(1,k):
el el * x
print 'el: ',el
if el!=None and sum!=None:
sum = sum + el
print 'sum ',sum
output
entered : [2, 3, 4] [4, 3, 2]
a + b = 6*1 + 6*x + 6*x^2
20.0855369232
2*1 + 3*x + 4*x^2
sum 2*1 + 3*x + 4*x^2
el: 4*1 + 12*x + 25*x^2 + 24*x^3 + 16*x^4
sum 6*1 + 15*x + 29*x^2 + 24*x^3 + 16*x^4
el: 4*1 + 12*x + 25*x^2 + 24*x^3 + 16*x^4
el: 8*1 + 36*x + 102*x^2 + 171*x^3 + 204*x^4 + 144*x^5 + 64*x^6
sum 14*1 + 51*x + 131*x^2 + 195*x^3 + 220*x^4 + 144*x^5 + 64*x^6
el: 4*1 + 12*x + 25*x^2 + 24*x^3 + 16*x^4
el: 8*1 + 36*x + 102*x^2 + 171*x^3 + 204*x^4 + 144*x^5 + 64*x^6
el: 16*1 + 96*x + 344*x^2 + 792*x^3 + 1329*x^4 + 1584*x^5 + 1376*x^6 + 768*x^7 + 256*x^8
sum 30*1 + 147*x + 475*x^2 + 987*x^3 + 1549*x^4 + 1728*x^5 + 1440*x^6 + 768*x^7 + 256*x^8
I solved the task in the following way, though im not sure if it answers question (iv).
The output just compares the exact value of e**x to the calculated value from module Polynomial.
from math import factorial, exp
from Polynomial import *
from sys import *
#Reads x and N from the command line on the form [filename.py, x-value, N-value]
x = eval(argv[1])
N = eval(argv[2])
#Creating list of coefficients on the form [1 / i!]
list_coeff = [1./factorial(i) for i in range(N)]
print list_coeff
#Creating an instance of class Polynomial
p1 = Polynomial(list_coeff)
print 'Calculated value of e**%f = %f ' %(x, p1.__call__(x))
print 'Exact value of e**%f = %f'% (x, exp(x))
"""Test Execution
Terminal > python Polynomial_exp.py 0.5 5
[1.0, 1.0, 0.5, 0.16666666666666666, 0.041666666666666664]
Calculated value of e**0.500000 = 1.648438
Exact value of e**0.500000 = 1.648721
"""
Related
Fastest way to solve non-negative linear diophantine equations
Let A be a list of n lists of m non-negative integers, such that for all j there is i with A[i][j] nonzero. Let V be a list of m positive integers. Question: What is the fastest way to find all the lists X of n non-negative integers such that for all i then sum_j A[i][j] X[j] = V[i]? The assumptions implies that the number of solutions is finite. See below an example of A and V, with 5499 solutions X. Let me reformulate the problem using matrix and vector. Let A be a n-by-m matrix with non-negative integral entries and without zero column. Let V be a vector with positive integral entries. What is the fastest way to find all the vectors X, with non-negative integral entries, such that AX=V? The usual functions for solving such a system may underuse the non-negativity. To prove so, I wrote a brute-force code finding all the solutions of such a system and applied it to an example (see below, and these crossposts on mathoverflow and on ask.sagemath), but I'm still looking for something significantly faster than this; in fact I'm looking for the fastest way. Example Here is the kind of system I need to solve (where x_i is non-negative integral), but with possibly more equations and variables. [ 5*x0 + 5*x1 + 5*x2 + 6*x3 + 7*x4 + 7*x5 == 24, 5*x1 + 7*x10 + 5*x6 + 5*x7 + 6*x8 + 7*x9 == 25, 5*x11 + 6*x12 + 7*x13 + 7*x14 + 5*x2 + 5*x7 == 25, 5*x12 + 6*x15 + 7*x16 + 7*x17 + 5*x3 + 5*x8 == 30, 5*x13 + 6*x16 + 7*x18 + 7*x19 + 5*x4 + 5*x9 == 35, 5*x10 + 5*x14 + 6*x17 + 7*x19 + 7*x20 + 5*x5 == 35, 5*x1 + 7*x10 + 5*x6 + 5*x7 + 6*x8 + 7*x9 == 25, 5*x21 + 5*x22 + 6*x23 + 7*x24 + 7*x25 + 5*x6 == 24, 5*x22 + 5*x26 + 6*x27 + 7*x28 + 7*x29 + 5*x7 == 25, 5*x23 + 5*x27 + 6*x30 + 7*x31 + 7*x32 + 5*x8 == 30, 5*x24 + 5*x28 + 6*x31 + 7*x33 + 7*x34 + 5*x9 == 35, 5*x10 + 5*x25 + 5*x29 + 6*x32 + 7*x34 + 7*x35 == 35, 5*x11 + 6*x12 + 7*x13 + 7*x14 + 5*x2 + 5*x7 == 25, 5*x22 + 5*x26 + 6*x27 + 7*x28 + 7*x29 + 5*x7 == 25, 5*x11 + 5*x26 + 5*x36 + 6*x37 + 7*x38 + 7*x39 == 24, 5*x12 + 5*x27 + 5*x37 + 6*x40 + 7*x41 + 7*x42 == 30, 5*x13 + 5*x28 + 5*x38 + 6*x41 + 7*x43 + 7*x44 == 35, 5*x14 + 5*x29 + 5*x39 + 6*x42 + 7*x44 + 7*x45 == 35, 5*x12 + 6*x15 + 7*x16 + 7*x17 + 5*x3 + 5*x8 == 30, 5*x23 + 5*x27 + 6*x30 + 7*x31 + 7*x32 + 5*x8 == 30, 5*x12 + 5*x27 + 5*x37 + 6*x40 + 7*x41 + 7*x42 == 30, 5*x15 + 5*x30 + 5*x40 + 6*x46 + 7*x47 + 7*x48 == 35, 5*x16 + 5*x31 + 5*x41 + 6*x47 + 7*x49 + 7*x50 == 42, 5*x17 + 5*x32 + 5*x42 + 6*x48 + 7*x50 + 7*x51 == 42, 5*x13 + 6*x16 + 7*x18 + 7*x19 + 5*x4 + 5*x9 == 35, 5*x24 + 5*x28 + 6*x31 + 7*x33 + 7*x34 + 5*x9 == 35, 5*x13 + 5*x28 + 5*x38 + 6*x41 + 7*x43 + 7*x44 == 35, 5*x16 + 5*x31 + 5*x41 + 6*x47 + 7*x49 + 7*x50 == 42, 5*x18 + 5*x33 + 5*x43 + 6*x49 + 7*x52 + 7*x53 == 48, 5*x19 + 5*x34 + 5*x44 + 6*x50 + 7*x53 + 7*x54 == 49, 5*x10 + 5*x14 + 6*x17 + 7*x19 + 7*x20 + 5*x5 == 35, 5*x10 + 5*x25 + 5*x29 + 6*x32 + 7*x34 + 7*x35 == 35, 5*x14 + 5*x29 + 5*x39 + 6*x42 + 7*x44 + 7*x45 == 35, 5*x17 + 5*x32 + 5*x42 + 6*x48 + 7*x50 + 7*x51 == 42, 5*x19 + 5*x34 + 5*x44 + 6*x50 + 7*x53 + 7*x54 == 49, 5*x20 + 5*x35 + 5*x45 + 6*x51 + 7*x54 + 7*x55 == 48 ] Here are explicit A and V from above system (in list form): A=[ [5,5,5,6,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,5,0,0,0,0,5,5,6,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,5,0,0,0,0,5,0,0,0,5,6,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,5,0,0,0,0,5,0,0,0,5,0,0,6,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,5,0,0,0,0,5,0,0,0,5,0,0,6,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,5,0,0,0,0,5,0,0,0,5,0,0,6,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,5,0,0,0,0,5,5,6,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,6,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,5,6,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,5,0,0,6,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,5,0,0,6,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,5,0,0,6,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,5,0,0,0,0,5,0,0,0,5,6,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,5,6,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,6,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,6,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,6,0,7,7,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,6,0,7,7,0,0,0,0,0,0,0,0,0,0], [0,0,0,5,0,0,0,0,5,0,0,0,5,0,0,6,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,5,0,0,6,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,6,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,6,7,7,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,7,7,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,7,7,0,0,0,0], [0,0,0,0,5,0,0,0,0,5,0,0,0,5,0,0,6,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,5,0,0,6,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,6,0,7,7,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,7,7,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,7,7,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,7,7,0], [0,0,0,0,0,5,0,0,0,0,5,0,0,0,5,0,0,6,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,5,0,0,6,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,6,0,7,7,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,7,7,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,7,7,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,7,7] ] V=[24,25,25,30,35,35,25,24,25,30,35,35,25,25,24,30,35,35,30,30,30,35,42,42,35,35,35,42,48,49,35,35,35,42,49,48] Computation I wrote a brute-force code finding all the solutions of such a system, then applied it to A, V above. It took 12 seconds to find all 5499 solutions. I'm looking for something significantly faster than this. sage: %time LX=NonnegativeSolverPartition(A,V) CPU times: user 11.8 s, sys: 0 ns, total: 11.8 s Wall time: 11.8 s sage: len(LX) 5499 Note that the time reduces to 3 seconds with PyPy3, but it is still too slow for other (bigger) such systems I need to solve. Code Here is my (python) code, improved by Peter Taylor (see his comment): def NonnegativeSolverPartition(A,V): WB = WeakBasis(A) VB = VarBound(A,V) PP = [] for i, ll in WB: L = tuple(A[i][j] for j in ll) B = tuple(VB[j] for j in ll) PP.append(WeightedPartitionSolver(L, B, V[i])) return list(NonnegativeSolverPartitionInter(A, V, PP, WB, [-1] * len(A[0]))) def NonnegativeSolverPartitionInter(A, V, PP, WB, X): if any(len(P) > 1 for P in PP): _, ii = min((len(P), i) for i, P in enumerate(PP) if len(P) > 1) for p in PP[ii]: PPP = PP[:ii] + [[p]] + PP[ii+1:] Fi = Filter(PPP, list(X), WB) if Fi: PPPP, XX = Fi yield from NonnegativeSolverPartitionInter(A, V, PPPP, WB, XX) else: assert -1 not in X yield X def WeakBasis(A): return tuple(enumerate([j for j, tmp in enumerate(row) if tmp] for row in A)) def WeightedPartitions(ws, n): def inner(ws, n): if n == 0: yield (0,) * len(ws) elif ws: w = ws[0] lim = n // w ws = ws[1:] for i in range(lim + 1): for tl in inner(ws, n - w * i): yield (i,) + tl return list(inner(ws, n)) def VarBound(A,V): nvars = len(A[0]) # Solve the individual constraints and then intersect the solutions. possible_values = [None] * nvars row_solns = [] for row, v in zip(A, V): lut = [] ws = [] var_assignments = [] for j, val in enumerate(row): if val: lut.append(j) ws.append(val) var_assignments.append(set()) for soln in WeightedPartitions(ws, v): for i, w in enumerate(soln): var_assignments[i].add(w) for j, assignments in zip(lut, var_assignments): if possible_values[j] is None: possible_values[j] = assignments else: possible_values[j] &= assignments return tuple(frozenset(x) for x in possible_values) def WeightedPartitionSolver(L, B, n): # the entries of L must be non-negative # B gives valid values coming from other equations (see VarBound) def inner(L, B, n): if n == 0: yield (0,) * len(L) elif L: w, allowed = L[0], B[0] L, B = L[1:], B[1:] for i in range(n // w + 1): if i in allowed: for tl in inner(L, B, n - w * i): yield (i,) + tl return list(inner(L, B, n)) def Filter(PP, X, W): if [] in PP: return None while True: for Wi, P in zip(W, PP): F = FixedPoints(P) for j in F: P0j = P[0][j] Wij = Wi[1][j] if X[Wij] == -1: X[Wij] = P0j elif X[Wij] != P0j: return None LL=[] for Wi, P in zip(W, PP): LL.append([p for p in P if not any(X[idx] not in (-1, pval) for idx, pval in zip(Wi[1], p))]) if not LL[-1]: return None if PP == LL: return LL, X PP = LL def FixedPoints(P): # This would prefer P to be transposed m=len(P) n=len(P[0]) return tuple(i for i in range(n) if all(P[j][i] == P[0][i] for j in range(m))) A simpler brute-force code by Max Alekseyev is available in this answer.
How can I form multiple lists from append
I made this code in order that every time it runs once it gives me a list in the correct sequence, I wanted the code to form a list from the repetition forming p1+p2+p3, but the code gives me all the p1 plus all the p2 plus all the p3, I wish every time it ran I was given a list. p11 = [] p22 = [] p33 = [] for n in range(0, quantidade): print('EPISÓDIO', n+1) for g in range(0, prot): p1 = ' ' + protagonistasn[g] + ' ' + random.choice(açoes) + ' ' + random.choice(coadjuvantesn) + ' ' + random.choice(locais) if g <= prot/2 : p1_1 = p1.replace("#","a") p11.append(p1_1) print(p1_1) elif g > prot/2 : p1_1 = p1.replace("#", "o") p11.append(p1_1) print(p1_1) for j in range(0, vil): p2 = ' ' +viloesn[j]+ ' ' + random.choice(açoes) + ' ' + random.choice(protagonistasn) + ' ' + random.choice(locais) if j <= vil/2: p2_2 = p2.replace("#", "a") p22.append(p2_2) print(p2_2) elif j > vil/2: p2_2 = p2.replace("#", "o") p22.append(p2_2) print(p2_2) for h in range(0, prot): p3 = ' ' + protagonistasn[h] + ' ' + random.choice(açoes) + ' ' + random.choice(viloesn) + ' ' + random.choice(locais) if h <= prot/2 : p3_3 = p3.replace("#","a") p33.append(p3_3) print(p3_3) elif h > prot/2 : p3_3 = p3.replace("#", "o") p33.append(p3_3) print(p3_3) p_total = [p11, p22, p33] p_tot = []
If I understand you right, you want your p_total list to contain all the p1s, p2s, and p3s from the first iteration, and then all the p1s, p2s, and p3d from the second iteration. Is that right? If so: p_total = [] for n in range(0, quantidade): p11 = [] p22 = [] p33 = [] print('EPIS?DIO', n+1) for g in range(0, prot): ... print(p3_3) p_total.extend( [p11, p22, p33] ) p_tot = [] So, start each loop with an empty p11, p22, and p33. At the end of each iteration, append those on to your p_total, instead of holding them until the end.
IndexError: invalid index to scalar variable.- PSO algorithm
While trying to solve this problem using PSO algorithm I got the error message as "IndexError: invalid index to scalar variable". Since I am new to PSO algorithm, I am unable to figure out the error. Kindly help me to solve the issue. import random import numpy as np import math import matplotlib.pyplot as plt def fitness_function(position): s1=0.014109786*position[0] + 0.004596846*position[1] + 0.01603721*position[2] + 0.029275618*position[3] + 0.007085358*position[4] + 0.013234328*position[5] + 0.012554958*position[6] + 0.012447232*position[7] + 0.007867602*position[8] + 0.011312568*position[9] + 0.003087858*position[10] + 0.016566954*position[11] + 0.008428942*position[12] + 0.008477444*position[13] + 0.004357354*position[14] s2=0.016566954*position[0] + 0.00585045*position[1] + 0.053172638*position[2] + 0.113404042*position[3] + 0.028190744*position[4] + 0.046330688*position[5] + 0.05629084*position[6] + 0.047796486*position[7] + 0.025793022*position[8] + 0.046164518*position[9] + 0.026696192*position[10] + 0.080422654*position[11] + 0.029074508*position[12] + 0.039611624*position[13] + 0.044835566*position[14] return s1+s2 #Some variables to calculate the velocity W = 0.5 c1 = 0.8 c2 = 0.9 target = 1 n_iterations = int(input("Inform the number of iterations: ")) target_error = float(input("Inform the target error: ")) n_particles = int(input("Inform the number of particles: ")) particle_position_vector=np.array([np.random.uniform(low=0.025, high=0.035) for i in range (n_particles)]) print(particle_position_vector) pbest_position = particle_position_vector pbest_fitness_value = float('inf') gbest_fitness_value = float('inf') gbest_position = np.array([float('inf')for _ in range(n_particles)]) velocity_vector =np.array([0,0,0,0,0,0,0,0,0,0,0,0,0,0]) print(velocity_vector) iteration = 0 while iteration < n_iterations: for i in range(n_particles): fitness_cadidate = fitness_function(particle_position_vector[i]) print(fitness_cadidate, ' ', particle_position_vector[i]) if(pbest_fitness_value[i] > fitness_cadidate): pbest_fitness_value[i] = fitness_cadidate pbest_position[i] = particle_position_vector[i] if(gbest_fitness_value > fitness_cadidate): gbest_fitness_value = fitness_cadidate gbest_position = particle_position_vector[i] if(abs(gbest_fitness_value - target) < target_error): break for i in range(n_particles): new_velocity = (W*velocity_vector[i]) + (c1*random.random()) * (pbest_position[i] - particle_position_vector[i]) + (c2*random.random()) * (gbest_position-particle_position_vector[i]) new_position = new_velocity + particle_position_vector[i] particle_position_vector[i] = new_position iteration = iteration + 1 print("The best position is ", gbest_position, "in iteration number ", iteration)``` ```IndexError Traceback (most recent call last) <ipython-input-35-5610603d3302> in <module> 32 while iteration < n_iterations: 33 for i in range(n_particles): ---> 34 fitness_cadidate = fitness_function(particle_position_vector[i]) 35 print(fitness_cadidate, ' ', particle_position_vector[i]) 36 <ipython-input-35-5610603d3302> in fitness_function(position) 5 6 def fitness_function(position): ----> 7 s1=0.014109786*position[0] + 0.004596846*position[1] + 0.01603721*position[2] + 0.029275618*position[3] + 0.007085358*position[4] + 0.013234328*position[5] + 0.012554958*position[6] + 0.012447232*position[7] + 0.007867602*position[8] + 0.011312568*position[9] + 0.003087858*position[10] + 0.016566954*position[11] + 0.008428942*position[12] + 0.008477444*position[13] + 0.004357354*position[14] 8 s2=0.016566954*position[0] + 0.00585045*position[1] + 0.053172638*position[2] + 0.113404042*position[3] + 0.028190744*position[4] + 0.046330688*position[5] + 0.05629084*position[6] + 0.047796486*position[7] + 0.025793022*position[8] + 0.046164518*position[9] + 0.026696192*position[10] + 0.080422654*position[11] + 0.029074508*position[12] + 0.039611624*position[13] + 0.044835566*position[14] 9 return s1+s2 IndexError: invalid index to scalar variable. Moreover, I want to plot a graph of fitness value with the iteration numbers. Please help me.
numpy.ndarray lambda is not callable within loop when using scipy.minimize_scalar, works fine single-run
I'm working on a piece of code that calculates surface wave velocities. When I run this as a single-shot in my Jupyter notebook it works fine, however when I try to start looping over the phi1 angle, I end up with the 'numpy.ndarray is not callable error' after the zero iteration of the loop. It seems to be focused on the lambda (g) I am using, but I am not sure the best way to go about debugging it. Any help/review would be greatly appreciated as Google searches aren't helping too much. I do apologize for the novel of code, but this is trimmed down to where it should be easily reproducible. ## This code is an implementation of the framework described by M. Cherry et al. in ## Cherry, Matthew R., Shamachary Sathish, and Ramana Grandhi. "A numerical method for predicting Rayleigh surface wave ## velocity in anisotropic crystals." Journal of Computational Physics 351 (2017): 108-120. ## The logic of this code is as follows. ## (1) It then calculates R, T, and Qv (which is the velocity independent Q, needed to determine the velocity range ## over which to search. ## (2) It then iterates to determine the velocity range by changing a variable called 'angle'. ## (3) It then finds a minimum vL, and solves for Q (with velocity as a term), N, A, B, and Z matrices. ## (4) It stores the three Euler angles (p1, P, p2) and RSW_vel ## This does not deal with pseudowaves yet. import matplotlib.pyplot as plt import numpy as np import scipy as sp import scipy.optimize as spo import scipy.linalg as la from scipy.linalg import eig, eigvals import math from decimal import * import time ts1 = time.time() # Setup material properties # Setup the Cij matrix of Ni (units in Pa) C11 = C22 = C33 = 2.41e11 C12 = C13 = C23 = C21 = C31 = C32 = 1.47e11 C14 = C15 = C16 = C24 = C25 = C26 = C34 = C35 = C36 = C41 = C42 = C43 = C51 = C52 = C53 = C61 = C62 = C63 = 0 C44 = C55 = C66 = 1.26e11 C45 = C46 = C56 = C54 = C64 = C65 = 0 Cij_list = np.array([C11,C12,C13,C14,C15,C16,C21,C22,C23,C24,C25,C26,C31,C32,C33,C34,C35,C36,C41,C42,C43,C44,C45,C46,C51,C52,C53,C54,C55,C56,C61,C62,C63,C64,C65,C66]) Cij=Cij_list.reshape(6,6) print('Cij =') print(Cij) # Setup density of Ni (units are in kg/m3) rho = 8910 RSW_matrix = np.array([0,0,0,0]) ## This is where the setting up of the loop for p1, P, and p2 should be. # Setup Euler Angles in Bunge's active notation (one time only - demo, will need to be iterated over), angles in degrees. p1 = phi1, P = Phi, p2 = phi2 #p1 = 15 P = 45 p2 = 8 for rotation in range(0, 180): ## Below this point, everything must be done for every Euler calculation. p1_rad = np.radians(rotation) P_rad = np.radians(P) p2_rad = np.radians(p2) Eul_Ang_deg = np.array([p1,P,p2]) Eul_Ang_rad = np.array([p1_rad,P_rad,p2_rad]) c1 = np.cos(p1_rad) c2 = np.cos(P_rad) c3 = np.cos(p2_rad) s1 = np.sin(p1_rad) s2 = np.sin(P_rad) s3 = np.sin(p2_rad) # Solve Rotation Matrix from Bunge's active notation, and m and n (m is wave propagation vector, n is plane normal) Rot_mat = np.array([[c1*c3-c2*s1*s3,-c1*s3-c2*c3*s1,s1*s2], [c3*s1+c1*c2*s3,c1*c2*c3-s1*s3,-c1*s2], [s2*s3,c3*s2,c2]]) #- could fill in the rest here and just extract col 1 and col 3 print('Rotation Matrix =') print(Rot_mat) m_vec = Rot_mat[[0],:] m1 = Rot_mat[[0],[0]] m2 = Rot_mat[[0],[1]] m3 = Rot_mat[[0],[2]] n_vec = Rot_mat[[2],:] n1 = Rot_mat[[2],[0]] n2 = Rot_mat[[2],[1]] n3 = Rot_mat[[2],[2]] # Below, we calculate R, T and Q matrices # CORRECT R matrix calculations Rij = np.ndarray(shape=(3,3)) Rij[0,0] = C11*m1*n1 + C61*m2*n1 + C51*m3*n1 + C16*m1*n2 + C66*m2*n2 + C56*m3*n2 + C15*m1*n3 + C65*m2*n3 + C55*m3*n3 Rij[0,1] = C16*m1*n1 + C66*m2*n1 + C56*m3*n1 + C12*m1*n2 + C62*m2*n2 + C52*m3*n2 + C14*m1*n3 + C64*m2*n3 + C54*m3*n3 Rij[0,2] = C15*m1*n1 + C65*m2*n1 + C55*m3*n1 + C14*m1*n2 + C64*m2*n2 + C54*m3*n2 + C13*m1*n3 + C63*m2*n3 + C53*m3*n3 Rij[1,0] = C61*m1*n1 + C21*m2*n1 + C41*m3*n1 + C66*m1*n2 + C26*m2*n2 + C46*m3*n2 + C65*m1*n3 + C25*m2*n3 + C45*m3*n3 Rij[1,1] = C66*m1*n1 + C26*m2*n1 + C46*m3*n1 + C62*m1*n2 + C22*m2*n2 + C42*m3*n2 + C64*m1*n3 + C24*m2*n3 + C44*m3*n3 Rij[1,2] = C65*m1*n1 + C25*m2*n1 + C45*m3*n1 + C64*m1*n2 + C24*m2*n2 + C44*m3*n2 + C63*m1*n3 + C23*m2*n3 + C43*m3*n3 Rij[2,0] = C51*m1*n1 + C41*m2*n1 + C31*m3*n1 + C56*m1*n2 + C46*m2*n2 + C36*m3*n2 + C55*m1*n3 + C45*m2*n3 + C35*m3*n3 Rij[2,1] = C56*m1*n1 + C46*m2*n1 + C36*m3*n1 + C52*m1*n2 + C42*m2*n2 + C32*m3*n2 + C54*m1*n3 + C44*m2*n3 + C34*m3*n3 Rij[2,2] = C55*m1*n1 + C45*m2*n1 + C35*m3*n1 + C54*m1*n2 + C44*m2*n2 + C34*m3*n2 + C53*m1*n3 + C43*m2*n3 + C33*m3*n3 Rij_trans = np.transpose(Rij) Rij_inv = np.linalg.inv(Rij) # CORRECT T matrix calculations Tij = np.ndarray(shape=(3,3)) Tij[0,0] = C11*n1*n1 + C16*n2*n1 + C51*n3*n1 + C16*n1*n2 + C66*n2*n2 + C56*n3*n2 + C15*n1*n3 + C65*n2*n3 + C55*n3*n3 Tij[0,1] = C16*n1*n1 + C66*n2*n1 + C56*n3*n1 + C12*n1*n2 + C62*n2*n2 + C52*n3*n2 + C14*n1*n3 + C64*n2*n3 + C54*n3*n3 Tij[0,2] = C15*n1*n1 + C65*n2*n1 + C55*n3*n1 + C14*n1*n2 + C64*n2*n2 + C54*n3*n2 + C13*n1*n3 + C63*n2*n3 + C53*n3*n3 Tij[1,0] = C61*n1*n1 + C21*n2*n1 + C41*n3*n1 + C66*n1*n2 + C26*n2*n2 + C46*n3*n2 + C65*n1*n3 + C25*n2*n3 + C45*n3*n3 Tij[1,1] = C66*n1*n1 + C26*n2*n1 + C46*n3*n1 + C62*n1*n2 + C22*n2*n2 + C42*n3*n2 + C64*n1*n3 + C24*n2*n3 + C44*n3*n3 Tij[1,2] = C65*n1*n1 + C25*n2*n1 + C45*n3*n1 + C64*n1*n2 + C24*n2*n2 + C44*n3*n2 + C63*n1*n3 + C23*n2*n3 + C43*n3*n3 Tij[2,0] = C51*n1*n1 + C41*n2*n1 + C31*n3*n1 + C56*n1*n2 + C46*n2*n2 + C36*n3*n2 + C55*n1*n3 + C45*n2*n3 + C35*n3*n3 Tij[2,1] = C56*n1*n1 + C46*n2*n1 + C36*n3*n1 + C52*n1*n2 + C42*n2*n2 + C32*n3*n2 + C54*n1*n3 + C44*n2*n3 + C34*n3*n3 Tij[2,2] = C55*n1*n1 + C45*n2*n1 + C35*n3*n1 + C54*n1*n2 + C44*n2*n2 + C34*n3*n2 + C53*n1*n3 + C43*n2*n3 + C33*n3*n3 Tij_trans = np.transpose(Tij) Tij_inv = np.linalg.inv(Tij) ## R and T defined as above. Q needs to be new - and not remove the rv2. Thus, we introduce Qv for "Q to determine ## critical velocity" Qv = np.ndarray(shape=(3,3)) Qv[0,0] = C11*m1*m1 + C61*m2*m1 + C51*m3*m1 + C16*m1*m2 + C66*m2*m2 + C56*m3*m2 + C15*m1*m3 + C65*m2*m3 + C55*m3*m3 Qv[0,1] = C16*m1*m1 + C66*m2*m1 + C56*m3*m1 + C12*m1*m2 + C62*m2*m2 + C52*m3*m2 + C14*m1*m3 + C64*m2*m3 + C54*m3*m3 Qv[0,2] = C15*m1*m1 + C65*m2*m1 + C55*m3*m1 + C14*m1*m2 + C64*m2*m2 + C54*m3*m2 + C13*m1*m3 + C63*m2*m3 + C53*m3*m3 Qv[1,0] = C61*m1*m1 + C21*m2*m1 + C41*m3*m1 + C66*m1*m2 + C26*m2*m2 + C46*m3*m2 + C65*m1*m3 + C25*m2*m3 + C45*m3*m3 Qv[1,1] = C66*m1*m1 + C26*m2*m1 + C46*m3*m1 + C62*m1*m2 + C22*m2*m2 + C42*m3*m2 + C64*m1*m3 + C24*m2*m3 + C44*m3*m3 Qv[1,2] = C65*m1*m1 + C25*m2*m1 + C45*m3*m1 + C64*m1*m2 + C24*m2*m2 + C44*m3*m2 + C63*m1*m3 + C23*m2*m3 + C43*m3*m3 Qv[2,0] = C51*m1*m1 + C41*m2*m1 + C31*m3*m1 + C56*m1*m2 + C46*m2*m2 + C36*m3*m2 + C55*m1*m3 + C45*m2*m3 + C35*m3*m3 Qv[2,1] = C56*m1*m1 + C46*m2*m1 + C36*m3*m1 + C52*m1*m2 + C42*m2*m2 + C32*m3*m2 + C54*m1*m3 + C44*m2*m3 + C34*m3*m3 Qv[2,2] = C55*m1*m1 + C45*m2*m1 + C35*m3*m1 + C54*m1*m2 + C44*m2*m2 + C34*m3*m2 + C53*m1*m3 + C43*m2*m3 + C33*m3*m3 res = [] res = spo.minimize_scalar(lambda x: ((min(eigvals(Qv * np.cos(np.radians(x)) * np.cos(np.radians(x)) + (Rij + Rij_trans) * np.cos(np.radians(x)) * np.sin(np.radians(x)) + Tij * np.sin(np.radians(x)) * np.sin(np.radians(x)))) / rho)**(0.5))*(1/(np.abs(np.cos(np.radians(x))))), bracket=(-90,0,90), method='Golden') vel_L = res.fun.real vel_L_int = int(vel_L) print('velocity limit') print(vel_L) print(vel_L_int) Det_B_try = 1 Qij = np.zeros(shape=(3,3)) Qij[0,1] = C16*m1*m1 + C66*m2*m1 + C56*m3*m1 + C12*m1*m2 + C62*m2*m2 + C52*m3*m2 + C14*m1*m3 + C64*m2*m3 + C54*m3*m3 Qij[0,2] = C15*m1*m1 + C65*m2*m1 + C55*m3*m1 + C14*m1*m2 + C64*m2*m2 + C54*m3*m2 + C13*m1*m3 + C63*m2*m3 + C53*m3*m3 Qij[1,0] = C61*m1*m1 + C21*m2*m1 + C41*m3*m1 + C66*m1*m2 + C26*m2*m2 + C46*m3*m2 + C65*m1*m3 + C25*m2*m3 + C45*m3*m3 Qij[1,2] = C65*m1*m1 + C25*m2*m1 + C45*m3*m1 + C64*m1*m2 + C24*m2*m2 + C44*m3*m2 + C63*m1*m3 + C23*m2*m3 + C43*m3*m3 Qij[2,0] = C51*m1*m1 + C41*m2*m1 + C31*m3*m1 + C56*m1*m2 + C46*m2*m2 + C36*m3*m2 + C55*m1*m3 + C45*m2*m3 + C35*m3*m3 Qij[2,1] = C56*m1*m1 + C46*m2*m1 + C36*m3*m1 + C52*m1*m2 + C42*m2*m2 + C32*m3*m2 + C54*m1*m3 + C44*m2*m3 + C34*m3*m3 for v in range(1, vel_L_int): # Calculate rho vel-squared rv2 = rho * v ** 2 # CORRECT Q matrix calculations Qij[0,0] = C11*m1*m1 + C61*m2*m1 + C51*m3*m1 + C16*m1*m2 + C66*m2*m2 + C56*m3*m2 + C15*m1*m3 + C65*m2*m3 + C55*m3*m3 - rv2 Qij[1,1] = C66*m1*m1 + C26*m2*m1 + C46*m3*m1 + C62*m1*m2 + C22*m2*m2 + C42*m3*m2 + C64*m1*m3 + C24*m2*m3 + C44*m3*m3 - rv2 Qij[2,2] = C55*m1*m1 + C45*m2*m1 + C35*m3*m1 + C54*m1*m2 + C44*m2*m2 + C34*m3*m2 + C53*m1*m3 + C43*m2*m3 + C33*m3*m3 - rv2 Qij_trans = np.transpose(Qij) Qij_inv = np.linalg.inv(Qij) # Create a new Nik matrix TR_ik = -1*np.matmul(Tij_inv, Rij_trans) TI_ik = Tij_inv QRTR_ik = -Qij + np.matmul(np.matmul(Rij, Tij_inv), Rij_trans) RT_ik = -1*np.matmul(Rij, Tij_inv) # Nik Creation Nik_r1to3 = np.concatenate((TR_ik,TI_ik),axis=1) Nik_r4to6 = np.concatenate((QRTR_ik,RT_ik),axis=1) Nik_whole = np.concatenate((Nik_r1to3,Nik_r4to6)) # Eigenvalues and Eigenvectors of Nik eigvals, eigvecs = eig(Nik_whole) ## The following code sorts the eigenvalues for those with negative imaginary numbers, and conducts the matrix ## operations to generate the B, A, and Z matrices from the COLUMNS in Pythons representation of eigenvectors eigvecsT = np.transpose(eigvecs) output_ab = output_ab_neg_imag = eigvecsT[eigvals.imag < 0] output_abT = np.transpose(output_ab) ### This is the B matrix (bottom 3 vectors assumed as b) B_matrix = output_b = np.delete(output_abT, [0,1,2], axis=0) B_matrixT = np.transpose(B_matrix) ### This is the A matrix (these are the displacement vectors, and when A is combined with B, the surface impedance (Z) matrix can be found) A_matrix = output_a = np.delete(output_abT, [3,4,5], axis=0) det_B = np.linalg.det(B_matrix) det_cc_B = det_B.conjugate() det_B_x_det_cc_B = det_B*det_cc_B v_real = v.real det_B_x_det_cc_B_real = det_B_x_det_cc_B.real if det_B_x_det_cc_B_real < Det_B_try: RSW_vel = v_real Det_B_try = det_B_x_det_cc_B_real print('RSW =') print(RSW_vel) print('Min |B|x|B|* =') print(Det_B_try) col_to_be_added2 = np.array([p1, P, p2, RSW_vel]) RSW_matrix = np.column_stack((RSW_matrix,col_to_be_added2)) print('RSW vel matrix is') print(RSW_matrix)
print binary tree level by level in python
I want to print my binary tree in the following manner: 10 6 12 5 7 11 13 I have written code for insertion of nodes but can't able to write for printing the tree. so please help on this . My code is : class Node: def __init__(self,data): self.data=data self.left=None self.right=None self.parent=None class binarytree: def __init__(self): self.root=None self.size=0 def insert(self,data): if self.root==None: self.root=Node(data) else: current=self.root while 1: if data < current.data: if current.left: current=current.left else: new=Node(data) current.left=new break; elif data > current.data: if current.right: current=current.right else: new=Node(data) current.right=new break; else: break b=binarytree()
Here's my attempt, using recursion, and keeping track of the size of each node and the size of children. class BstNode: def __init__(self, key): self.key = key self.right = None self.left = None def insert(self, key): if self.key == key: return elif self.key < key: if self.right is None: self.right = BstNode(key) else: self.right.insert(key) else: # self.key > key if self.left is None: self.left = BstNode(key) else: self.left.insert(key) def display(self): lines, *_ = self._display_aux() for line in lines: print(line) def _display_aux(self): """Returns list of strings, width, height, and horizontal coordinate of the root.""" # No child. if self.right is None and self.left is None: line = '%s' % self.key width = len(line) height = 1 middle = width // 2 return [line], width, height, middle # Only left child. if self.right is None: lines, n, p, x = self.left._display_aux() s = '%s' % self.key u = len(s) first_line = (x + 1) * ' ' + (n - x - 1) * '_' + s second_line = x * ' ' + '/' + (n - x - 1 + u) * ' ' shifted_lines = [line + u * ' ' for line in lines] return [first_line, second_line] + shifted_lines, n + u, p + 2, n + u // 2 # Only right child. if self.left is None: lines, n, p, x = self.right._display_aux() s = '%s' % self.key u = len(s) first_line = s + x * '_' + (n - x) * ' ' second_line = (u + x) * ' ' + '\\' + (n - x - 1) * ' ' shifted_lines = [u * ' ' + line for line in lines] return [first_line, second_line] + shifted_lines, n + u, p + 2, u // 2 # Two children. left, n, p, x = self.left._display_aux() right, m, q, y = self.right._display_aux() s = '%s' % self.key u = len(s) first_line = (x + 1) * ' ' + (n - x - 1) * '_' + s + y * '_' + (m - y) * ' ' second_line = x * ' ' + '/' + (n - x - 1 + u + y) * ' ' + '\\' + (m - y - 1) * ' ' if p < q: left += [n * ' '] * (q - p) elif q < p: right += [m * ' '] * (p - q) zipped_lines = zip(left, right) lines = [first_line, second_line] + [a + u * ' ' + b for a, b in zipped_lines] return lines, n + m + u, max(p, q) + 2, n + u // 2 import random b = BstNode(50) for _ in range(50): b.insert(random.randint(0, 100)) b.display() Example output: __50_________________________________________ / \ ________________________43_ ________________________99 / \ / _9_ 48 ____________67_____________________ / \ / \ 3 11_________ 54___ ______96_ / \ \ \ / \ 0 8 ____26___________ 61___ ________88___ 97 / \ / \ / \ 14_ __42 56 64_ 75_____ 92_ / \ / / \ / \ / \ 13 16_ 33_ 63 65_ 72 81_ 90 94 \ / \ \ / \ 25 __31 41 66 80 87 / / 28_ 76 \ 29
class Node(object): def __init__(self, value, left=None, right=None): self.value = value self.left = left self.right = right def printTree(node, level=0): if node != None: printTree(node.left, level + 1) print(' ' * 4 * level + '-> ' + str(node.value)) printTree(node.right, level + 1) t = Node(1, Node(2, Node(4, Node(7)),Node(9)), Node(3, Node(5), Node(6))) printTree(t) output: -> 7 -> 4 -> 2 -> 9 -> 1 -> 5 -> 3 -> 6
What you're looking for is breadth-first traversal, which lets you traverse a tree level by level. Basically, you use a queue to keep track of the nodes you need to visit, adding children to the back of the queue as you go (as opposed to adding them to the front of a stack). Get that working first. After you do that, then you can figure out how many levels the tree has (log2(node_count) + 1) and use that to estimate whitespace. If you want to get the whitespace exactly right, you can use other data structures to keep track of how many spaces you need per level. A smart estimation using number of nodes and levels should be enough, though.
I am leaving here a stand-alone version of #J. V.'s code. If anyone wants to grab his/her own binary tree and pretty print it, pass the root node and you are good to go. If necessary, change val, left and right parameters according to your node definition. def print_tree(root, val="val", left="left", right="right"): def display(root, val=val, left=left, right=right): """Returns list of strings, width, height, and horizontal coordinate of the root.""" # No child. if getattr(root, right) is None and getattr(root, left) is None: line = '%s' % getattr(root, val) width = len(line) height = 1 middle = width // 2 return [line], width, height, middle # Only left child. if getattr(root, right) is None: lines, n, p, x = display(getattr(root, left)) s = '%s' % getattr(root, val) u = len(s) first_line = (x + 1) * ' ' + (n - x - 1) * '_' + s second_line = x * ' ' + '/' + (n - x - 1 + u) * ' ' shifted_lines = [line + u * ' ' for line in lines] return [first_line, second_line] + shifted_lines, n + u, p + 2, n + u // 2 # Only right child. if getattr(root, left) is None: lines, n, p, x = display(getattr(root, right)) s = '%s' % getattr(root, val) u = len(s) first_line = s + x * '_' + (n - x) * ' ' second_line = (u + x) * ' ' + '\\' + (n - x - 1) * ' ' shifted_lines = [u * ' ' + line for line in lines] return [first_line, second_line] + shifted_lines, n + u, p + 2, u // 2 # Two children. left, n, p, x = display(getattr(root, left)) right, m, q, y = display(getattr(root, right)) s = '%s' % getattr(root, val) u = len(s) first_line = (x + 1) * ' ' + (n - x - 1) * '_' + s + y * '_' + (m - y) * ' ' second_line = x * ' ' + '/' + (n - x - 1 + u + y) * ' ' + '\\' + (m - y - 1) * ' ' if p < q: left += [n * ' '] * (q - p) elif q < p: right += [m * ' '] * (p - q) zipped_lines = zip(left, right) lines = [first_line, second_line] + [a + u * ' ' + b for a, b in zipped_lines] return lines, n + m + u, max(p, q) + 2, n + u // 2 lines, *_ = display(root, val, left, right) for line in lines: print(line) print_tree(root) __7 / \ ___10_ 3 / \ _19 13 / \ 9 8_ / \ \ 4 0 12
Simple solution with no recursion def PrintTree(root): def height(root): return 1 + max(height(root.left), height(root.right)) if root else -1 nlevels = height(root) width = pow(2,nlevels+1) q=[(root,0,width,'c')] levels=[] while(q): node,level,x,align= q.pop(0) if node: if len(levels)<=level: levels.append([]) levels[level].append([node,level,x,align]) seg= width//(pow(2,level+1)) q.append((node.left,level+1,x-seg,'l')) q.append((node.right,level+1,x+seg,'r')) for i,l in enumerate(levels): pre=0 preline=0 linestr='' pstr='' seg= width//(pow(2,i+1)) for n in l: valstr= str(n[0].val) if n[3]=='r': linestr+=' '*(n[2]-preline-1-seg-seg//2)+ '¯'*(seg +seg//2)+'\\' preline = n[2] if n[3]=='l': linestr+=' '*(n[2]-preline-1)+'/' + '¯'*(seg+seg//2) preline = n[2] + seg + seg//2 pstr+=' '*(n[2]-pre-len(valstr))+valstr #correct the potition acording to the number size pre = n[2] print(linestr) print(pstr) Sample output 1 /¯¯¯¯¯¯ ¯¯¯¯¯¯\ 2 3 /¯¯¯ ¯¯¯\ /¯¯¯ ¯¯¯\ 4 5 6 7 /¯ ¯\ /¯ /¯ 8 9 10 12
I enhanced Prashant Shukla answer to print the nodes on the same level in the same line without spaces. class Node(object): def __init__(self, value, left=None, right=None): self.value = value self.left = left self.right = right def __str__(self): return str(self.value) def traverse(root): current_level = [root] while current_level: print(' '.join(str(node) for node in current_level)) next_level = list() for n in current_level: if n.left: next_level.append(n.left) if n.right: next_level.append(n.right) current_level = next_level t = Node(1, Node(2, Node(4, Node(7)), Node(9)), Node(3, Node(5), Node(6))) traverse(t)
Just use this small method of print2DTree: class bst: def __init__(self, value): self.value = value self.right = None self.left = None def insert(root, key): if not root: return bst(key) if key >= root.value: root.right = insert(root.right, key) elif key < root.value: root.left = insert(root.left, key) return root def insert_values(root, values): for value in values: root = insert(root, value) return root def print2DTree(root, space=0, LEVEL_SPACE = 5): if (root == None): return space += LEVEL_SPACE print2DTree(root.right, space) # print() # neighbor space for i in range(LEVEL_SPACE, space): print(end = " ") print("|" + str(root.value) + "|<") print2DTree(root.left, space) root = insert_values(None, [8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15]) print2DTree(root) Results:
code Explanation: by using the BFS get the lists of list contains elements of each level number of white spaces at any level = (max number of element in tree)//2^level maximum number of elements of h height tree = 2^h -1; considering root level height as 1 print the value and white spaces find my Riple.it link here print-bst-tree def bfs(node,level=0,res=[]): if level<len(res): if node: res[level].append(node.value) else: res[level].append(" ") else: if node: res.append([node.value]) else: res.append([" "]) if not node: return bfs(node.left,level+1,res) bfs(node.right,level+1,res) return res def printTree(node): treeArray = bfs(node) h = len(treeArray) whiteSpaces = (2**h)-1 def printSpaces(n): for i in range(n): print(" ",end="") for level in treeArray: whiteSpaces = whiteSpaces//2 for i,x in enumerate(level): if i==0: printSpaces(whiteSpaces) print(x,end="") printSpaces(1+2*whiteSpaces) print() #driver Code printTree(root) #output
class magictree: def __init__(self, parent=None): self.parent = parent self.level = 0 if parent is None else parent.level + 1 self.attr = [] self.rows = [] def add(self, value): tr = magictree(self) tr.attr.append(value) self.rows.append(tr) return tr def printtree(self): def printrows(rows): for i in rows: print("{}{}".format(i.level * "\t", i.attr)) printrows(i.rows) printrows(self.rows) tree = magictree() group = tree.add("company_1") group.add("emp_1") group.add("emp_2") emp_3 = group.add("emp_3") group = tree.add("company_2") group.add("emp_5") group.add("emp_6") group.add("emp_7") emp_3.add("pencil") emp_3.add("pan") emp_3.add("scotch") tree.printtree() result: ['company_1'] ['emp_1'] ['emp_2'] ['emp_3'] ['pencil'] ['pan'] ['scotch'] ['company_2'] ['emp_5'] ['emp_6'] ['emp_7']
As I came to this question from Google (and I bet many others did too), here is binary tree that has multiple children, with a print function (__str__ which is called when doing str(object_var) and print(object_var)). Code: from typing import Union, Any class Node: def __init__(self, data: Any): self.data: Any = data self.children: list = [] def insert(self, data: Any): self.children.append(Node(data)) def __str__(self, top: bool=True) -> str: lines: list = [] lines.append(str(self.data)) for child in self.children: for index, data in enumerate(child.__str__(top=False).split("\n")): data = str(data) space_after_line = " " * index if len(lines)-1 > index: lines[index+1] += " " + data if top: lines[index+1] += space_after_line else: if top: lines.append(data + space_after_line) else: lines.append(data) for line_number in range(1, len(lines) - 1): if len(lines[line_number + 1]) > len(lines[line_number]): lines[line_number] += " " * (len(lines[line_number + 1]) - len(lines[line_number])) lines[0] = " " * int((len(max(lines, key=len)) - len(str(self.data))) / 2) + lines[0] return '\n'.join(lines) def hasChildren(self) -> bool: return bool(self.children) def __getitem__(self, pos: Union[int, slice]): return self.children[pos] And then a demo: # Demo root = Node("Languages Good For") root.insert("Serverside Web Development") root.insert("Clientside Web Development") root.insert("For Speed") root.insert("Game Development") root[0].insert("Python") root[0].insert("NodeJS") root[0].insert("Ruby") root[0].insert("PHP") root[1].insert("CSS + HTML + Javascript") root[1].insert("Typescript") root[1].insert("SASS") root[2].insert("C") root[2].insert("C++") root[2].insert("Java") root[2].insert("C#") root[3].insert("C#") root[3].insert("C++") root[0][0].insert("Flask") root[0][0].insert("Django") root[0][1].insert("Express") root[0][2].insert("Ruby on Rails") root[0][0][0].insert(1.1) root[0][0][0].insert(2.1) print(root)
This is part of my own implementation of BST. The ugly part of this problem is that you have to know the space that your children occupies before you can print out yourself. Because you can have very big numbers like 217348746327642386478832541267836128736..., but also small numbers like 10, so if you have a parent-children relationship between these two, then it can potentially overlap with your other child. Therefore, we need to first go through the children, make sure we get how much space they are having, then we use that information to construct ourself. def __str__(self): h = self.getHeight() rowsStrs = ["" for i in range(2 * h - 1)] # return of helper is [leftLen, curLen, rightLen] where # leftLen = children length of left side # curLen = length of keyStr + length of "_" from both left side and right side # rightLen = children length of right side. # But the point of helper is to construct rowsStrs so we get the representation # of this BST. def helper(node, curRow, curCol): if(not node): return [0, 0, 0] keyStr = str(node.key) keyStrLen = len(keyStr) l = helper(node.l, curRow + 2, curCol) rowsStrs[curRow] += (curCol -len(rowsStrs[curRow]) + l[0] + l[1] + 1) * " " + keyStr if(keyStrLen < l[2] and (node.r or (node.p and node.p.l == node))): rowsStrs[curRow] += (l[2] - keyStrLen) * "_" if(l[1]): rowsStrs[curRow + 1] += (len(rowsStrs[curRow + 2]) - len(rowsStrs[curRow + 1])) * " " + "/" r = helper(node.r, curRow + 2, len(rowsStrs[curRow]) + 1) rowsStrs[curRow] += r[0] * "_" if(r[1]): rowsStrs[curRow + 1] += (len(rowsStrs[curRow]) - len(rowsStrs[curRow + 1])) * " " + "\\" return [l[0] + l[1] + 1, max(l[2] - keyStrLen, 0) + keyStrLen + r[0], r[1] + r[2] + 1] helper(self.head, 0, 0) res = "\n".join(rowsStrs) #print("\n\n\nStart of BST:****************************************") #print(res) #print("End of BST:****************************************") #print("BST height: ", h, ", BST size: ", self.size) return res Here's some examples of running this: [26883404633, 10850198033, 89739221773, 65799970852, 6118714998, 31883432186, 84275473611, 25958013736, 92141734773, 91725885198, 131191476, 81453208197, 41559969292, 90704113213, 6886252839] 26883404633___________________________________________ / \ 10850198033__ 89739221773___________________________ / \ / \ 6118714998_ 25958013736 65799970852_______________ 92141734773 / \ / \ / 131191476 6886252839 31883432186_ 84275473611 91725885198 \ / / 41559969292 81453208197 90704113213 Another example: ['rtqejfxpwmggfro', 'viwmdmpedzwvvxalr', 'mvvjmkdcdpcfb', 'ykqehfqbpcjfd', 'iuuujkmdcle', 'nzjbyuvlodahlpozxsc', 'wdjtqoygcgbt', 'aejduciizj', 'gzcllygjekujzcovv', 'naeivrsrfhzzfuirq', 'lwhcjbmcfmrsnwflezxx', 'gjdxphkpfmr', 'nartcxpqqongr', 'pzstcbohbrb', 'ykcvidwmouiuz'] rtqejfxpwmggfro____________________ / \ mvvjmkdcdpcfb_____________________________ viwmdmpedzwvvxalr_______________ / \ \ iuuujkmdcle_________ nzjbyuvlodahlpozxsc_ ykqehfqbpcjfd / \ / \ / aejduciizj_____________ lwhcjbmcfmrsnwflezxx naeivrsrfhzzfuirq_ pzstcbohbrb wdjtqoygcgbt_ \ \ \ gzcllygjekujzcovv nartcxpqqongr ykcvidwmouiuz / gjdxphkpfmr
Here's a 2-pass solution with no recursion for general binary trees where each node has a value that "fits" within the allotted space (values closer to the root have more room to spare). (Pass 0 computes the tree height). ''' 0: 0 1: 1 2 2: 3 4 5 6 3: 7 8 9 a b c d e h: 4 N: 2**4 - 1 <--| 2**0 + 2**1 + 2**2 + 2**3 ''' import math def t2_lvl( i): return int(math.log2(i+1)) if 0<i else 0 # #meta map the global idx to the lvl def t2_i2base(i): return (1<<t2_lvl(i))-1 # #meta map the global idx to the local idx (ie. the idx of elem 0 in the lvl at idx #i) def t2_l2base(l): return (1<< l) -1 # #meta map the lvl to the local idx (ie. the idx of elem 0 in lvl #l) class Tree2: # #meta a 2-tree is a tree with at most 2 sons per dad def __init__(self, v=None): self.v = v self.l = None self.r = None def __str__(self): return f'{self.v}' def t2_show(tree:Tree2): # #meta 2-pass fn. in the 1st pass we compute the height if not tree: return q0 = [] # perm queue q1 = [] # temp queue # pass 0 h = 0 # height is the number of lvls q0.append((tree,0)) q1.append((tree,0)) while q1: n,i = q1.pop(0) h = max(h, t2_lvl(i)) if n.l: l=(n.l, 2*i+1); q0.append(l); q1.append(l) if n.r: r=(n.r, 2*i+2); q0.append(r); q1.append(r) h += 1 # nlvls N = 2**h - 1 # nelems (for a perfect tree of this height) W = 1 # elem width # pass 1 print(f'\n\x1b[31m{h} \x1b[32m{len(q0)}\x1b[0m') print(f'{0:1x}\x1b[91m:\x1b[0m',end='') for idx,(n,i) in enumerate(q0): l = t2_lvl(i) # lvl b = (1<<l)-1 # base s0 = (N // (2**(l+1))) s1 = (N // (2**(l+0))) s = 3+1 + s0 + (i-b)*(s1+1) # absolute 1-based position (from the beginning of line) w = int(2**(h-l-2)) # width (around the element) (to draw the surrounding #-) # print(f'{i:2x} {l} {i-b} {s0:2x} {s1:2x} {s:2x} {w:x} {n.v:02x}') if 0<idx and t2_lvl(q0[idx-1][1])!=l: print(f'\n{l:1x}\x1b[91m:\x1b[0m',end='') # new level: go to the next line print(f"\x1b[{s-w}G{w*'-'}\x1b[1G", end='') print(f"\x1b[{s}G{n.v:1x}\x1b[1G", end='') # `\x1b[XG` is an ANSI escape code that moves the cursor to column X print(f"\x1b[{s+W}G{w*'-'}\x1b[1G", end='') print() And an example: tree = Tree2(0) tree.l = Tree2(1) tree.r = Tree2(2) tree.l.l = Tree2(3) tree.r.l = Tree2(4) tree.r.r = Tree2(5) tree.l.l.l = Tree2(3) tree.r.l.l = Tree2(6) tree.r.l.r = Tree2(7) tree.l.l.l.l = Tree2(3) tree.r.l.l.l = Tree2(8) tree.r.l.l.r = Tree2(9) t2_show(tree) Output: 5 12 0: --------0-------- 1: ----1---- ----2---- 2: --3-- --4-- --5-- 3: -3- -6- -7- 4: 3 8 9 Another output example: 7 127 0: --------------------------------0-------------------------------- 1: ----------------1---------------- ----------------2---------------- 2: --------3-------- --------4-------- --------5-------- --------6-------- 3: ----7---- ----8---- ----9---- ----a---- ----b---- ----c---- ----d---- ----e---- 4: --f-- --0-- --1-- --2-- --3-- --4-- --5-- --6-- --7-- --8-- --9-- --a-- --b-- --c-- --d-- --e-- 5: -f- -0- -1- -2- -3- -4- -5- -6- -7- -8- -9- -a- -b- -c- -d- -e- -f- -0- -1- -2- -3- -4- -5- -6- -7- -8- -9- -a- -b- -c- -d- -e- 6: f 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 8 9 a b c d e
Record Each Level Separately using Breadth First Approach You can use a breadth first traversal and record node values in a dictionary using level as key. This helps next when you want to print each level in a new line. If you maintain a count of nodes processed, you can find current node's level (since it's a binary tree) using - level = math.ceil(math.log(count + 1, 2) - 1) Sample Code Here's my code using the above method (along with some helpful variables like point_span & line_space which you can modify as you like). I used my custom Queue class, but you can also use a list for maintaining queue. def pretty_print(self): q, current, count, level, data = Queue(), self.root, 1, 0, {} while current: level = math.ceil(math.log(count + 1, 2) - 1) if data.get(level) is None: data[level] = [] data[level].append(current.value) count += 1 if current.left: q.enqueue(current.left) if current.right: q.enqueue(current.right) current = q.dequeue() point_span, line_space = 8, 4 line_width = int(point_span * math.pow(2, level)) for l in range(level + 1): current, string = data[l], '' for c in current: string += str(c).center(line_width // len(current)) print(string + '\n' * line_space) And here's how the output looks:
Similar question is being answered over here This may help following code will print in this format >>> 1 2 3 4 5 6 7 >>> Code for this is as below : class Node(object): def __init__(self, value, left=None, right=None): self.value = value self.left = left self.right = right def traverse(rootnode): thislevel = [rootnode] a = ' ' while thislevel: nextlevel = list() a = a[:len(a)/2] for n in thislevel: print a+str(n.value), if n.left: nextlevel.append(n.left) if n.right: nextlevel.append(n.right) print thislevel = nextlevel t = Node(1, Node(2, Node(4, Node(7)),Node(9)), Node(3, Node(5), Node(6))) traverse(t) Edited code gives result in this format : >>> 1 2 3 4 9 5 6 7 >>> This is just a trick way to do what you want their maybe a proper method for that I suggest you to dig more into it.