182 lines
6.8 KiB
Python
Executable File
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())"""
|