Factoring, Substituting and printing roots of a polynomial - python

We've been asked to make a program that takes in polynomial coefficients(i.e. [1, 2, 1] representing x^2 + 2x + 1 and use the rational root theorem to find and print the roots in a list of fractional strings. We were only allowed to use import math. The problem with my code is it only works if I input [1, 2, 1] and when I input other polynomials, it prints a blank list.
import math
roots = []
pr = []
pf = []
qf = []
count = 1
t = 0
co = raw_input('Input Coefficients: ')
co = co.split(' ')
p = co[0]
q = co[-1]
def gcd(a,b): #function for computing gcf between two numbers. will be used to simplify fractions into lowest terms
r = a%b
if r == 0:
return b
else:
return gcd(b,r)
def rmvvalues(coefficients, val): #remove the zeroes from the list because zero is not factorable
for i in range(coefficients.count(val)):
coefficients.remove(val)
while int(p) == 0: #if the constant was 0, it means 0 is automatically a root
roots.append(0)
rmvvalues(co, str('0'))
p = co[0]
q = co[-1]
while count <= math.fabs(int(p)): #factors of the constant
if int(p) % count == 0:
pf.append(count)
pf.append(count*(-1))
count = count + 1
else:
count = count + 1
count = 1
while count <= math.fabs(int(q)): #factors of the last term
if int(q) % count == 0:
qf.append(count)
qf.append(count*(-1))
count = count + 1
else:
count = count + 1
count = 1
for i in range(len(pf)): #every element in the first list of factors is to be divided by every element of the other list of factors
for j in range(len(qf)):
result = 0
for c in range(len(co)): #and each pf/qf is to be checked if it would make the polynomial zero
result = int(result) * (int(pf[i])/int(qf[j])) + int(co[c])
if result == 0: #if it makes it zero, it appends the answer in fraction string to the list of roots
if (int(pf[i]) / int(qf[j])) == 1: #add 1 to the list of roots if p/q == 1 and would make the equation zero
roots.append(1)
elif int(pf[i])/int(qf[j]) == -1: #add -1 to the list of roots if p/q == -1 and would make the equation zero
roots.append(-1)
else: #if they would be fractions
a = int(pf[i]) / int(gcd(int(pf[i]),int(qf[j])))
b = int(qf[j]) / int(gcd(int(pf[i]),int(qf[j])))
roots.append(str(a) + '/' +str(b))
roots = sorted(set(roots))
print roots
p.s.(I just copy/pasted the code from my editor so the indentation may be a little off)

