Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split #16

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

KhalidAl-otaibi
Copy link
Contributor

Split function and other basic function such as expandingShape and squeezingShape. I think there is a much better implementation for the split function but this is what I came up with. It uses a few helper functions. These helper functions could also be used for subscription. In fact, if subscription was implemented, split could have been implemented very straightforwardly.

@rexmas
Copy link
Member

rexmas commented Apr 24, 2023

if subscription was implemented

Not sure if you mean subscript or something else, but if you mean subscript we do have an impl for that

public subscript(index: Int) -> Element {

/// takes a shape for the original array, a shape for the subarray,
/// and an axis on which the original array would be divided
/// and returns an array of start and end indices for each subarray

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For doc comments, let's use both starting capitalization and ending punctuation. also // helper function is missing an /

/// and returns an array of start and end indices for each subarray

@usableFromInline
internal func _calculateSubarrayIndices(shape: [Int], subarrayShape: [Int], axis: Int) -> [SubarrayIndices] {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only use of the_ prefix for a name is for public identifiers such as public protocol _ShapedArrayProtocol because they need to be public to work yet we want to signal to the user that they shouldn't be used directly. For non-public identifiers I think we should omit _, in this case that would be calculateSubarrayIndices.

However, i think we can improve on the name more too. Possibly

slicedSubArrayIndices(forShape shape: [Int], subarrayShape: [Int], alongAxis axis: Int) -> [SubarrayIndices]

?

Lastly, and maybe this isn't possible with @usableFromInline, but if this is only used in 1 function I usually move the function declaration inside of the function that uses it. It adds some indentation but makes it clear at point of use that it isn't used elsewhere. Up to you though, nbd either way.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or maybe splitSubArrayIndices to match the calling function..

internal func _calculateSubarrayIndices(shape: [Int], subarrayShape: [Int], axis: Int) -> [SubarrayIndices] {
let numberOfSubarrays = shape[axis] / subarrayShape[axis]

var subarrays = [SubarrayIndices]()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to think of a name that better captures this type, maybe var groupedSubarrayIndices? any suggestions?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

slicedSubarrayIndices?

endIndices[axis] = startIndices[axis] + subarrayShape[axis]

subarrays.append(SubarrayIndices(start: startIndices, end: endIndices))
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this may look a bit nicer with a map

let subarrays = (0..<numberSubarrays).map { i in
    var startIndices = [Int](repeating: 0, count: shape.count)
    var endIndices = shape

    startIndices[axis] = i * subarrayShape[axis]
    endIndices[axis] = startIndices[axis] + subarrayShape[axis]

    return SubarrayIndices(start: startIndices, end: endIndices)
}

}

// helper function for subarray indices generation
/// takes a start and end index for each dimension and returns all the n-dim indices in between
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as before about doc comments.

/// Splits the ShapedArray into multiple subarrays along the given axis.
/// - Parameters:
/// - count: The number of subarrays to return.
/// - axis: The axis along which to split the ShapedArray. Negative values wrap around.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

- axis seems misaligned with - count

// helper function for subarray indices generation
/// takes a start and end index for each dimension and returns all the n-dim indices in between
@usableFromInline
internal func _generateIndices(start: [Int], end: [Int], currentIndex: [Int] = [], depth: Int = 0) -> [[Int]] {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe

allIndices(fromStart start: [Int], toEnd end: [Int], currentIndices: [Int] = [], depth: Int = 0) -> [[Int]]


for i in start[depth]..<end[depth] {
let newIndex = currentIndex + [i]
let subIndices = _generateIndices(start: start, end: end, currentIndex: newIndex, depth: depth + 1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't tail recursive so there's no tail-call optimization. Granted probably plenty to optimize in the future, but maybe add a comment here calling that out explicitly?
E.g. TODO: Possible tail-call optimization?

}

// helper function for subarray indices generation
/// takes a shape, strides, and n-dim indices and returns the linear index
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

// helper function for subarray indices generation
/// takes a shape, strides, and n-dim indices and returns the linear index
@usableFromInline
internal func _calculateLinearIndex(shape: [Int], strides: [Int], indices: [Int]) -> Int {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe

linearIndexFrom(shape: [Int], strides: [Int], indices: [Int]) -> Int

?
other option may be bufferIndexFrom(shape:strides:indices)

}
linearIndex += stride * index
}
return linearIndex
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation is very off here...

return linearIndex
}


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only 1 newline please

return newArrays
}


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only 1 newline please

@@ -70,15 +183,17 @@ extension ShapedArray {
/// - Precondition: `axis` must be in the range `[-rank, rank)`, where `rank` is the rank of
/// the provided ShapedArrays.
///


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

both newlines here should be deleted please, this breaks up the comment

@@ -318,3 +318,14 @@ extension _ShapedArrayProtocol where Scalar: Equatable {
}
}
}

extension _ShapedArrayProtocol where Scalar: Comparable {
internal func _isLess(than other: Self) -> Bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this function used anywhere, is this something we need to keep?


}

// test expandingShape
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment here probably not needed since it's in the name of the test function

@@ -99,6 +214,47 @@ extension ShapedArray {

return newArrays.map { ShapedArray(shape: newShape, scalars: $0) }
}

@inlinable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some docs we can include:

/// Returns a shape-expanded `ShapedArray`, with a dimension of 1 inserted at the specified shape
/// indices.

}

@inlinable
public func rankLifted() -> ShapedArray {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible docs for this:

/// Returns a rank-lifted `ShapedArray` with a leading dimension of 1.

Copy link
Member

@rexmas rexmas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for this! left some comments before approval, but nothing major

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants