Created
May 19, 2023 19:39
-
-
Save JarnaChao09/aed7a12902a386617c05ef23facf4b54 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// missing `}` before catch leads to error saying the code is a macro (???) | |
// unable to pass in dummy Unit struct as the argument list | |
// still errors as empty (???) | |
// unable to get around `Dynamic` use in first arg since it expects | |
// a Tuple and tuple literals do not work currently | |
// struct Unit {} | |
// func test(fun: Lambda<Dynamic, Dynamic, Dynamic>) { | |
// try { | |
// fun.invoke([Unit({})]); | |
// } catch (val e: Dynamic) { | |
// print("caught"); | |
// } | |
// } | |
// test { | |
// print("hello"); | |
// }; | |
// zip must return List<List<T>> where List<T> is Pair<T, T> semantically | |
// Tuple is unable to have generic parameters | |
// Returning Tuples leads to other functions relying on zip | |
// to error on [] access since TupleInitializer.kt does not | |
// have any other functions defined on it | |
func zip<T>(list1: List<T>, list2: List<T>): List<List<T>> { | |
require list1.size == list2.size; | |
var ret = []; | |
range(0, list1.size, :incl_excl).for { | |
ret = ret + [[list1[val], list2[val]]]; | |
}; | |
ensure ret.size == list1.size && ret.size == list2.size; | |
return ret; | |
} | |
struct Vector { | |
val backing: List<Decimal>; | |
func size(this): Integer { | |
return this.backing.size; | |
} | |
// add, sub, mul, and div | |
// could have been generalized with Lambda<T, R, E> | |
// however, .invoke()/.invoke!() on Lambda types leads to | |
// a checked exception error (see test func at top of file) | |
// catching the exception | |
func add(this, other: Vector): Vector { | |
require this.size == other.size; | |
return Vector({ | |
backing: this.backing.|zip(other.backing).map |pair| { | |
// caused NPE despite the lists having valid values at 0 and 1 | |
// pair.first!() + pair.last!() | |
// using .value!() on first() errors with | |
// expected Result found Decimal | |
// initial guess after looking at ListInitializer.kt | |
// is first returns Type.NULLABLE instead of a | |
// Result type | |
pair[0] + pair[1] | |
} | |
}); | |
} | |
func sub(this, other: Vector): Vector { | |
require this.size == other.size; | |
return Vector({ | |
backing: this.backing.|zip(other.backing).map |pair| { | |
pair[0] - pair[1] | |
} | |
}); | |
} | |
func mul(this, other: Vector): Vector { | |
require this.size == other.size; | |
return Vector({ | |
backing: this.backing.|zip(other.backing).map |pair| { | |
pair[0] * pair[1] | |
} | |
}); | |
} | |
func div(this, other: Vector): Vector { | |
require this.size == other.size; | |
for (val i in other.backing) { | |
require i != 0.0; | |
} | |
return Vector({ | |
backing: this.backing.|zip(other.backing).map |pair| { | |
pair[0] / pair[1] | |
} | |
}); | |
} | |
func reduceByAddition(this): Decimal { | |
require this.size != 0; | |
var ret = 0.0; | |
for (val e in this.backing) { | |
ret = ret + e; | |
} | |
return ret; | |
} | |
func dot(this, other: Vector): Decimal { | |
require this.size != 0 && this.size == other.size; | |
// unable to access val.result property | |
// printing out val leads to "{result=0.0, element=xxx}" | |
// return this.mul(other).reduce(0.0) { (val.result) + (val.element) }; | |
return this.mul(other).reduceByAddition(); | |
} | |
} | |
struct Shape { | |
val rows: Integer; | |
val columns: Integer; | |
} | |
struct Matrix { | |
val shape: Shape; | |
val backing: List<Decimal>; | |
// using init block leads to functions saying `this` | |
// is not initialized in rowCount and colCount | |
// error message does not aggregate and stops at the first function | |
// init(literal: List<List<Decimal>>) { | |
// require literal.size > 0; | |
// val rowCount = literal.size; | |
// val colCount = literal[0].size; | |
// var flattened = []; | |
// for (val row in literal) { | |
// require colCount == row.size; | |
// for (val e in row) { | |
// flattened = flattened + [e]; | |
// } | |
// } | |
// this { | |
// shape: Shape({ | |
// rows: rowCount, | |
// columns: colCount, | |
// }), | |
// backing: flattened, | |
// }; | |
// } | |
func rowCount(this): Integer { | |
return this.shape.rows; | |
} | |
func columnCount(this): Integer { | |
return this.shape.columns; | |
} | |
func get(this, r: Integer, c: Integer): Decimal { | |
require r >= 0 && c >= 0; | |
require r * this.columnCount() + c < this.backing.size; | |
return this.backing[r * this.columnCount() + c]; | |
} | |
func getRow(this, r: Integer): Vector { | |
require r >= 0; | |
var backing = []; | |
val startingIndex = r * this.columnCount(); | |
range(startingIndex, startingIndex + this.columnCount(), :incl_excl).for { | |
backing = backing + [this.backing[val]]; | |
}; | |
return Vector({ | |
backing: backing | |
}); | |
} | |
func transpose(this): Matrix { | |
var flattened = []; | |
range(0, this.rowCount(), :incl_excl).for |i| { | |
range(0, this.columnCount(), :incl_excl).for |j| { | |
flattened = flattened + [this.get(j, i)]; | |
}; | |
}; | |
return Matrix({ | |
shape: Shape({ | |
rows: this.columnCount(), | |
columns: this.rowCount(), | |
}), | |
backing: flattened, | |
}); | |
} | |
func matmul(this, other: Matrix): Matrix { | |
require this.columnCount() == other.rowCount(); | |
val newRowCount = this.columnCount(); | |
val newColumnCount = other.rowCount(); | |
val otherT = other.transpose(); | |
var flattened = []; | |
range(0, this.rowCount(), :incl_excl).for |i| { | |
range(0, other.columnCount(), :incl_excl).for |j| { | |
flattened = flattened + [this.getRow(i).dot(otherT.getRow(j))]; | |
}; | |
}; | |
return Matrix({ | |
shape: Shape({ | |
rows: newRowCount, | |
columns: newColumnCount, | |
}), | |
backing: flattened, | |
}); | |
} | |
} | |
// trying to matrix function before definition in source is not possible | |
// Matrix struct will need to create everything with the builtin ctor | |
// since init blocks are causing uninitialized static analysis bug | |
// could be a static function (if possible) | |
func matrix(literal: List<List<Decimal>>): Matrix { | |
require literal.size > 0; | |
val rowCount = literal.size; | |
val colCount = literal[0].size; | |
var flattened = []; | |
for (val row in literal) { | |
require colCount == row.size; | |
for (val e in row) { | |
flattened = flattened + [e]; | |
} | |
} | |
return Matrix({ | |
shape: Shape({ | |
rows: rowCount, | |
columns: colCount, | |
}), | |
backing: flattened, | |
}); | |
} | |
val m1 = [[1.0, 2.0], [3.0, 4.0]].|matrix(); | |
val m2 = [[3.0, 4.0], [5.0, 6.0]].|matrix(); | |
print(m1); | |
print(m1.transpose()); | |
print(""); | |
print(m2); | |
print(m2.transpose()); | |
print(""); | |
print(m1.matmul(m2)); | |
assert m1.matmul(m2) == [[13.0, 16.0], [29.0, 36.0]].|matrix(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment