//===-- NumpyConversion.swift ---------------------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the `ConvertibleFromNumpyArray` protocol for bridging
// `numpy.ndarray`.
//
//===----------------------------------------------------------------------===//
/// The `numpy` Python module.
/// Note: Global variables are lazy, so the following declaration won't produce
/// a Python import error until it is first used.
private let np = Python.import("numpy")
private let ctypes = Python.import("ctypes")
/// A type that can be initialized from a `numpy.ndarray` instance represented
/// as a `PythonObject`.
public protocol ConvertibleFromNumpyArray {
init?(numpy: PythonObject)
}
/// A type that is bitwise compatible with one or more NumPy scalar types.
public protocol NumpyScalarCompatible {
/// The NumPy scalar types that this type is bitwise compatible with. Must
/// be nonempty.
static var numpyScalarTypes: [PythonObject] { get }
/// The Python `ctypes` scalar type corresponding to this type.
static var ctype: PythonObject { get }
}
extension Bool : NumpyScalarCompatible {
public static let numpyScalarTypes = [np.bool_, Python.bool]
public static var ctype: PythonObject { return ctypes.c_bool }
}
extension UInt8 : NumpyScalarCompatible {
public static let numpyScalarTypes = [np.uint8]
public static var ctype: PythonObject { return ctypes.c_uint8 }
}
extension Int8 : NumpyScalarCompatible {
public static let numpyScalarTypes = [np.int8]
public static var ctype: PythonObject { return ctypes.c_int8 }
}
extension UInt16 : NumpyScalarCompatible {
public static let numpyScalarTypes = [np.uint16]
public static var ctype: PythonObject { return ctypes.c_uint16 }
}
extension Int16 : NumpyScalarCompatible {
public static let numpyScalarTypes = [np.int16]
public static var ctype: PythonObject { return ctypes.c_int16 }
}
extension UInt32 : NumpyScalarCompatible {
public static let numpyScalarTypes = [np.uint32]
public static var ctype: PythonObject { return ctypes.c_uint32 }
}
extension Int32 : NumpyScalarCompatible {
public static let numpyScalarTypes = [np.int32]
public static var ctype: PythonObject { return ctypes.c_int32 }
}
extension UInt64 : NumpyScalarCompatible {
public static let numpyScalarTypes = [np.uint64]
public static var ctype: PythonObject { return ctypes.c_uint64 }
}
extension Int64 : NumpyScalarCompatible {
public static let numpyScalarTypes = [np.int64]
public static var ctype: PythonObject { return ctypes.c_int64 }
}
extension Float : NumpyScalarCompatible {
public static let numpyScalarTypes = [np.float32]
public static var ctype: PythonObject { return ctypes.c_float }
}
extension Double : NumpyScalarCompatible {
public static let numpyScalarTypes = [np.float64]
public static var ctype: PythonObject { return ctypes.c_double }
}
extension Array : ConvertibleFromNumpyArray
where Element : NumpyScalarCompatible {
/// Creates an `Array` with the same shape and scalars as the specified
/// `numpy.ndarray` instance.
///
/// - Parameter numpyArray: The `numpy.ndarray` instance to convert.
/// - Precondition: The `numpy` Python package must be installed.
/// - Returns: `numpyArray` converted to an `Array`. Returns `nil` if
/// `numpyArray` is not 1-D or does not have a compatible scalar `dtype`.
public init?(numpy numpyArray: PythonObject) {
// Check if input is a `numpy.ndarray` instance.
guard Python.isinstance(numpyArray, np.ndarray) == true else {
return nil
}
// Check if the dtype of the `ndarray` is compatible with the `Element`
// type.
guard Element.numpyScalarTypes.contains(numpyArray.dtype) else {
return nil
}
// Only 1-D `ndarray` instances can be converted to `Array`.
let pyShape = numpyArray.__array_interface__["shape"]
guard let shape = Array(_ elements: S)` initializer,
// which performs unnecessary copying.
let dummyPointer = UnsafeMutablePointer