Informatique/MPSI/Pivot/main.py
2020-09-01 16:07:00 +02:00

182 lines
6.8 KiB
Python
Executable File

#!/usr/bin/env python3
import random
import fractions
class System():
def __str__(self):
return str('\n'.join([', '.join(list(map(str, i))) for i in self.coeffs]))
def __init__(self, coeffs, quiet=True, text=None, parent=None):
if text:
pass
else:
self.coeffs = [[fractions.Fraction(j) for j in i] for i in coeffs]
self.quiet = quiet
self.parent = parent
self.proper_offset = 0
def crop(self):
self.proper_offset += 1
self.coeffs = [[j for index,j in enumerate(i) if index > 0] for i in self.coeffs]
return self
def triangularise(self):
# Find a good pivot
if len(self.coeffs) == 1:
return self
pivot = 0
for i, line in enumerate(self.coeffs):
if not self.coeffs[pivot][0] or line[0] == 0:
pivot = i
continue
if line[0] == 1:
pivot = i
break
if line[0].denominator == 1:
if line[0] < self.coeffs[pivot][0]:
pivot = i
continue
else:
if line[0].denominator < self.coeffs[pivot][0].denominator:
pivot = i
continue
self.swap(0, pivot)
# If we couldn't find a pivot, the first coeff of each line is 0.
# That means the system is not of the defined dimension.
# Let's fix it.
if self.coeffs[0][0] == 0:
self.crop()
return self.triangularise()
# Cancel the first coefficient of each line
for i in range(1, len(self.coeffs)):
factor = self.coeffs[i][0] / self.coeffs[0][0]
#print()
#print(self)
self.add(i, 0, factor)
#print(self)
#print()
# Triangularise the subsystem
sub = self.subsystem().triangularise()
for i in range(len(sub.coeffs)):
for j in range(len(sub.coeffs[0])):
self.coeffs[i + sub.lineoffset() - self.lineoffset()][j + sub.offset() - self.offset()] = sub.coeffs[i][j]
return self
def add(self, l1, l2, factor):
sl1,sl2 = [self.lineoffset() + i + 1 for i in [l1,l2]]
print("L%s <- L%s + (%s)*L%s"%(str(sl1), str(sl1), str(factor), str(sl2)))
term = [i*factor for i in self.coeffs[l2]]
res = [self.coeffs[l1][i] - term[i] for i in range(len(self.coeffs[0]))]
self.coeffs[l1] = res
return self
def swap(self, l1, l2):
self.coeffs[l1], self.coeffs[l2] = self.coeffs[l2], self.coeffs[1]
return self
def offset(self):
if self.parent:
return self.parent.offset() + self.proper_offset + 1
else:
return self.proper_offset
def lineoffset(self):
if self.parent:
return self.parent.lineoffset() + 1
else:
return 0
def subsystem(self):
print(self)
subcoefs = [[j for j in i[1:]] for i in self.coeffs[1:]]
return self.__class__(subcoefs, parent=self)
k=3
test = System([[fractions.Fraction(str(random.randint(1,50))+'/'+str(1+0*random.randint(1,10))) for j in range(k+1)] for i in range(k)], quiet=False)
print(test.triangularise())
"""class Systeme():
def __str__(self):
return '\n'.join([''.join([((str(self.coeffs[i][j])) + ["x" + str(j+self.offset),"tbcdefghijklmnopqrstuvwxyz"[(j+23+self.offset)%26]][True] + (' + ' if self.coeffs[i][j+1:-1].count(0) == 0 else ' ') if self.coeffs[i][j] else '' ) if j != len(self.coeffs[0]) - 1 else "= " + str(self.coeffs[i][j]) for j in range(len(self.coeffs[0]))]) for i in range(len(self.coeffs))])
def __init__(self, coeffs, quiet=True, text=None, parent=None, offset=0):
if text:
self.coeffs=[list(map(fractions.Fraction, map(int, i.split(',')))) for i in text.split(';')]
else:
self.coeffs = [[fractions.Fraction(j) for j in i] for i in coeffs]
self.quiet=quiet
self.parent=parent
self.offset=offset
def pivot(self, new_pivot):
self.quiet or print("L%s <-> L"%(str(self.offset + 1))+ str(new_pivot+1+self.offset))
self.coeffs[0], self.coeffs[new_pivot] = self.coeffs[new_pivot], self.coeffs[0]
return self
def cancel(self, line):
if line == 0:
return self
if self.coeffs[0][0] == 0:
return self
line_coeff = self.coeffs[line][0] / self.coeffs[0][0]
self.quiet or print("L"+str(line+1+self.offset) + " <- L" + str(line+1+self.offset) + " - ("+str(line_coeff)+")*L"+str(self.offset+1))
self.coeffs[line] = [self.coeffs[line][i] - line_coeff * self.coeffs[0][i] for i in range(len(self.coeffs[line]))]
return self
def solve(self):
self.quiet or print("\nSolving system of dimension : ", len(self.coeffs))
self.quiet or print(self)
if len(self.coeffs) == 1:
return self
#Selecting pivot
pivot = 0
for i in range(len(self.coeffs)):
if self.coeffs[i][0] != 0 and (self.coeffs[i][0] < self.coeffs[pivot][0] or self.coeffs[pivot][0]==0) :
pivot = i
self.pivot(pivot)
#Canceling the first coeffs of each equation (except the first one)
self.quiet or print("\n<=>\n")
for i in range(1, len(self.coeffs)):
self.cancel(i)
self.quiet or print(self)
#Solving the subsystem
for i, line in enumerate(Systeme([[self.coeffs[i][j] for j in range(1, len(self.coeffs[i]))]for i in range(1, len(self.coeffs))], quiet=self.quiet, parent=self, offset=(self.offset+1)).solve().coeffs):
for j in range(len(line)):
self.coeffs[i+1][j+1] = line[j]
self.quiet or print()
return self
def find(self, this):
if self.coeffs[this][:-1].count(0) < len(self.coeffs[this][:-1]) - 1:
self.cleanline(this)
if self.coeffs[this][:-1].count(0) == len(self.coeffs[this][:-1]) - 1:
if self.coeffs[this][this]==1:
return self.coeffs[this][-1]
else:
self.coeffs[this][-1], self.coeffs[this][this] = self.coeffs[this][-1] / self.coeffs[this][this], 1
return self.coeffs[this][-1]
raise Exception("Unicity error")
def cleanline(self, line):
for i in range(len(self.coeffs[line][:-1:])-1, 0-1, -1):
if len(self.coeffs[line][:-1]) - self.coeffs[line][:-1].count(0) <= 1:
return self
if self.coeffs[line][i] !=0:
self.coeffs[line][-1], self.coeffs[line][i]=self.coeffs[line][-1] - self.coeffs[line][i]*self.find(i), 0
return self
def clean(self):
self.find(0)
return self
"""
"""
print(test)
print()
print(test.solve())
print()
print(test.clean())"""