Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 在System.Numerics.Vector<;T>;_.net_F#_Vectorization_Simd_Units Of Measurement - Fatal编程技术网

.net 在System.Numerics.Vector<;T>;

.net 在System.Numerics.Vector<;T>;,.net,f#,vectorization,simd,units-of-measurement,.net,F#,Vectorization,Simd,Units Of Measurement,我很难将F#度量单位与System.Numerics.Vector>结合使用(v:Vector>=u*v|>重新键入 // ... 设u=v.*.v//断言类型向量 问题:不需要任何其他操作,但使用了不推荐使用的功能(内联IL),并且不是完全通用的(仅针对度量单位) 有人有更好的解决方案吗* *请注意,上面的示例实际上是一个演示一般问题的玩具问题。实际程序解决了一个更复杂的初值问题,涉及多种物理量。编译器能够很好地解决如何应用乘法的单位规则,这里的问题是您有一个包装类型。在y中我们的第一个示例

我很难将F#度量单位与
System.Numerics.Vector>结合使用(v:Vector>=u*v|>重新键入
// ...
设u=v.*.v//断言类型向量
问题:不需要任何其他操作,但使用了不推荐使用的功能(内联IL),并且不是完全通用的(仅针对度量单位)

有人有更好的解决方案吗*


*请注意,上面的示例实际上是一个演示一般问题的玩具问题。实际程序解决了一个更复杂的初值问题,涉及多种物理量。

编译器能够很好地解决如何应用乘法的单位规则,这里的问题是您有一个包装类型。在y中我们的第一个示例是,当您编写
xs |>Array.map(funx->x*x)
时,您是根据数组的元素而不是直接在数组上描述乘法

如果有
向量
,则单位将附加到
浮点
,而不是
向量
,因此当您尝试乘法
向量
时,编译器不会将该类型视为有任何单位


考虑到类公开的方法,我认为使用
Vector不是一个简单的解决方法,我提出了一个解决方案,它满足了我的大部分需求(看起来)。它的灵感来自(包装
Vector'a)
和'a:struct
和'a:>System.ValueType>=struct
val公共数据:向量)={Data=d}
静态成员内联(*)(u:PackedScalars,v:PackedScalars)=u.Data*v.Data |>PackedScalars'a)
和'a:struct
和'a:>System.ValueType>=struct
val公共数据:“a[]
内联get i=Scalar的成员self.Item(self.Data.[i])
和内联集i(v:标量)=自数据。[i]

和内联集i(v:PackedScalarsHm,我尝试了
FloatVectorWithUnits
,但是
(*)
操作符的度量值自动约束为“1”(无量纲,签名
FloatVectorWithUnits*FloatVectorWithUnits->FloatVectorWithUnits
)。此外,
VectorWithUnits
需要额外的显式类型约束,但在其他方面似乎有效。我也考虑过包装类型,但我不知道您可以为度量参数断言/强制某些规则。很有趣。@Frank好奇。我在安装
Vector
类型时遇到了一些问题n从稳定版本中删除,因此我不得不以稍微迂回的方式测试此代码,但我没有得到与“1”相同的约束。我想知道这是否与不同的F#版本有关,我将尝试调查。@Frank我很抱歉,我认为第二个示例是不可行的。它在我处理这些安装问题时有点狡猾,但我认为它不会对你起作用,除非你能找到一种方法去除度量单位注释并重新添加我知道您希望避免在算术函数定义中使用em。希望第一种方法仍然有用…是的,NuGet包仍然存在一些问题,至少对于.NET framework/F#和Numerics.Vector版本的某些组合是这样的(另请参阅).NET 4.5.2、F#4.0和Vectors 4.1.1-beta-23516对我来说很有效。@Frank,有一种方法可以使用一些运行时强制转换重新创建第二个示例,我想这与您最初的内联IL方法类似。
xs |> Array.map (fun x -> x * x) // float<m^2>[]
open System.Numerics
let simdWidth = Vector<float>.Count
// fill with dummy data
let xs = Array.init (simdWidth * 10) (fun i -> float i * 1.0<m>)
// array to store the results
let rs: float<m^2> array = Array.zeroCreate (xs |> Array.length)
// number of SIMD operations required
let chunks = (xs |> Array.length) / simdWidth
// for simplicity, assume xs.Length % simdWidth = 0
for i = 0 to chunks - 1 do
    let v = Vector<_>(xs, i * simdWidth) // Vector<float<m>>, containing xs.[i .. i+simdWidth-1]
    let u = v * v                        // Vector<float<m>>; expected: Vector<float<m^2>>
    u.CopyTo(rs, i * simdWidth)          // units mismatch
// remove all UoM from all arrays
let xsWoM = Array.map (fun x -> x / 1.0<m>) xs
// ...
// perform computation using xsWoM etc.
// ...
// add back units again
let xs = Array.map (fun x -> x * 1.0<m>) xsWoM
// reinterpret x to be of type 'b
let inline retype (x: 'a) : 'b = (# "" x: 'b #)
let inline (.*.) (u: Vector<float<'m>>) (v: Vector<float<'m>>): Vector<float<'m^2>> = u * v |> retype
// ...
let u = v .*. v // asserts type Vector<float<m^2>>
type VectorWithUnits<'a, [<Measure>]'b> = 
    |VectorWithUnits of Vector<'a>

    static member inline (*) (a : VectorWithUnits<'a0, 'b0>, b : VectorWithUnits<'a0, 'b1>) 
        : VectorWithUnits<'a0, 'b0*'b1> =
        match a, b with
        |VectorWithUnits a, VectorWithUnits b -> VectorWithUnits <| a * b
let toFloatVectors (array : float<'m>[]) : VectorWithUnits<float,'m>[]  =
    let arrs = array |> Array.chunkBySize (Vector<float>.Count)
    arrs |> Array.map (Array.map (float) >> Vector >> VectorWithUnits)
let fromFloatVectors (vectors : VectorWithUnits<float,'m>[]) : float<'m>[] =
    let arr = Array.zeroCreate<float> (Array.length vectors)
    vectors |> Array.iteri (fun i uVec ->
        match uVec with
        |VectorWithUnits vec -> vec.CopyTo arr)
    arr |> Array.map (LanguagePrimitives.FloatWithMeasure<'m>)
type FloatVectorWithUnits<[<Measure>]'b> = 
    |FloatVectorWithUnits of Vector<float<'b>>

    static member ( * ) (a : FloatVectorWithUnits<'b0>, b : FloatVectorWithUnits<'b1>) =
        match a, b with
        |FloatVectorWithUnits a, FloatVectorWithUnits b ->
            let c, d = box a :?> Vector<float<'b0*'b1>>, box b :?> Vector<float<'b0*'b1>>
            c * d |> FloatVectorWithUnits
// units-aware wrapper for System.Numerics.Vector<'T>
type PackedScalars<[<Measure>] 'm> = struct
    val public Data: Vector<float>
    new (d: Vector<float>) = {Data = d}
    static member inline (*) (u: PackedScalars<'m1>, v: PackedScalars<'m2>) = u.Data * v.Data |> PackedScalars<'m1*'m2>
end

// unit-ware type, wrapping a raw array for easy stream processing
type ScalarField<[<Measure>] 'm> = struct
    val public Data: float[]
    member self.Item with inline get i                = LanguagePrimitives.FloatWithMeasure<'m> self.Data.[i]
                     and  inline set i (v: float<'m>) = self.Data.[i] <- (float v)
    member self.Packed 
           with inline get i                        = Vector<float>(self.Data, i) |> PackedScalars<'m>
           and  inline set i (v: PackedScalars<'m>) = v.Data.CopyTo(self.Data, i)
    new (d: float[]) = {Data = d}
    new (count: int) = {Data = Array.zeroCreate count}
end
let xs = Array.init (simdWidth * 10) float |> ScalarField<m>    
let mutable rs = Array.zeroCreate (xs.Data |> Array.length) |> ScalarField<m^2>
let chunks = (xs.Data |> Array.length) / simdWidth
for i = 0 to chunks - 1 do
    let j = i * simdWidth
    let v = xs.Packed(j) // PackedScalars<m>
    let u = v * v        // PackedScalars<m^2>
    rs.Packed(j) <- u
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module ScalarField =
    let map f (sf: ScalarField<_>) =
        let mutable res = Array.zeroCreate sf.Data.Length |> ScalarField
        for i = 0 to sf.Data.Length do
           res.[i] <- f sf.[i]
        res
type Scalar<'a, [<Measure>] 'm> = struct
    val public Data: 'a
    new (d: 'a) = {Data = d}
end

type PackedScalars<'a, [<Measure>] 'm 
            when 'a: (new: unit -> 'a) 
            and  'a: struct 
            and  'a :> System.ValueType> = struct
    val public Data: Vector<'a>
    new (d: Vector<'a>) = {Data = d}
    static member inline (*) (u: PackedScalars<'a, 'm1>, v: PackedScalars<'a, 'm2>) = u.Data * v.Data |> PackedScalars<'a, 'm1*'m2>
end

type ScalarField<'a, [<Measure>] 'm
            when 'a: (new: unit -> 'a) 
            and  'a: struct 
            and  'a :> System.ValueType> = struct
    val public Data: 'a[]
    member self.Item with inline get i                    = Scalar<'a, 'm>(self.Data.[i])
                     and  inline set i (v: Scalar<'a,'m>) = self.Data.[i] <- v.Data
    member self.Packed 
           with inline get i                          = Vector<'a>(self.Data, i) |> PackedScalars<_,'m>
           and  inline set i (v: PackedScalars<_,'m>) = v.Data.CopyTo(self.Data, i)
    new (d:'a[]) = {Data = d}
    new (count: int) = {Data = Array.zeroCreate count}
end