Question

I'm working on an optimization algorithm and need to store some of the data (generated by the algorithm) in a 2-dimensional array called matrix, where row(i) contains the fitness score and parameter values of optimization vector(i).

Dim matrix(vectorCount() - 1, parameterCount()) As Double
Dim params(parameterCount() - 1) As Double

For i As Integer = 0 To vectorCount() - 1
    matrix(i, 0) = vectorScore(i)
    params = vectorValues(i)
    For j As Integer = 0 To params.Length - 1
        matrix(i, j+1) = params(j)
    Next
Next

int vectorCount() returns the number of vectors.
int parameterCount() returns the number of parameters in each vector.
double vectorScore(int vectorIndex) returns the fitness score of a specified vector.
double[] vectorValues(int vectorIndex) returns the parameter values of a specified vector.

My question:
Is there a faster (i.e. more efficient) way to insert params into matrix?

Était-ce utile?

La solution

If you want efficiency, relying on "plain" arrays is undoubtedly the best option. The reason why they are so efficient with respect to other alternatives (Collections, List, etc.) is because they contain the minimum amount of information required. If you want fancy functions allowing to sort the information easily/quickly or write complex queries to retrieve data, you shouldn't rely on arrays.

I always rely on a code like the one you wrote and haven't ever had a speed problem (this is really fast). I have done a quick research to make sure that there is no other option, but couldn't find any. The closest thing you have is Array.Copy, although it works just when the arrays have the same dimensions (I, personally, use it just with 1D arrays). In any case, I found an interesting link about Array.Copy() vs. loop performance for 2D arrays (it is in C# but everything is applicable to VB.NET).

Summary: your code is really fast and does not need to be improved. In case of having a valid alternative (Array.Copy working for 2D and 1D, what does not exist), the resulting performance would be just a bit better (and only for small array sizes).

Autres conseils

If you want to use more than one thread, you can use a parrallel for loop.

http://msdn.microsoft.com/en-us/library/dd460713.aspx

Dim matrix(vectorCount() - 1, parameterCount()) As Double
Dim params(parameterCount() - 1) As Double

Parallel.For(0, vectorCount() - 1, Sub(i)
                                      matrix(i, 0) = vectorScore(i)
                                      params = vectorValues(i)
                                      For j As Integer = 0 To params.Length - 1
                                          matrix(i, j+1) = params(j)
                                      Next
                                   End Sub)

It depends a lot on the size of the array, for loop is very efficient but with very large array you can see improvement with array.copy or buffer.blockcopy.

Sub Main()

    Const ARR_SIZE_X As Integer = 9999999
    Const ARR_SIZE_y As Integer = 5
    Const DBL_SIZE As Integer = 8

    Dim watch As New Stopwatch

    Dim a1(ARR_SIZE_X) As Double
    Dim a2(ARR_SIZE_y, ARR_SIZE_X) As Double

    For x = 0 To ARR_SIZE_X
        a1(ARR_SIZE_X) = x
    Next

    watch.Start()

    For t = 0 To 10
        For y = 0 To ARR_SIZE_y
            For x = 0 To ARR_SIZE_X
                a2(y, x) = a1(x)
            Next
        Next
    Next

    watch.Stop()
    Console.WriteLine(watch.ElapsedTicks)

    watch.Reset()

    watch.Start()

    For t = 0 To 10
        For y = 0 To ARR_SIZE_y
            System.Buffer.BlockCopy(a1, 0, a2, (ARR_SIZE_X + 1) * DBL_SIZE * y, DBL_SIZE * ARR_SIZE_X)
        Next
    Next

    watch.Stop()
    Console.WriteLine(watch.ElapsedTicks)

    'For y = 0 To 4
    '    For x = 0 To 4
    '        Console.Write(a2(y, x))
    '    Next

    '    Console.WriteLine()
    'Next

    Console.ReadLine()

End Sub
Function OneD2TwoD(ByVal xLen As Integer, ByVal yLen As Integer)
    ' (1) populate 1d array
    Dim TwoD(xLen, yLen) As Integer
    Dim OneD((xLen + 1) * (yLen + 1) - 1) As Integer
    For i As Integer = 0 To OneD.GetUpperBound(0)
        OneD(i) = i
    Next
    PrintValues(OneD, "|")
    Console.WriteLine()
    ' (2) Convert 1d array to 2d array/
    Dim z, Row(yLen) As Integer
    For x As Integer = 0 To xLen
        For y As Integer = 0 To yLen
            z = x * (yLen + 1) + y
            TwoD(x, y) = OneD(z)
            Row(y) = TwoD(x, y)
        Next
        PrintValues(Row, "|")
    Next
    Console.WriteLine()
    ' (3) Convert 2d array to 1d array/
    Erase OneD
    ReDim OneD((xLen + 1) * (yLen + 1) - 1)
    For x As Integer = 0 To xLen
        For y As Integer = 0 To yLen
            z = y + x * (yLen + 1)
            OneD(z) = TwoD(x, y)
        Next
    Next
    PrintValues(OneD, "|")
End Function

Public Sub PrintValues(ByVal myList As IEnumerable, ByVal mySeparator As Char)
    ' source: https://msdn.microsoft.com/en-us/library/system.collections.arraylist.add(v=vs.110).aspx
    Dim obj As [Object]
    For Each obj In myList
        Console.Write("{0}{1}", mySeparator, obj)
    Next obj
    Console.WriteLine()
End Sub 'PrintValues

Example for: OneD2TwoD(0, 10)

(1) Populate 1D array

|0|1|2|3|4|5|6|7|8|9|10

(2) Convert 1D array to 2D array

|0|1|2|3|4|5|6|7|8|9|10

(3) Convert 2D array to 1D array

|0|1|2|3|4|5|6|7|8|9|10

Example for: OneD2TwoD(5, 0)

(1) Populate 1D array

|0|1|2|3|4|5

(2) Convert 1D array to 2D array

|0

|1

|2

|3

|4

|5

(3) Convert 2D array to 1D array

|0|1|2|3|4|5

Example for: OneD2TwoD(2, 5)

(1) Populate 1D array

|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17

(2) Convert 1D array to 2D array

| 0| 1| 2| 3| 4| 5

| 6| 7| 8| 9|10|11

|12|13|14|15|16|17

(3) Convert 2D array to 1D array

|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17

Thank you for your attention

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top