#!/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())"""