如何在 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。一旦我们在任意位置找到1true 值,我们就不需要检查后续矩阵相同位置的元素。为了实现这一点,我们将使用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?的主要内容,如果未能解决你的问题,请参考以下文章

在 Julia 中对多变量函数进行数值积分的问题 WRT 单个变量(使用 hcubature)

Julia:找到所有最大值的索引

如何以特定格式在 Julia 中保存数组或矩阵?

从 Julia 中的文本文件中读取数据矩阵

如何在 LINQ 中对单个连接中的多个字段进行连接

matlab中已知一矩阵,如何将其中的已知的元素打乱顺序进行随机排列得到新的矩阵,如: