Debugging in Jupyter

I’m writing up an algorithm in a function in a Jupyter notebook, and it does some matrix multiplication. At some point, I have missed a transpose or something, and multiplied two matrices whose sizes don’t match. So, when I call my function, I get the following traceback:

DimensionMismatch("A has dimensions (64,64) but B has dimensions (1797,16)")

Stacktrace:
  [1] gemm_wrapper!(C::Matrix{Float64}, tA::Char, tB::Char, A::Matrix{Float64}, B::Matrix{Float64}, _add::LinearAlgebra.MulAddMul{true, true, Bool, Bool})
    @ LinearAlgebra /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.6/LinearAlgebra/src/matmul.jl:643
  [2] mul!
    @ /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.6/LinearAlgebra/src/matmul.jl:392 [inlined]
  [3] mul!
    @ /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.6/LinearAlgebra/src/matmul.jl:464 [inlined]
  [4] mul!
    @ /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.6/LinearAlgebra/src/matmul.jl:275 [inlined]
  [5] *
    @ /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.6/LinearAlgebra/src/matmul.jl:153 [inlined]
  [6] my_algorithm(X::Matrix{Float64}, k::Int64, max_iter::Int64; eps::Float64)
    @ Main ./In[33]:13
  [7] my_algorithm(X::Matrix{Float64}, k::Int64, max_iter::Int64)
    @ Main ./In[33]:2
  [8] top-level scope
    @ In[38]:1
  [9] eval
    @ ./boot.jl:360 [inlined]
 [10] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
    @ Base ./loading.jl:1094

My function is decently long, and since I’m in Jupyter I truly have no idea how to interpret the line numbers here. Contrast this with the Python behavior: in Jupyter/Python, if I define

def f():
    x = np.zeros((1, 10)) @ np.zeros((11, 1))
    return 1

in one cell, and run f() in another cell, the Python traceback is:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-47-c43e34e6d405> in <module>
----> 1 f()

<ipython-input-46-31197cac7006> in f()
      1 def f():
----> 2     x = np.zeros((1, 10)) @ np.zeros((11, 1))
      3     return 1

ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 11 is different from 10)

This is super helpful, there is a big arrow pointing at the line which caused the problem.

Is there any way to get stacktraces to print out the actual offending line of code in Julia, as they would in Python? If not, is there any way to make debugging more ergonomic? How would a Julian hunt down the bug in this situation?

2 Likes