I have an implementation to propose, but not a debugging of yours.
The fact is that you are writing a big one bloc code that I don't understand.
As I want to help you I give you an example of implementation that I hope you will find helpful AND readable. My big suggest when coding is to split the code in little function easy to understand with meaningful name, and then add an algorithm function that call all the sub-functions. This make the algorithm to looks like pseudocode and be mode understandable.
Additionally, more specifically related to python, your code is supposed to follow some rule. Runtime code is supposed to be placed after if __name__ == "__main__": bloc.
Hope it helps you (take a look at the findSolution method):
class Polynom():
""" A class representing a polynom that provides methods to find roots of the polynom. """
#-----------------------------------------------------------------------------------------
def __init__(self, coefficients):
"""
Constructor of the class.
Takes a coeficient list [n, n-1, ..., n1, n0] that are the coefficients of a polynom.
Example :
Polynom([1,2,3]) stand for : x² + 2x + 3
"""
self.coefficients = coefficients
#-----------------------------------------------------------------------------------------
def _dividers(self, coefficient):
"""Returns the list of the divider of a number by filtering the values in [1, 2, ... , |coefficient| ] that divide coefficient. """
def filter_dividers(coefficient, candidate_values):
# lambda function explanations : http://www.diveintopython.net/power_of_introspection/lambda_functions.html
return filter(lambda number : coefficient%number == 0, candidate_values)
return list(filter_dividers(coefficient, range(1, abs(coefficient)+1)))
#-----------------------------------------------------------------------------------------
def _gcd(self, x, y):
""" Returns the greatest common diviser of the integers x and y """
if y == 0:
return abs(x)
else:
r = x%y
return self._gcd(y, r)
#-----------------------------------------------------------------------------------------
def _positiveAndNegativeCombinations(self, p_values, q_values):
"""
Returns the list of positives and negatives combination of (p,q) pairs.
Example :
[1,2]
-> [(1,4), (-1,4), (2,4), (-2,4), (1,5), (-1,5), (2,5), (-2,5)]
[4,5]
"""
def combinations(p, q_values):
if len(q_values) == 1:
return [(p, q_values[0])]
else:
return [(p, q_values[0])] + combinations(p, q_values[1:])
result = []
for p in p_values:
p_combinations = combinations(p, q_values)
for combination in p_combinations:
result += [combination, (-1*combination[0], combination[1])]
return result
#-----------------------------------------------------------------------------------------
def __repr__(self):
""" Representation of the object in a string for printing purpose."""
def from_number_to_string_exposant(number):
"""
Returns a string that is the number given as exposant.
Example : 1 -> "¹"
"""
utf8_exposant = {"0":"⁰", "1":"¹", "2":"²", "3": "³", "4":"⁴", "5":"⁵", "6":"⁶", "7":"⁷", "8":"⁸", "9":"⁹"}
string = str(number)
result = ""
for digit in string:
result += utf8_exposant[digit]
return result
result = ""
degree = 0
coefficients = self.coefficients
while coefficients != [] :
coef, coefficients = coefficients[-1], coefficients[0:-1]
result = "+ " +str(coef)+"x"+ from_number_to_string_exposant(degree) + result
degree+=1
return "<Polynom :" + result[1:] + " = 0 >"
#-----------------------------------------------------------------------------------------
def valueFor(self, value):
""" Returns ture or false depending on the fact that the given value is or not a polunom's solution. """
total_value = 0
degree = 0
coefficients = self.coefficients
while coefficients != [] :
coef, coefficients = coefficients[-1], coefficients[0:-1]
total_value += coef*(value**degree)
degree += 1
return total_value
#-----------------------------------------------------------------------------------------
def isSolution(self, value):
""" Returns true or false depending if the given value is a polynom solution or not """
return (self.valueFor(value) == 0)
#-----------------------------------------------------------------------------------------
def findSolution(self):
"""
Return a pair (p,q) that verify that p/q is a solution of this polynom. If no valid pair is find, return None.
Call to this function come with log printing.
"""
print("Search solution for ", self)
a0 = self.coefficients[-1]
aN = self.coefficients[0]
if a0 == 0 or aN == 0:
return None #algorithm is not applicable in this case.
else:
p_values = self._dividers(a0)
q_values = self._dividers(aN)
print("finded dividers of p :", p_values)
print("finded dividers of q :", q_values)
candidate_solutions = self._positiveAndNegativeCombinations(p_values,q_values)
print("(p,q) pairs to evaluate are : \n\t",candidate_solutions)
for candidate in candidate_solutions :
candidate_value = 1.0 * candidate[0] / candidate[1]
print("pair : ",candidate, " | value : ", candidate_value)
if self.isSolution(candidate_value):
print()
return candidate
else:
print("The pair ", candidate, "is invalid, replacing x by it leads to say that 0=", self.valueFor(candidate_value))
return None
#-----------------------------------------------------------------------------------------
if __name__ == "__main__":
poly = Polynom([2,1,-6])
print(poly.findSolution())
Execute it with python3 (or change the print calls).
Arthur.

https://code.activestate.com/recipes/577974-polynomial-factoring-using-rational-root-theorem/
Here's a working link.
from math import ceil
listOfFactors = lambda n: {i for i in range(1,ceil(abs(n)/2)+1) if n%i == 0}
def removeDuplicates(mylist):
if mylist:
mylist.sort()
last = mylist[-1]
for i in range(len(mylist)-2, -1, -1):
if last == mylist[i]:
del mylist[i]
else:
last = mylist[i]
return mylist
def polyRoots(polyListCoeff):
allFactors = set()
allFactorsListOld = list(allFactors.union(listOfFactors(polyListCoeff[0]),{polyListCoeff[0]},listOfFactors(polyListCoeff[-1]),{polyListCoeff[-1]}))
allFactorsListOld.extend([-1*i for i in allFactorsListOld])
allFactorsList = list()
for k in allFactorsListOld:
for j in allFactorsListOld:
allFactorsList.append(k/j)
allFactorsList = removeDuplicates(allFactorsList)
polyListCoeff.reverse()
roots = [i for i in allFactorsList if sum([pow(i,j)*polyListCoeff[j] for j in range(0,len(polyListCoeff))]) == 0]
factorList = list()
for i in roots:
if i<0:
factorList.append("(x+{})".format(-i))
else:
factorList.append("(x-{})".format(i))
return "".join(factorList)
if __name__ == "__main__":
polyRoots([1,0,-4])
# '(x+2.0)(x-2.0)'

