#!/usr/local/bin/pythonw
# coding: iso-8859-1
# Copyright © 2009 by Amos Newcombe
# 
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along with this program.  If not, see <http://www.gnu.org/licenses/>.

'''Polynomial
'''

class Polynomial:
	
	def __init__(self, *tpzCoef):
		if not tpzCoef: tpzCoef = (0,)
		if isinstance(tpzCoef[0], (tuple, list)):
			tpzCoef = tuple(tpzCoef[0])
		self.tpzCoef = tpzCoef
	
	def __repr__(self):
		sCoef = ', '.join([`z` for z in self.tpzCoef])
		return '%s(%s)' % (self.__class__.__name__, sCoef)
	
	def __call__(self, z):
		zOut = 0.
		for zCoef in self.tpzCoef: zOut = zOut * z + zCoef
		return zOut
	
	def derivative(self):
		nDegree = len(self.tpzCoef) - 1
		lzD = list(self.tpzCoef)
		for n in range(len(lzD)):
			lzD[n] *= nDegree - n
		return Polynomial(*tuple(lzD[:-1]))
	
	def NewtonInit(self):
		self.D = self.derivative()
	
	def NewtonStep(self, z):
		return z - self(z) / self.D(z)
	
	def Newton(self, z, xEpsilon):
# 		print '%s.Newton(%s, %s) [%s]' % (`self`, z, xEpsilon, self(z))
		c = 0
		self.NewtonInit()
		while (xEpsilon <= abs(self(z))) and (c < 32):
# 			print 'loop: %s, %s, %s' % (z, self(z), c)
			z = self.NewtonStep(z)
			c += 1
		return (z, 32-c)

if __name__ == '__main__':
	
	lsTest = [
		'Polynomial()',
		'Polynomial(0)',
		"Polynomial('foo')",
		'Polynomial(1, 2, 3)',
		'Polynomial([1, 2, 3])',
		'Polynomial(0-1j, 0, 1.)',
	]
	
	cchLim = max([len(s) for s in lsTest])
	z = 2
	for s in lsTest:
		o = eval(s)
		try: zOut = o(z)
		except TypeError: zOut = 0.
		print '%s -> %s(%s) -> %s' % (s.rjust(cchLim), `o`, z, zOut)
	
	o = Polynomial(1, 0, -2)
	print `o`
	print `o.derivative()`
	z, zP = o.Newton(1., 2**-32)
	print z, zP