2012-12-05 2 views
4

도메인 특정 수치 계산 라이브러리를 디자인 할 때 사용할 적절한 데이터 형식 (예 : IndexedSeq[Double])을 찾고 있습니다. 이 질문에 대해서는 범위를 1 차원 배열 Double으로 작업하는 것으로 제한합니다. 라이브러리는 일반적으로 1D 배열의 각 요소에 적용되는 숫자 함수를 정의합니다.벡터화 된 수치 계산을위한 최상의 스칼라 컬렉션 유형

고려 사항 :

  • 같은 Vector 또는
  • IndexedSeq은을 사용하여 다른 사람들을 위해 시간과 공간의
  • 합리적으로 효율적인 데이터 변환을 최소화하기 위해
  • 친절한를 원하십니까, 불변의 데이터 유형을 선호 도서관
  • 우아하고 깨끗한 API

Seq과 같이 컬렉션 계층 구조에서 더 높은 값을 사용해야합니까?

아니면 단일 요소 기능을 정의하고 매핑/반복을 최종 사용자에게 맡기는 것이 좋습니다.

이것은 (어떤 계산은 호출 집합마다 한 번 수행 될 수 있기 때문에) 효율성이 떨어지지 만 동시에 모든 유형의 컬렉션에서 작동하므로 더 유연한 API를 사용합니다.

어떤 권장 사항이 있습니까?

+1

값 권투에 문제가있는 경우 [debox] (https://github.com/non/debox)에서 살펴볼 수 있습니다. –

답변

11

계산이 원격으로 계산 집약적 인 작업을 수행하려면 Array을 raw로 사용하거나 자신의 클래스로 래핑하십시오. 콜렉션 호환 랩퍼를 제공 할 수는 있지만 상호 운용성에 대한 명시적인 랩퍼 만 작성하십시오. Array 이외의 모든 것은 일반이므로 상자가 들어가서 비교적 느리고 부피가 커집니다.

Array을 사용하지 않으면 사람들이 갖고있는 모든 것을 포기하고 대신 성능 문제가 발생할 때 Array을 사용해야합니다.아마 괜찮아. 어쩌면 당신은 계산이 편의가 아닌 편리함을 원할 것입니다. 이 경우 인터페이스에 IndexedSeq을 사용하는 것이 좋습니다. 사람들이 색인 생성이 너무 느리지는 않지만 (예 : List이 아님) 사람들에게 알리도록하고 Vector을 사용하는 것이 좋습니다. Array[Double]보다 4 배 더 많은 메모리를 사용하며, 대부분의 저효율 작업 (예 : 곱하기)의 경우 3 ~ 10 배 느립니다. 예를 들어

이 :

val u = v.map(1.0/_) // v is Vector[Double] 

이것보다 약 3 배 느립니다 :

val u = new Array[Double](v.length) 
var j = 0 
while (j<u.length) { 
    u(j) = 1.0/v(j)  // v is Array[Double] 
    j += 1 
} 

당신이 Arraymap 방법을 사용하는 경우는 Vector[Double] 방법만큼 느린; Array의 연산은 일반적이므로 박스로 처리됩니다. (대다수는 벌금이 부과되는 곳입니다.)

3

숫자 값을 처리 할 때 항상 벡터를 사용합니다. 매우 효율적인 랜덤 액세스는 물론 덧셈/덧셈을 제공하기 때문입니다.

불변의 인덱스 된 시퀀스의 현재 기본 컬렉션은 Vector이므로 for (i <- 0 until n) yield {...}과 같은 코드를 작성하면 IndexedSeq[...]을 반환하지만 런타임 유형은 Vector입니다. 따라서 두 개의 시퀀스를 입력으로 사용하는 일부 이진 연산자는 두 개의 인수가 동일한 구현 유형이라는 사실 때문에 이익을 얻을 수 있으므로 항상 벡터를 사용하는 것이 좋습니다. (사실 지금은 아니지만 두 번째 매개 변수가 일반 시퀀스로 처리된다는 사실 때문에 현재 선형 시간과 달리 벡터 연결이 로그 (N) 시간에있을 수 있다고 지적한 사람이 있습니다.

그럼에도 불구하고 나는 Seq[Double]이 필요한 대부분의 기능 인터페이스를 제공해야한다고 생각합니다. 그리고 Range에서 매핑 결과가 Vector을 직접적으로 산출하지 못하기 때문에 보통은 인수 유형으로 Seq[Double]을 입력으로 사용하므로 어떤 일반성을 갖습니다. 효율성은 기본 구현에서 최적화 될 것으로 기대됩니다.

희망이 있습니다.