Related

Implementing memoization within a Collatz algorithm (Python)

I am trying to perform a Collatz algorithm on the following code. It works fine when I use a range of 1-10 etc... However, if the range is for example 1-500,000 it's too slow and won't ever show me the output of the longest sequence.
numberArray = []
s=int(1)
f=int(10)
def collatz(n):
global count
if n == 1:
count += 1
numberArray.append(count)
return True
elif (n % 2) == 0:
count += 1
collatz(n/2)
else:
count += 1
collatz(3*n+1)
for i in range (s, f+1):
count = 0
ourNumber = i
collatz(i)
print(max(numberArray))
Stef means something like this, which uses a dictionary to memorise the values that have already been counted:
s = 1
f = 10000000
def collatz(n):
if n in collatz.memory:
return collatz.memory[n]
if (n % 2) == 0:
count = collatz(n//2)+1
else:
count = collatz((3*n+1)//2)+2
collatz.memory[n] = count
return count
collatz.memory = {1:0}
highest = max(collatz(i) for i in range(s, f+1))
highest_n = max(collatz.memory, key=collatz.memory.get)
print(f"collatz({highest_n}) is {highest}")
Output:
collatz(8400511) is 685
Use lru_cache decorator. Its function to memorize (cache) the returned value of function called with specific argument.
Also read how to write clean code in python
The next code solves your problem
from functools import lru_cache
number_array = []
s = 1
f = 500000
#lru_cache
def collatz(n: int):
if n == 1:
return 1
elif n % 2 == 0:
return 1 + collatz(n // 2)
else:
return 1 + collatz(3 * n + 1)
for i in range(s, f + 1):
number_array.append(collatz(i))
print(number_array)

Recursion gives me completely wrong answers

I want to find the number of ways, a given integer X can be decomposed into sums of numbers which are N-th powers and every summand must be unique. For example if X = 10 and N=3, I can decompose this number like that:
10 = 2^3+1^3+1^3 ,but this is not a valid decomposition, because the number 1 appears twice. A valid decomposition for X = 10 and N = 2 would be 10 = 3^2+1^2, since no summand is repeating here.
Now I tried it to use recursion and created the following Python Code
st = set(range(1,int(pow(X,1/float(N))))) # generate set of unique numbers
print(str(ps(X, N, st)))
def ps(x, n, s):
res = 0
for c in s:
chk = x-pow(c,n) # test validity
if chk > 0:
ns = s-set([c])
res += ps(chk,n,ns)
elif chk == 0:
res += 1 # one result is found
else:
res += 0 # no valid result
return res
I used a set called st and then I recursively called the function ps that includes the base case "decomposition found" and "decomposition not found". Moreover it reduces a larger number to a smaller one by considering only the ways how to decompose a given number into only two summands.
Unfortunately, I get completely wrong results, e.g.
X = 100, N = 3: Outputs 0, Expected 1
X = 100, N = 2: Outputs 122, Expected 3
X = 10, N = 2: Outputs 0, Expected 1
My thoughts are correct, but I think the Problem is anywhere in the recursion. Does anybody see what I make wrong? Any help would be greatly appreciated.
Hint:
>>> X = 100
>>> N = 3
>>> int(pow(X, 1/float(N)))
4
>>> list(range(1, 4))
[1, 2, 3]
The output is indeed correct for the input you are feeding it.
The problem is line res += 1 # one result is found in conjuction with res += ps(chk,n,ns) will make the algorithm add twice.
E.g X = 10, N = 2: Outputs 0, Expected 1 because:
c=1:
10 - 1^2 > 0 -> res += ps(chk,n,ns)
c=3:
9 - 3^2 == 0 -> res += 1 # one result is found ... return res
So, in c=3 res=1 is returned to the c=1 call, which will
res += ps(chk,n,ns), and ps(chk,n,ns) = 1, making res = 2 and doubling the result expected.
E.g. X = 29, N = 2.
29 = 2^2 + 3^2 + 4^2
Solving from bottom to top (the algorithm flow):
c=4 -> res += 1... return res
c=3 -> res += ps() -> res += 1 -> res = 2 ... return res
c=2 -> res += ps() -> res += 2 -> res = 4 ... return res
But res is supposed to be 1.
Solution: You cannot add res to res. And you must remove the previous iterated objects to avoid path repetition. Check the solution below (with prints for better understanding):
def ps(x, n, s):
print(s)
print("")
return ps_aux(x, n, s, 0) # level
def ps_aux(x, n, s, level):
sum = 0
for idx, c in enumerate(s):
print("----> " * level + "C = {}".format(c))
chk = x - pow(c,n) # test validity
if chk > 0:
ns = s[idx + 1:]
sum += ps_aux(chk,n,ns, level + 1)
elif chk == 0:
print("OK!")
sum += 1 # one result is found
else:
sum += 0 # no valid result
return sum
Try with:
X=10 # 1 solution
N=2
st = list(range(1,int(pow(X,1/float(N))) + 1 )) # generate set of unique numbers
print(str(ps(X, N, st)))
X=25 # 2 solutions [3,4], [5]
N=2
st = list(range(1,int(pow(X,1/float(N))) + 1 )) # generate set of unique numbers
print(str(ps(X, N, st)))

How to add 2 singly-linked lists together?

I am trying to write a Python function that adds two linked lists together. Each node contains one digit of a potentially large integer, with the least-significant digit coming first
Ex Function: add_linked_list_integers(a, b) - where a and b are singly-linked list whose nodes each contain one digit of a positive integer.
Ex Problem: 617 + 295 = 912 would be represented in linked-lists as (7->1->6) + (5->9->2) = (2->1->9).
I am provided with a basic ListNode class, and sample functions to print and create a linked-list of integers.
class ListNode:
'''Simple node for singly-linked list with _value and _next fields'''
def __init__(self, value, next=None):
'''Create a new node, with _value field and optional _next node pointer'''
self._value = value
self._next = next
def print_helper(l):
'''Prints the value of the integer represented by the linked-list l, without trailing carriage return'''
if l:
if (l._value < 0) or (l._value > 9):
raise Exception('digit out of range')
print_helper(l._next)
print(l._value, end="")
def print_linked_list_integer(l):
'''Prints the value of the integer represented by the linked-list l, with trailing carriage return'''
print_helper(l)
print()
def create_linked_list_integer(i):
'''Returns the linked-list representation of the integer i, least-significant digit first'''
result = ListNode(i % 10)
if i >= 10:
result._next = create_linked_list_integer(i // 10)
return result
def add_linked_list_integers(a, b):
'''Return the sum of two integers represented as linked lists
Currently my function looks like this:
def add_linked_list_integers(a, b):
'''Return the sum of two integers represented as linked lists'''
answer = ListNode()
if a == None:
return b
elif b == None:
return a
carry = 0
result = (a.data + b.data + carry)
if result > 9:
result = result - 10
carry = 1
answer.push(result)
return answer
def add_linked_list_integers(a, b):
'''Return the sum of two integers represented as linked lists'''
pre_head = ListNode(-1)
carry = 0
head = pre_head
while a is not None and b is not None:
digit = (a._value + b._value + carry) % 10
carry = (a._value + b._value + carry) // 10
head._next = ListNode(digit)
head = head._next
a = a._next
b = b._next
while a is not None:
digit = (a._value + carry) % 10
carry = (a._value + carry) // 10
head._next = ListNode(digit)
head = head._next
a = a._next
while b is not None:
digit = (b._value + carry) % 10
carry = (b._value + carry) // 10
head._next = ListNode(digit)
head = head._next
b = b._next
if carry != 0:
head._next = ListNode(carry)
return pre_head._next
This is what I would do
Just perform the equivalent of base-10 addition. This means looping over the digits!
from itertools import zip_longest
def add_linked_list_integers(xs, ys):
carry = 0
result = []
for x, y in zip_longest(xs, ys, fillvalue=0):
s = x + y + carry
carry = s // 10
result.append(s % 10)
if carry > 0:
result.append(carry)
return result
Example runs:
>>> add_linked_list_integers([7, 1, 6], [5, 9, 2])
[2, 1, 9]
>>> to_list = lambda y: [int(x) for x in reversed(str(y))]
>>> to_int = lambda xs: int(''.join(str(x) for x in xs)[::-1])
>>> a, b = 3192097619, 999999998472534892
>>> a + b
1000000001664632511
>>> to_int(add_linked_list_integers(to_list(a), to_list(b)))
1000000001664632511

I'm not sure about the last function if its correct

The main function has been written but you need to fill out other
function bodies so that:
The first function takes argument n which signifies the first n terms
of the geometric sequence: { 1, 4, 16,64, 256, … }, adds the terms,
and returns the total of the terms. An example run with 5 for input
would produce: The sum of the geometric series from 1 to 256 is 341
The second function takes argument n which signifies the first n terms of the arithmetic sequence: { 1/3,2/3, 3/3, 4/3, … }, adds the
terms, and returns the total to be displayed in the output.
The third function takes a word and returns True if a word is in reverse alphabetical order, False otherwise; examples of reverse
alphabetical order words are: won, pi, role, ton.
def main():
num = int(input('Enter a number of terms: '))
total = ex4a(num)
print("The sum of the geometric series from 1 to {} is {}".\
format(4 ** (num - 1), total))
total = ex4b(num)
print("The sum of the arithmetic series from 1/3 to {}/3 is {:.5f}".format(num, total))
word = input("Enter a word: ")
isReverse = ex4c(word)
negation = 'not '
if isReverse:
negation = ''
print("The word {} is {}in reverse alphabetical order".format(word, negation))
def ex4a(num):
s = 0
i = 1
for el in range(num):
s += i
i = 4 * i
return s
def ex4b(num):
s = 0
for i in range(num):
s += i / 3
return s
def ex4c(word):
for i in range(len(word) - 1):
if word[i] > word[i + 1]:
return True
else:
return False
Wrong, the function return True if word[i]> word[i+1] for every valid i,
In another word, it return False if any word[i]<=word[i+1]
def ex4c(word):
for i in range(len(word) - 1):
if word[i] <= word[i + 1]:
return False
return True

Largest palindrome which is product of two n-digit numbers (Python)

This is my implementation, but it not efficient when given 6 digit number.
Input : n = 2
Output : 9009
9009 is the largest number which is product of two
2-digit numbers. 9009 = 91*99.
def isPali(x):
n = str(x)
for i in range(len(n)):
if not n[i] == n[-i-1]:
return False
return True
def isProduct(x,A):
counter = A
while counter > 1:
if x // counter <= A and x % counter == 0:
return True
else:
counter-=1
return False
def largestProduct(A):
for i in range(A*A,1,-1):
if isPali(i) and isProduct(i,A):
return i
return False
largestProduct(999999)
Let x and y be the two n-digit factors of the palindrome number.
You can iterate over them in a descending number.
Key is to stop as soon as possible, which mean, once a first solution has been found, you don't check any product below that solution.
def get_max_palindrome(n):
res = 0
for x in range(10 ** n - 1, 1, -1):
for y in range(10 ** n - 1, 1, -1):
p = x * y
if res > p:
break
if str(p) == str(p)[::-1]:
res = p
break
if (x - 1) ** 2 < res:
break
return res
print(get_max_palindrome(6))
Exec in 0.378s on my laptop.
Codewise, this is not too difficult:
n = 999999
max_pali =0
t = ()
for i in range(1,n+1):
for j in range(i,n+1):
m = i*j
s = str(m)
if s == s[::-1] and m > max_pali:
max_pali = m
t = (i,j)
print(max_pali,t)
However, this is a brute force approach. For numbers with 6 digits, this will not terminate in a reasonable amount of time. Even if it will, I could ask you the same question for 7 or 42 digits. I suggest you look for some structure, or property, of those numbers whose multiple is a palindrome. Could such a pair be any pair of numbers? Is the case 91*99 = 9009 a mere coincidence, or is there a pattern?

Categories

Resources