How to sort the indices of Slice<UnsafeMutableBufferPointer<Double>> using vDSP?

I’m using buffer in many other vDSP operations before the code below. To those operations it is naturally a contiguous piece of memory, and that’s handy as there are vastly reduced number of calls to vDSP.


// […] many operations with buffer here


var buffer = UnsafeMutableBufferPointer<Double>.allocate(capacity: 10000000)

var sortedIndices: UnsafeMutablePointer<UInt> = UnsafeMutablePointer<UInt>.allocate(capacity: 10000000)

for (indexIndices, indexC) in buffer.indices.enumerated() {
    sortedIndices[indexIndices] = UInt(indexC)
}

vDSP_vsortiD(
    UnsafePointer<Double>(buffer.baseAddress)!, 
    sortedIndices, 
    nil, 
    UInt(buffer.count), 
    vDSP.SortOrder.descending.rawValue
)

buffer needs to be sorted sliced up (a grouped sort, where each Slice corresponds to some special attribute of the value and it needs to be sorted separately because the resulting data is used separately later).

Also, copying the buffer’s contents into smaller buffers before every sort has to be avoided as performance is critical (as many times as possible per second).

vDSP_vsortiD() and vDSP_vsorti() do not support Slice.

For example this code is not possible since .baseAddress doesn’t exist on a Slice and I guess UnsafePointer doesn’t understand Slice either.

var sliceOfBuffer: Slice<UnsafeMutableBufferPointer<Double>> = buffer[0...30000]

vDSP_vsortiD(
    UnsafePointer<Double>(sliceOfBuffer.baseAddress)!, // This fails
    sortedIndices[0...30000], // This also fails
    nil, 
    UInt(30000), 
    vDSP.SortOrder.descending.rawValue
)

// Is there another sort indices function which accepts those types as params?

Many operations under vDSP accept Slice, however the above sort functions don’t.

Swift v5.6

Answered by Oxygens in 729406022

This question was answered on SO.

Adding Martin R’s answer with his permission:

You can use withUnsafeBufferPointer() to pass the address of the slice's element storage to the vDSP function:

sliceOfBuffer.withUnsafeBufferPointer { bp in
    vDSP_vsortiD(
        bp.baseAddress!,
        sortedIndices,
        nil,
        UInt(sliceOfBuffer.count),
        vDSP.SortOrder.descending.rawValue
    )
}

With respect to slicing the indices: It seems that one can pass sortedIndices + sliceOfBuffer.startIndex to the vDSP function. However, the documentation states that the indices must be initialized starting at zero, so I would not rely on that.

Accepted Answer

This question was answered on SO.

Adding Martin R’s answer with his permission:

You can use withUnsafeBufferPointer() to pass the address of the slice's element storage to the vDSP function:

sliceOfBuffer.withUnsafeBufferPointer { bp in
    vDSP_vsortiD(
        bp.baseAddress!,
        sortedIndices,
        nil,
        UInt(sliceOfBuffer.count),
        vDSP.SortOrder.descending.rawValue
    )
}

With respect to slicing the indices: It seems that one can pass sortedIndices + sliceOfBuffer.startIndex to the vDSP function. However, the documentation states that the indices must be initialized starting at zero, so I would not rely on that.

How to sort the indices of Slice&lt;UnsafeMutableBufferPointer&lt;Double&gt;&gt; using vDSP?
 
 
Q