如何在 Julia 中对多个矩阵进行元素或运算?

Mar*_*kul 6 iterator short-circuiting boolean-operations julia

我有几个布尔矩阵,我想要一个结果矩阵来指示这些矩阵的该位置中的任何元素是否为真。Julia 语言中是否有一个函数可以让我对任意数量的矩阵进行元素或运算?

\n
# My data\na = Bool[1 0; 1 1]\nb = Bool[0 0; 1 1]\nc = Bool[0 0; 0 0]\nd = Bool[0 0; 1 1]\n\n# Arrays of Bool Arrays\nz1 = [a]\nz2 = [a, b]\nz3 = [b, c, d]\nz4 = [a, b, c, d]\nz100 = [rand(Bool, 2, 2) for i in 1:100]\n\n# Expected\njulia> some_function(z1)\n2\xc3\x972 BitMatrix:\n 1  0\n 1  1\n\njulia> some_function(z2)\n2\xc3\x972 BitMatrix:\n 1  0\n 1  1\n\njulia> some_function(z3)\n2\xc3\x972 BitMatrix:\n 0  0\n 1  1\n\njulia> some_function(z4)\n2\xc3\x972 BitMatrix:\n 1  0\n 1  1\n\njulia> some_function(z100)\n2\xc3\x972 BitMatrix:\n 1  1\n 1  1\n
Run Code Online (Sandbox Code Playgroud)\n

这个问题最初是在Julia Slack上提出的。

\n

Mar*_*kul 10

Julia 中最简单的方法是使用广播。Julia 中的 OR 运算符是|。要广播这样的运算符,我们可以在其前面加上一个点,如下所示。

\n
julia> .|(a)\n2\xc3\x972 BitMatrix:\n 1  0\n 1  1\n\njulia> .|(a,b)\n2\xc3\x972 BitMatrix:\n 1  0\n 1  1\n\njulia> .|(a,b,c)\n2\xc3\x972 BitMatrix:\n 1  0\n 1  1\n\njulia> .|(a,b,c,d)\n2\xc3\x972 BitMatrix:\n 1  0\n 1  1\n\n
Run Code Online (Sandbox Code Playgroud)\n

手动指示每个矩阵是乏味的。为了避免这种情况,我们可以使用splat 运算符,它将获取迭代器中的元素并将它们每个转换为被调用函数的不同参数。

\n
julia> .|(z1...)\n2\xc3\x972 BitMatrix:\n 1  0\n 1  1\n\njulia> .|(z2...)\n2\xc3\x972 BitMatrix:\n 1  0\n 1  1\n\njulia> .|(z3...)\n2\xc3\x972 BitMatrix:\n 0  0\n 1  1\n\njulia> .|(z4...)\n2\xc3\x972 BitMatrix:\n 1  0\n 1  1\n\njulia> .|(z100...)\n2\xc3\x972 BitMatrix:\n 1  1\n 1  1\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,广播允许扩展某些参数,因此所有参数不需要具有相同的形状。

\n
julia> .|(z4..., [1 0])\n2\xc3\x972 Matrix{Int64}:\n 1  0\n 1  1\n\njulia> .|(z4..., [0 1])\n2\xc3\x972 Matrix{Int64}:\n 1  1\n 1  1\n\njulia> .|(z4..., [0, 1])\n2\xc3\x972 Matrix{Int64}:\n 1  0\n 1  1\n\njulia> .|(z4..., [1, 0])\n2\xc3\x972 Matrix{Int64}:\n 1  1\n 1  1\n\njulia> .|(z4..., 0)\n2\xc3\x972 Matrix{Int64}:\n 1  0\n 1  1\n\njulia> .|(z4..., 1)\n2\xc3\x972 Matrix{Int64}:\n 1  1\n 1  1\n
Run Code Online (Sandbox Code Playgroud)\n

由于上述解决方案使用了广播,因此它们非常通用。如果我们限制问题,使所有布尔矩阵必须具有相同的大小,那么我们就可以利用短路评估。一旦我们在任意位置找到了 a 1ortrue值,我们就不需要检查后续矩阵中同一位置的元素。为了实现这一点,我们将使用该any函数以及数组理解

\n
julia> short_circuit_or(z...) = short_circuit_or(z)\nshort_circuit_or (generic function with 1 method)\n\njulia> short_circuit_or(z::Tuple) = [\n           any(x->x[ind], z) for ind in CartesianIndices(first(z))\n       ]\nshort_circuit_or (generic function with 2 methods)\n\njulia> short_circuit_or(a,b,c)\n2\xc3\x972 Matrix{Bool}:\n 1  0\n 1  1\n\njulia> short_circuit_or(z4...)\n2\xc3\x972 Matrix{Bool}:\n 1  0\n 1  1\n\njulia> short_circuit_or(z1)\n2\xc3\x972 Matrix{Bool}:\n 1  0\n 1  1\n\njulia> short_circuit_or(z2)\n2\xc3\x972 Matrix{Bool}:\n 1  0\n 1  1\n\njulia> short_circuit_or(z3)\n2\xc3\x972 Matrix{Bool}:\n 0  0\n 1  1\n\njulia> short_circuit_or(z4)\n2\xc3\x972 Matrix{Bool}:\n 1  0\n 1  1\n\njulia> short_circuit_or(z100)\n2\xc3\x972 Matrix{Bool}:\n 1  1\n 1  1\n
Run Code Online (Sandbox Code Playgroud)\n

正如这些基准测试所证明的,短路评估可以节省时间。

\n
julia> using BenchmarkTools\n\njulia> @btime .|($z100...)\n  3.032 ms (24099 allocations: 1.91 MiB)\n2\xc3\x972 BitMatrix:\n 1  1\n 1  1\n\njulia> @btime short_circuit_or($z100)\n  76.413 ns (1 allocation: 96 bytes)\n2\xc3\x972 Matrix{Bool}:\n 1  1\n 1  1\n
Run Code Online (Sandbox Code Playgroud)\n