<commit_before>//
//  Matrix.swift
//  LinearAlgebra
//
//  Created by <NAME> on 04.07.16.
//  Copyright © 2016 pauljohanneskraft. All rights reserved.
//

public struct Matrix < N > : ExpressibleByArrayLiteral, CustomStringConvertible {
	public typealias Element = [N]
	
	public fileprivate(set) var elements : [[N]]
	
	public init(_			 elements: [[N]]	 ) { self.elements = elements; precondition(isRect) }
	public init(arrayLiteral elements: Element...) { self.init(elements)						}
	
	public var isSquare : Bool						{ return elements.count == elements[0].count }
	public var size		: (rows: Int, columns: Int) { return (elements.count, elements[0].count) }
	
	private var isRect : Bool {
		guard elements.count > 0 else { return true }
		/* debugging, in O(rows) */
		let columnCount = elements[0].count
		for e in elements { guard e.count == columnCount else { return false } }
		return true
	}
	
	public var oneLineDescription : String {
		let (c,d) = size
		var desc = "| "
		for i in 0..<c {
			for j in 0..<d { desc += "\(elements[i][j]) " }
			desc += "| "
		}
		desc.characters = desc.characters.dropLast()
		return desc
	}
	
	public var description : String {
		let c = elements.count
		let d = elements[0].count
		var desc = ""
		for i in 0..<c {
			desc += "| "
			for j in 0..<d { desc += "\(elements[i][j]) " }
			desc += "|\n"
		}
		return desc
	}
	
	public subscript(index: Int) -> [N] {
		get { return elements[index] }
		set { elements[index] = newValue }
	}
}

extension Matrix where N : BasicArithmetic {
	
	public static func identity(_ count: Int) -> Matrix<N> {
		var mat = [[N]](repeating: [N](repeating: 0, count: count), count: count)
		for i in 0..<count { mat[i][i] = 1 }
		return Matrix<N> (mat)
	}
	
	public var rank : Int {
		func onlyZeros(_ row: Element) -> Bool {
			for e in row { guard e == 0 else { return false } }
			return true
		}
		
		let rowEchelonForm = self.rowEchelonForm
		var i = rowEchelonForm.size.rows - 1
		// print(rowEchelonForm)
		while i >= 0 {
			// print("checking line", i, ":", rowEchelonForm[i])
			guard onlyZeros(rowEchelonForm[i]) else { return i + 1 }
			i -= 1
		}
		return 0
	}
	
	public var rowEchelonForm : Matrix<N> {
		
		func removeLeadingNumber(row: inout Element, withLine: Element, startAt: Int) {
			let coeff = row[startAt] / withLine[startAt]
			
			if coeff != 0 { for i in startAt ..< row.count { row[i] -= coeff*withLine[i] } }
		}
		
		func divide(row: inout Element, by: N, startAt: Int) {
			assert(by != 0)
			for i in startAt ..< row.count { row[i] /= by }
		}
		
		let size = self.size
		var elements = self.elements
		var column	= 0
		var row		= 0
		
		while column < min(size.rows, size.columns) {
			// looking for element which is not 0 at index "row"
			if elements[row][column] == 0 {
				for i in (row+1) ..< size.rows {
					if elements[i][column] != 0 {
						swap(&elements[row], &elements[i])
						// print("swapped")
						break
					}
				}
			}
			// print("did choose changing row")
			
			if elements[row][column] == 0 { column += 1; continue }
			divide(row: &elements[row], by: elements[row][column], startAt: row)
			for i in (row+1) ..< size.rows {
				removeLeadingNumber(row: &elements[i], withLine: elements[row], startAt: column)
			}
			column += 1
			row += 1
		}
		return Matrix(elements) // TODO!!
	}
	
