如何在 Julia 中对多个矩阵进行元素 OR?
Posted
技术标签:
【中文标题】如何在 Julia 中对多个矩阵进行元素 OR?【英文标题】:How do I take an elementwise OR of several matrices in Julia? 【发布时间】:2021-12-18 02:46:32 【问题描述】:我有几个布尔矩阵,我想要一个结果矩阵来指示这些矩阵中该位置的任何元素是否为真。 Julia 语言中是否有一个函数可以让我在任意数量的矩阵上获得元素 OR?
# My data
a = Bool[1 0; 1 1]
b = Bool[0 0; 1 1]
c = Bool[0 0; 0 0]
d = Bool[0 0; 1 1]
# Arrays of Bool Arrays
z1 = [a]
z2 = [a, b]
z3 = [b, c, d]
z4 = [a, b, c, d]
z100 = [rand(Bool, 2, 2) for i in 1:100]
# Expected
julia> some_function(z1)
2×2 BitMatrix:
1 0
1 1
julia> some_function(z2)
2×2 BitMatrix:
1 0
1 1
julia> some_function(z3)
2×2 BitMatrix:
0 0
1 1
julia> some_function(z4)
2×2 BitMatrix:
1 0
1 1
julia> some_function(z100)
2×2 BitMatrix:
1 1
1 1
这个问题最初是在 Julia Slack 上提出的。
【问题讨论】:
【参考方案1】:在 Julia 中直接使用 broadcasting。 Julia 中的 OR 运算符是 |
。要像这样广播一个运算符,我们可以在它前面加上一个点,如下所示。
julia> .|(a)
2×2 BitMatrix:
1 0
1 1
julia> .|(a,b)
2×2 BitMatrix:
1 0
1 1
julia> .|(a,b,c)
2×2 BitMatrix:
1 0
1 1
julia> .|(a,b,c,d)
2×2 BitMatrix:
1 0
1 1
手动指示每个矩阵很繁琐。为避免这种情况,我们可以使用splat operator,它将在迭代器中获取元素,并将它们各自转换为被调用函数的不同参数。
julia> .|(z1...)
2×2 BitMatrix:
1 0
1 1
julia> .|(z2...)
2×2 BitMatrix:
1 0
1 1
julia> .|(z3...)
2×2 BitMatrix:
0 0
1 1
julia> .|(z4...)
2×2 BitMatrix:
1 0
1 1
julia> .|(z100...)
2×2 BitMatrix:
1 1
1 1
请注意,broadcasting 允许扩展某些参数,因此所有参数不需要是相同的形状。
julia> .|(z4..., [1 0])
2×2 MatrixInt64:
1 0
1 1
julia> .|(z4..., [0 1])
2×2 MatrixInt64:
1 1
1 1
julia> .|(z4..., [0, 1])
2×2 MatrixInt64:
1 0
1 1
julia> .|(z4..., [1, 0])
2×2 MatrixInt64:
1 1
1 1
julia> .|(z4..., 0)
2×2 MatrixInt64:
1 0
1 1
julia> .|(z4..., 1)
2×2 MatrixInt64:
1 1
1 1
由于上述解决方案使用广播,因此它们非常通用。如果我们限制问题使得所有布尔矩阵必须具有相同的大小,那么我们可以利用short circuit evaluation。一旦我们在任意位置找到1
或true
值,我们就不需要检查后续矩阵相同位置的元素。为了实现这一点,我们将使用any
函数和array comprehension。
julia> short_circuit_or(z...) = short_circuit_or(z)
short_circuit_or (generic function with 1 method)
julia> short_circuit_or(z::Tuple) = [
any(x->x[ind], z) for ind in CartesianIndices(first(z))
]
short_circuit_or (generic function with 2 methods)
julia> short_circuit_or(a,b,c)
2×2 MatrixBool:
1 0
1 1
julia> short_circuit_or(z4...)
2×2 MatrixBool:
1 0
1 1
julia> short_circuit_or(z1)
2×2 MatrixBool:
1 0
1 1
julia> short_circuit_or(z2)
2×2 MatrixBool:
1 0
1 1
julia> short_circuit_or(z3)
2×2 MatrixBool:
0 0
1 1
julia> short_circuit_or(z4)
2×2 MatrixBool:
1 0
1 1
julia> short_circuit_or(z100)
2×2 MatrixBool:
1 1
1 1
正如这些基准所证明的,短路评估可以节省时间。
julia> using BenchmarkTools
julia> @btime .|($z100...)
3.032 ms (24099 allocations: 1.91 MiB)
2×2 BitMatrix:
1 1
1 1
julia> @btime short_circuit_or($z100)
76.413 ns (1 allocation: 96 bytes)
2×2 MatrixBool:
1 1
1 1
【讨论】:
这是一个非常好的答案!但是它错过了short_circuit_or
的代码 - 您可以添加它以便其他读者可以使用它吗?
喷溅可能相当昂贵。 reduce(.|, z100)
比 .|(z100...)
快得多。
@PrzemyslawSzufel short_circuit_or
的代码在那里。有两种方法,一种是让调用更容易,另一种是完成工作。它们中没有“功能”一词,这可能会使它们更难被发现,但它们就在最后一个代码段的顶部。
这是一个非常好的答案,不仅因为它确实回答了问题,还因为它说明了 splatting 和广播对于编写简单代码的有效性。由于这些确实是核心功能,因此最好清楚地说明它们的用途。以上是关于如何在 Julia 中对多个矩阵进行元素 OR?的主要内容,如果未能解决你的问题,请参考以下文章