【问题标题】:Counting arithmetic operations计数算术运算
【发布时间】:2015-11-02 17:45:59
【问题描述】:

有没有办法计算函数/表达式中数字运算(+、-、/、*)的数量?

以一个简单的线性代数问题为例 (Ax = b):

A_data = np.array([[1, -4, 1],
                  [1, 6, -1],
                  [2, -1, 2]], dtype=float)

b_data = np.array([[7],
                  [13],
                  [5]], dtype=float)

接下来,让我们应用高斯消去过程:

def gauss_elim(A, b):
    Ab = np.column_stack((A, b))
    for k, pivot_row in enumerate(Ab[:-1]):
        for row in Ab[k+1:]:
            if pivot_row[k] != 0:
                row[k:] = row[k:] - pivot_row[k:] * row[k]/pivot_row[k]
    return Ab

结果是:

array([[  1. ,  -4. ,   1. ,   7. ],
       [  0. ,  10. ,  -2. ,   6. ],
       [  0. ,   0. ,   1.4, -13.2]])

我如何计算操作数?

注意:我知道可以事先通过数学计算运算次数(即对于 Gaussian elimination,它是 O(n^3))。

【问题讨论】:

  • numerically 是什么意思?
  • “有没有办法以数字方式评估数字运算(+、-、/、*)的数量。” - 有四个?
  • 也许可以使用unittest.mock.Mock.call_countobject数组来做到这一点
  • numerically 我的意思是在程序中计算它,而不是事先在数学上计算。在上面的例子中,我知道数学算术复杂度是 O(n^2),例如:en.wikipedia.org/wiki/….
  • @blaz 您是在谈论降低时间复杂度从而提高性能的性能吗?我仍然不清楚“数字”或事先的事情。

标签: python numpy recursion scipy


【解决方案1】:

我假设您正在尝试降低此处的复杂性以提高性能。这篇文章中列出了一种杀死 Gauss-elimination 的内部循环的方法,broadcasting 为我们提供了一个部分矢量化的解决方案,就像这样 -

# Concatenate A and b into a single 2D array
Ab = np.concatenate((A,b),axis=1)

for k, pivot_row in enumerate(Ab[:-1]):

    # Vectorized broadcasting magic happens here : 
    # Calculate offsets corresponding to "pivot_row[k:] * row[k]/pivot_row[k]" 
    offsets = (Ab[k+1:,k][:,None] * pivot_row[k:])/pivot_row[k]

    # Update each row
    Ab[k+1:,k:] -= offsets

运行时测试和验证输出 -

In [137]: def partvect_gauss_elim(A,b):
     ...:     Ab = np.concatenate((A,b),axis=1)
     ...:     for k, pivot_row in enumerate(Ab[:-1]):
     ...:         offsets = (Ab[k+1:,k][:,None] * pivot_row[k:])/pivot_row[k]
     ...:         Ab[k+1:,k:] -= offsets
     ...:     return Ab
     ...: 
     ...: def original_gauss_elim(A,b):
     ...:     Ab = np.concatenate((A,b),axis=1)
     ...:     for k, pivot_row in enumerate(Ab[:-1]):
     ...:         for row in Ab[k+1:]:
     ...:             if pivot_row[k] != 0:
     ...:                 row[k:] = row[k:] - pivot_row[k:] * row[k]/pivot_row[k]
     ...:     return Ab
     ...: 

In [138]: A = np.random.randint(0,9,(50,50))
     ...: b = np.random.randint(0,9,(50,1))
     ...: 

In [139]: np.allclose(original_gauss_elim(A,b),partvect_gauss_elim(A,b))
Out[139]: True

In [140]: %timeit original_gauss_elim(A,b)
100 loops, best of 3: 12.1 ms per loop

In [141]: %timeit partvect_gauss_elim(A,b)
100 loops, best of 3: 2.56 ms per loop

【讨论】:

    【解决方案2】:

    如果你能花一点时间,应该有一个方法:创建一个数字类并通过嵌入一个计数器覆盖基本算术方法:__add____mul____sub____div__其中的系统(例如与某些全局变量有关)。然后,您应该能够通过使用dtype=object 参数(在创建数组时)强制 Numpy 使用您的类型,以确保 Numpy 不会将您的数字转换为任何其他类型。我有时会为了更简单的任务而这样做;我从来没有用 Numpy 做过,但它应该可以工作。希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 2016-03-10
      • 1970-01-01
      • 1970-01-01
      • 2020-02-18
      • 2017-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-16
      相关资源
      最近更新 更多