如何快速重塑阵列

时间:2014-09-20 14:22:09

标签: julia

在下面的代码中,我使用Julia Optim软件包来查找与目标函数相关的最优矩阵。 遗憾的是,提供的优化函数仅支持向量,因此我必须先将矩阵转换为向量,然后再将其传递给optimize函数,并在目标函数中使用它时将其转换回来。

function opt(A0,X)    
    I1(A) = sum(maximum(X*A,1))

    function transform(A)
      # reshape matrix to vector
      return reshape(A,prod(size(A)))
    end

    function transformback(tA)
      # reshape vector to matrix
      return reshape(tA, size(A0))
    end

    obj(tA) = -I1(transformback(tA))
    result = optimize(obj, transform(A0), method = :nelder_mead)
    return transformback(result.minimum)
end

我认为朱莉娅每次都会为此分配新的空间而感觉很慢,那么解决这个问题的方法会更有效?

2 个答案:

答案 0 :(得分:6)

只要数组包含被认为是不可变的元素(包括所有基元),那么数组的元素就包含在1个 连续的 内存块中。因此,您可以打破维度规则,只需将二维数组视为一维数组,这就是您想要做的。所以你不需要重塑,但我不认为重塑是你的问题

数组是列主要且连续的

考虑以下功能

function enumerateArray(a)
   for i = 1:*(size(a)...)
      print(a[i])
   end
end

此函数将 a 的所有维度相乘,然后从1到该数字循环,假设 a 是一维。

将a定义为以下

julia> a = [ 1 2; 3 4; 5 6]
3x2 Array{Int64,2}:
 1  2  
 3  4
 5  6

结果是

julia> enumerateArray(a)
135246

这说明了一些事情。

  1. 是的,它确实有效
  2. 矩阵以列主格式存储
  3. 重塑

    那么,问题是为什么不重塑这个事实呢?它确实如此。这是array.c

    中重塑的julia来源
    a = (jl_array_t*)allocobj((sizeof(jl_array_t) + sizeof(void*) + ndimwords*sizeof(size_t) + 15)&-16);
    

    所以是的,创建了一个新数组,但只创建了新的维度信息,它指向未复制的原始数据。您可以像这样验证这一点:

     b = reshape(a,6);
    
    julia> size(b)
    (6,)
    
    julia> size(a)
    (3,2)
    
    julia> b[4]=100
    100
    
    julia> a
    3x2 Array{Int64,2}:
     1  100
     3    4
     5    6
    

    因此设置 b 的第4个元素会设置 a 的(1,2)元素。

    总体缓慢

    I1(A) = sum(maximum(X*A,1))
    

    将创建一个新数组。

    您可以使用几个宏来跟踪 @profile @time 。时间将另外记录分配的内存量,并且可以放在任何表达式之前。

    例如

    julia> A = rand(1000,1000);
    julia> X = rand(1000,1000);
    julia> @time sum(maximum(X*A,1))
    elapsed time: 0.484229671 seconds (8008640 bytes allocated)
    266274.8435928134
    

    @profile 记录的统计信息使用 Profile.print()

    输出

答案 1 :(得分:1)

此外,Optim中的大多数方法实际上允许您提供数组,而不仅仅是Vector。您可以概括nelder_mead函数来执行相同的操作。