	public var reducedRowEchelonForm : Matrix<N> {
		
		func subtract(line: [N], from: inout [N], multipliedBy: N = 1) {
			assert(line.count == from.count)
			for i in line.indices { from[i] -= line[i]*multipliedBy }
		}
		
		func onlyZeros(_ row: Element) -> Bool {
			for e in row { guard e == 0 else { return false } }
			return true
		}
		
		var rowEchelonForm = self.rowEchelonForm
		let rows = rowEchelonForm.size.rows
		var i = rows - 1
		
		while i >= 0 {
			if !onlyZeros(rowEchelonForm[i]) {
				for j in 0 ..< i {
					// print("\nbefore:\n", rowEchelonForm, "\n")
					if rowEchelonForm[i][i] != 0 {
						let factor = rowEchelonForm.elements[j][i] / rowEchelonForm.elements[i][i]
						// print(i, j, factor)
						subtract(line: rowEchelonForm.elements[i],
						         from: &rowEchelonForm.elements[j],
						         multipliedBy: factor)
					}
					// print("\nafter:\n", rowEchelonForm, "\n")
				}
			}
			i -= 1
		}
		
		return rowEchelonForm // TODO!!
	}
	
	public var inverse : Matrix<N> {
		assert(isSquare)
		let rows = size.rows
		var two = self
		var id = Matrix<N>.identity(rows)
		for i in two.elements.indices { two.elements[i].append(contentsOf: id.elements[i]) }
		two = two.reducedRowEchelonForm
		let drows = rows << 1
		for i in two.elements.indices { id.elements[i] = two.elements[i][rows..<drows] + [] }
		return id
	}
	
	public var determinant : N {
		assert(isSquare)
		let count = elements.count
		
		switch count {
		case 0: return 1
		case 1: return elements[0][0]
		case 2: return elements[0][0] * elements[1][1] - elements[0][1] * elements[1][0]
		case 3:
			let a = elements[0][0]*elements[1][1]*elements[2][2]
			let b = elements[0][1]*elements[1][2]*elements[2][0]
			let c = elements[0][2]*elements[1][0]*elements[2][1]
			let d = elements[2][0]*elements[1][1]*elements[0][2]
			let e = elements[0][0]*elements[1][2]*elements[2][1]
			let f = elements[0][1]*elements[1][0]*elements[2][2]
			return a + b + c - d - e - f
		default:<commit_msg>[] is no valid matrix any more<commit_after>//
//  Matrix.swift
//  LinearAlgebra
//
//  Created by <NAME> on 04.07.16.
//  Copyright © 2016 pauljohanneskraft. All rights reserved.
//

public struct Matrix < N > : ExpressibleByArrayLiteral, CustomStringConvertible {
	public typealias Element = [N]
	
	public fileprivate(set) var elements : [[N]]
	
	public init(_			 elements: [[N]]	 ) { self.elements = elements; precondition(elements.count > 0 && isRect) }
	public init(arrayLiteral elements: Element...) { self.init(elements)						}
	
	public var isSquare : Bool						{ return elements.count == elements[0].count }
	public var size		: (rows: Int, columns: Int) { return (elements.count, elements[0].count) }
	
	private var isRect : Bool {
		/* debugging, in O(rows) */
		let columnCount = elements[0].count
		for e in elements { guard e.count == columnCount else { return false } }
		return true
	}
	
	public var oneLineDescription : String {
		let (c,d) = size
		var desc = "| "
		for i in 0..<c {
			for j in 0..<d { desc += "\(elements[i][j]) " }
			desc += "| "
		}
		desc.characters = desc.characters.dropLast()
		return desc
	}
	
	public var description : String {
		let c = elements.count
		let d = elements[0].count
		var desc = ""
		for i in 0..<c {
			desc += "| "
			for j in 0..<d { desc += "\(elements[i][j]) " }
			desc += "|\n"
		}
		return desc
	}
	
	public subscript(index: Int) -> [N] {
		get { return elements[index] }
		set { elements[index] = newValue }
	}
}

extension Matrix where N : BasicArithmetic {
	
	public static func identity(_ count: Int) -> Matrix<N> {
		var mat = [[N]](repeating: [N](repeating: 0, count: count), count: count)
		for i in 0..<count { mat[i][i] = 1 }
		return Matrix<N> (mat)
	}
	
	public var rank : Int {
		func onlyZeros(_ row: Element) -> Bool {
			for e in row { guard e == 0 else { return false } }
			return true
		}
		
		let rowEchelonForm = self.rowEchelonForm
		var i = rowEchelonForm.size.rows - 1
		// print(rowEchelonForm)
		while i >= 0 {
			// print("checking line", i, ":", rowEchelonForm[i])
			guard onlyZeros(rowEchelonForm[i]) else { return i + 1 }
			i -= 1
		}
		return 0
	}
	
	public var rowEchelonForm : Matrix<N> {
		
		func removeLeadingNumber(row: inout Element, withLine: Element, startAt: Int) {
			let coeff = row[startAt] / withLine[startAt]
			
			if coeff != 0 { for i in startAt ..< row.count { row[i] -= coeff*withLine[i] } }
		}
		
		func divide(row: inout Element, by: N, startAt: Int) {
			assert(by != 0)
			for i in startAt ..< row.count { row[i] /= by }
		}
		
		let size = self.size
		var elements = self.elements
		var column	= 0
		var row		= 0
		
		while column < min(size.rows, size.columns) {
			// looking for element which is not 0 at index "row"
			if elements[row][column] == 0 {
				for i in (row+1) ..< size.rows {
					if elements[i][column] != 0 {
						swap(&elements[row], &elements[i])
						// print("swapped")
						break
					}
				}
			}
			// print("did choose changing row")
			
			if elements[row][column] == 0 { column += 1; continue }
			divide(row: &elements[row], by: elements[row][column], startAt: row)
			for i in (row+1) ..< size.rows {
				removeLeadingNumber(row: &elements[i], withLine: elements[row], startAt: column)
			}
			column += 1
			row += 1
		}
		return Matrix(elements) // TODO!!
	}
	
	public var reducedRowEchelonForm : Matrix<N> {
		
		func subtract(line: [N], from: inout [N], multipliedBy: N = 1) {
			assert(line.count == from.count)
			for i in line.indices { from[i] -= line[i]*multipliedBy }
		}
		
		func onlyZeros(_ row: Element) -> Bool {
			for e in row { guard e == 0 else { return false } }
			return true
		}
		
		var rowEchelonForm = self.rowEchelonForm
		let rows = rowEchelonForm.size.rows
		var i = rows - 1
		
		while i >= 0 {
			if !onlyZeros(rowEchelonForm[i]) {
				for j in 0 ..< i {
					// print("\nbefore:\n", rowEchelonForm, "\n")
					if rowEchelonForm[i][i] != 0 {
						let factor = rowEchelonForm.elements[j][i] / rowEchelonForm.elements[i][i]
						// print(i, j, factor)
						subtract(line: rowEchelonForm.elements[i],
						         from: &rowEchelonForm.elements[j],
						         multipliedBy: factor)
					}
					// print("\nafter:\n", rowEchelonForm, "\n")
				}
			}
			i -= 1
		}
		
		return rowEchelonForm // TODO!!
	}
	
	public var inverse : Matrix<N> {
		assert(isSquare)
		let rows = size.rows
		var two = self
		var id = Matrix<N>.identity(rows)
		for i in two.elements.indices { two.elements[i].append(contentsOf: id.elements[i]) }
		two = two.reducedRowEchelonForm
		let drows = rows << 1
		for i in two.elements.indices { id.elements[i] = two.elements[i][rows..<drows] + [] }
		return id
	}
	
	public var determinant : N {
		assert(isSquare)
		let count = elements.count
		
		switch count {
		case 1: return elements[0][0]
		case 2: return elements[0][0] * elements[1][1] - elements[0][1] * elements[1][0]
		case 3:
			let a = elements[0][0]*elements[1][1]*elements[2][2]
			let b = elements[0][1]*elements[1][2]*elements[2][0]
			let c = elements[0][2]*elements[1][0]*elements[2][1]
			let d = elements[2][0]*elements[1][1]*elements[0][2]
			let e = elements[0][0]*elements[1][2]*elements[2][1]
			let f = elements[0][1]*elements[1][0]*elements[2][2]
			return a + b + c - d - e - f
		default:
{'fraction_non_alphanumeric': 0.15584292996035493, 'fraction_numerical': 0.01868982442892203, 'mean_word_length': 2.866788321167883, 'pattern_counts': {'":': 2, '<': 47, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1160972', 'n_tokens_mistral': 4465, 'n_tokens_neox': 3760, 'n_words': 1025}