trait NDArrayOps[+T <: NDArray] {
/**
* @param shape shape of the result array
* @param values values to fill
* @return new array
*/
def apply(shape: Seq[Int], values: Seq[Float]): T
/**
* Return new array with the given shape.
* If the number of value in `values` does not match to the given `shape`,
* raise `NNException`
*
* @param shape shape of the result array
* @param value values to fill
* @return new array
*/
def fill(shape: Seq[Int], value: Float): T
/**
* Stack the arrays with a one dimension lower along the first axis.
* If there is an array in the values with a different shape,
* then raise `NNException`.
*
* @param values sequence of the same-shaped (N-1)-dim arrays.
* @return new array
*/
def stack(values: Seq[NDArray]): T
}
trait NDArrayOps[+T <: NDArray] { }
가 정의됐는데, 저기에서 +T가 의미는 +T가 NDArray의 subtype임을 의미한다.
T가 아닌 굳이 +T로 적은 이유가 궁금하다. 나중에 찾아봐야징
trait NDArrayOps[+T <: NDArray] {
def apply(shape: Seq[Int], values: Seq[Float]): T
def fill(shape: Seq[Int], value: Float): T
def stack(values: Seq[NDArray]): T
}
일단 NDArrayOps 는 메서드가 상대적으로 적게 정의됐다
apply
fill
stack 이 있는데 각각의 기능을 알아보자.
1. def apply(shape: Seq[Int], values: Seq[Float]): T
shape param에 주어진 Seq[Int]에 따라서 새로운 array를 리턴한다. 약간 NDArray를 생성하는 생성자 느낌
* Return new array with the given shape.
* If the number of value in `values` does not match to the given `shape`, raise `NNException`
* @param shape shape of the result array
* @param values values to fill
* @return new array
*/
2. def fill(shape: Seq[Int], value: Float): T
/**
* Return new array with the given shape.
* If the number of value in `values` does not match to the given `shape`,raise `NNException`
*
* @param shape shape of the result array
* @param value values to fill
* @return new array
*/
...? 아까 apply랑 다른 점이 뭐임
3. def stack(values: Seq[NDArray]): T
* Stack the arrays with a one dimension lower along the first axis.
* If there is an array in the values with a different shape, then raise `NNException`.
*
* @param values sequence of the same-shaped (N-1)-dim arrays.
* @return new array
*/
![](https://t1.daumcdn.net/keditor/emoticon/friends1/large/009.gif)
뭔소린지 하나도 모르겠음ㅋㅋㅋㅋㅋㅋ
일단 Matrix로 넘어가자
object Vector extends NDArrayOps[Vector] {
def apply(values: Seq[Float]): Vector = new Vector(values.toArray)
def apply(shape: Seq[Int], values: Seq[Float]): Vector = {
if (shape.length != 1) {
throw new NNException("the length of the given shape is not 1.")
} else if (shape.head != values.length) {
throw new NNException("the given shape does not equal to the number of values.")
} else {
new Vector(values.toArray)
}
}
def fill(shape: Seq[Int], value: Float): Vector = {
if (shape.length != 1) {
throw new NNException("the length of the given shape is not 1.")
} else {
new Vector(Array.fill(shape.head)(value))
}
}
def stack(values: Seq[NDArray]): Vector =
throw new NNException("There is not an implementation of 0-dim array.")
}
빈칸 채운 버전 :
object Matrix extends NDArrayOps[Matrix] {
def apply(values: Seq[Vector]): Matrix = new Matrix(values.toArray)
def apply(shape: Seq[Int], values: Seq[Float]): Matrix = {
if (shape.length != 2) {
throw new NNException("the length of the given shape is not 2.")
} else if ((shape(0)*shape(1)) != values.length) {
throw new NNException("the given shape does not equal to the number of values.")
} else {
val vec:Vector = new Vector(values.toArray)
vec.reshape(shape:_*)
}
}
def fill(shape: Seq[Int], value: Float): Matrix = {
if (shape.length != 2) {
throw new NNException("the length of the given shape is not 2.")
} else {
val vec:Vector = new Vector(Array.fill(shape(1))(value))
new Matrix(Array.fill(shape.head)(vec))
}
}
def stack(values: Seq[NDArray]): Matrix = {
val stand:Int = values(0).getShape.head
def check(idx:Int=0, res:Boolean=false):Boolean={
if(idx==values.length) res
else{
if((values(idx).ndim != 1) || (values(idx).getShape.head != stand) true
else check(idx+1, res)
}
}
if (check()) throw new NNException("not every value has same shape")
// TODO: check the every value in the values is Vector and has same shape.
else new Matrix(values.asInstanceOf[Seq[Vector]].toArray)
}
}
type mismatch가 떴다...... 하
![](https://t1.daumcdn.net/keditor/emoticon/friends1/large/021.gif)
Vector의 reshape을 정의할 때 사용했던 코드를 가지고 왔다.
// Vector(values:Array[Float])
def reshape(shape: Int*): NDArray = {
def func(x: Array[Float], shape: Int*): NDArray = {
def sep(i: Int, n: Int, res: Array[Float] = Array()): Array[Float] = {
if (n == 0) res
else sep(i + 1, n - 1, res ++ Array(x(i)))
}
val res: Array[Vector] = Array()
for (x <- 1 to shape(0)) {
val a = new Vector(sep((x - 1) * shape(1), shape(1)))
res ++ Array(a)
}
//res 는 Array(Vector)
new Matrix(res)
}
}
func(this.values,shape:_*)
}
def apply(shape: Seq[Int], values: Seq[Float]): Matrix = {
if (shape.length != 2) {
throw new NNException("the length of the given shape is not 2.")
} else if ((shape(0) * shape(1)) != values.length) {
throw new NNException("the given shape does not equal to the number of values.")
} else {
val vec: Vector = new Vector(values.toArray)
vec.reshape(shape: _*)
}
}
![](https://t1.daumcdn.net/keditor/emoticon/friends1/large/027.gif)
def apply(shape: Seq[Int], values: Seq[Float]): Matrix = {
def sep(i: Int, n: Int = shape(1), res: Array[Float] = Array()): Array[Float] = {
if (n == 0) res
else sep(i + 1, n - 1, res ++ Array(values(i)))
}
def fin (idx: Int = 0, result: Array[Vector]= Array()): Array[Vector] = {
if (idx == shape(0)) result
else {
val x: Array[Float] = sep(idx * shape(1))
val y: Vector = new Vector(x)
fin(idx + 1, result ++ Array(y))
}
}
if (shape.length != 2) {
throw new NNException("the length of the given shape is not 2.")
} else if ((shape(0) * shape(1)) != values.length) {
throw new NNException("the given shape does not equal to the number of values.")
} else new Matrix(fin ())
}
최종 apply !!! error는 안뜸.
2차원 배열에 대해서 메서드를 정의하면 된다.
final class Matrix(val values: Array[Vector]) extends NDArray {
val ndim: Int = 2
val getShape: Array[Int] = Array(values.length, values(0).getShape(0))
def getArr(i: Int): Vector = {
if(i>=values.length) NNException("OutOfRange") //should raise an `NNException`
else values(i)
}
def get(i: Int): Float = {
if(values.getShape.length==1) values(i)
else NNException("Not a Vector") //raise NNException
}
def reshape(shape: Int*): NDArray = ???
def reduceLeft[T](f: (Float, Float) => Float): T = ???
def unaryOp(f: Float => Float): NDArray = ???
def binOp(f: (Float, Float) => Float, that: NDArray): NDArray = ???
def equals(that: NDArray): Boolean = ???
}
아 또 reshape 에서 고비를 만났다........
일단 Vector에서 썼던 코드를 참고해보자
매트릭스의 2차원 배열은 모두 일차원으로 바꿔서
매트릭스의 value === Array(Vector)
그 Vector의 value === Array[Float]
메트릭스의 value의 value들을 하나의 Array[Float]으로 만든다음 Vector의 reshape를 사용하면 되지 않을까??
val res:Array[Vector] = this.values
val len = res.length (행의 개수)
val arr:Array[Float] = Array()
for (x <- 0 until len)
arr + res(x).values
def toRow(idx:Int, arr:Array[Float] = Array())={
if(idx==len) arr
else {
toRow(idx+1, arr ++ Array(res(idx).values)
}
}
def reshape(shape: Int*): NDArray = {
val res: Array[Vector] = this.values
val len = res.length
def func(x: Array[Float], shape: Int*): NDArray = {
def sep(i: Int, n: Int, res: Array[Float] = Array()): Array[Float] = {
if (n == 0) res
else sep(i + 1, n - 1, res ++ Array(x(i)))}
if (shape.length == 1) new Vector(x)
else if (shape.length == 2) {
val res: Array[Vector] = Array()
for (x <- 1 to shape(0)) {
val a = new Vector(sep((x - 1) * shape(1), shape(1)))
res ++ Array(a)
}
//res 는 Array(Vector)
new Matrix(res)
}
else {
//3차원 이상은 수정하기
new Vector(x)}}
val length:Int = this.values.length
def toRow(idx: Int, arr: Array[Float] = Array()):Array[Float] = {
if (idx == length) arr
else {
val res:Array[Vector] = this.values
val vect:Vector = res(idx)
val a:Array[Float]= Array(vect.values)
toRow(idx + 1,arr++a)
}
}
func(toRow(0), shape:_*)
}
나중에 차차 검토해보는걸로 하고 ...
reduceLeft로 가보자
/**
* Apply an element-wise binary operator to all elements along the first axis.
* Note that f can be non-associative.
*
* e.g) [[2, 3, 5], [3, 1, 0]].reduceLeft(_ + _) = [5, 4, 5]
* [[1, 2, 3]].reduceLeft(_ + _) = [1, 2, 3]
*
* @param f binary operator
* @tparam T type of the inner element: NDArray (if this is Matrix or StackedArray) or Float (if this is Vector)
* @return see Seq.reduceLeft
*/
def reduceLeft[T](f: (Float, Float) => Float): T = ???
Matrix의 shape이 (n,m)
빈 Array()에 m번 추가함
n은 인덱스느낌이고, shape(0)이랑 비교해서 stop하면 된다.
* e.g) [[2, 3, 5], [3, 1, 0]].reduceLeft(_ + _) = [5, 4, 5]
def reduceLeft[T](f: (Float, Float) => Float): T = ???
type parameter에 대한 이해가 더 필요할 것 같다 ..
val shape = this.getShape //Array[Int] = Array(2,3)
def calculate(idx:Int, arr:Array[T] = Array() ):Array[T] ={
if(idx == shape(0)) arr
else {
val new_arr:Array[T] = arr ++ getArr(idx)
calculate(idx+1,
}
}
'학교 공부 > 프로그래밍원리' 카테고리의 다른 글
HW4-(1) (0) | 2022.12.02 |
---|---|
HW3 -(4) StackedArray 구현하기 (0) | 2022.11.27 |
HW 3- (2) reshape 구현하기 (0) | 2022.11.26 |
HW3 - (1) (0) | 2022.11.25 |
1122 Stacking with Type Classes (0) | 2022.11.22 |