Skip to main content

debugging - Automatically add debug contents to a program


Sometimes I'll use Print[1] or Print[n] to debug in a long loop, but it's really a boring job to add these sentence by sentence and removing them sentence by sentence. (It's already boring to read this first three lines sentence by sentence so you can imagine how boring it is to add these stuff sentence by sentence. :P) So my question is how to throw this job to a program?


Let's take this small (and stupid) program as an example:


Do[j=i^2;Thread[{{1},{2,3}}],{i,3}]

I would like to add two Print in this program to determin where the problem occurs.


Do[Print@1;j=i^2;Print@2;Thread[{{1},{2,3}}],{i,3}]

In this way I can know that it's the second step that goes wrong.



Any idea how to do this automatically?



Answer



Yesterday I checked my account's question list again and find this question lying inside. After a year wrestling mostly with Hold stuffs, I think I finally found a, well, not that elegant solution. Any suggestions or new answers are surely welcomed!!!


It seems that this question is not that bad, actually I may say that It's quite hard for one to solve this problem using all sorts of evaluation manipulation techniques. and it has real applications sometimes.




As usual, my code first:


SetAttributes[adddebug, HoldFirst]
adddebug[orig_, func_: Echo, level_: {2}] :=
Module[{$count = 1, tempf},
Replace[

Replace[Hold[orig], HoldPattern[CompoundExpression[comp__]] :>
Block[{},
tempf @@
Riffle[List @@ (Hold /@ Hold[comp]),
With[{$func = func, q = #}, Hold@$func@q] & /@
Range[$count, ($count = $count + Length@Hold[comp] + 1) -
1], {2, -1, 2}] /; True],level],
tempf[seg__] :>
Block[{},
tempf[Hold[CompoundExpression]] @@ (tempf /@ {seg}) /; True],level] /. tempf[Hold[seg_]] :> seg

]

adddebug[Do[j = i^2; Thread[{{1}, {2, 3}}], {i, 3}]]

The result is satisfying



Hold[Do[j = i^2; Echo[1]; Thread[{{1}, {2, 3}}]; Echo[2], {i, 3}]]





Some additional notes:



Why I say this question is not that trivial is because I should protect CompoundExpression and its content from evaluating while still need to operate on CompoundExpression's structure and use in place evaluation techniques extensively.


So I install protection in the following ways:




  1. When pattern-matching, Use HoldPattern




  2. Use unique symbol tempf as a medium to mark Where CompoundExpression previoulsly existed. Use tempf[Hold[CompoundExpression]].





  3. make every element of CompoundExpression Hold at all times, and mark them using tempf[Hold[expr]]




  4. I'm quite satisfied by the last ReplaceAll's design, as previously I’ve already make where should be CompoundExpression tempf[Hold[CompoundExpression]] and where should be CompoundExpression's element tempf[Hold[element]], Now I can safely use ReplaceAll once to make those stuffs back to their original form!






I still am looking foward to a better solution, so if anyone has any idea, post something, Thanks!


Comments

Popular posts from this blog

functions - Get leading series expansion term?

Given a function f[x] , I would like to have a function leadingSeries that returns just the leading term in the series around x=0 . For example: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x)] x and leadingSeries[(1/x + 2 + (1 - 1/x^3)/4)/(4 + x)] -(1/(16 x^3)) Is there such a function in Mathematica? Or maybe one can implement it efficiently? EDIT I finally went with the following implementation, based on Carl Woll 's answer: lds[ex_,x_]:=( (ex/.x->(x+O[x]^2))/.SeriesData[U_,Z_,L_List,Mi_,Ma_,De_]:>SeriesData[U,Z,{L[[1]]},Mi,Mi+1,De]//Quiet//Normal) The advantage is, that this one also properly works with functions whose leading term is a constant: lds[Exp[x],x] 1 Answer Update 1 Updated to eliminate SeriesData and to not return additional terms Perhaps you could use: leadingSeries[expr_, x_] := Normal[expr /. x->(x+O[x]^2) /. a_List :> Take[a, 1]] Then for your examples: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x), x] leadingSeries[Exp[x], x] leadingSeries[(1/x + 2 + (1 - 1/x...

How to thread a list

I have data in format data = {{a1, a2}, {b1, b2}, {c1, c2}, {d1, d2}} Tableform: I want to thread it to : tdata = {{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}} Tableform: And I would like to do better then pseudofunction[n_] := Transpose[{data2[[1]], data2[[n]]}]; SetAttributes[pseudofunction, Listable]; Range[2, 4] // pseudofunction Here is my benchmark data, where data3 is normal sample of real data. data3 = Drop[ExcelWorkBook[[Column1 ;; Column4]], None, 1]; data2 = {a #, b #, c #, d #} & /@ Range[1, 10^5]; data = RandomReal[{0, 1}, {10^6, 4}]; Here is my benchmark code kptnw[list_] := Transpose[{Table[First@#, {Length@# - 1}], Rest@#}, {3, 1, 2}] &@list kptnw2[list_] := Transpose[{ConstantArray[First@#, Length@# - 1], Rest@#}, {3, 1, 2}] &@list OleksandrR[list_] := Flatten[Outer[List, List@First[list], Rest[list], 1], {{2}, {1, 4}}] paradox2[list_] := Partition[Riffle[list[[1]], #], 2] & /@ Drop[list, 1] RM[list_] := FoldList[Transpose[{First@li...

front end - keyboard shortcut to invoke Insert new matrix

I frequently need to type in some matrices, and the menu command Insert > Table/Matrix > New... allows matrices with lines drawn between columns and rows, which is very helpful. I would like to make a keyboard shortcut for it, but cannot find the relevant frontend token command (4209405) for it. Since the FullForm[] and InputForm[] of matrices with lines drawn between rows and columns is the same as those without lines, it's hard to do this via 3rd party system-wide text expanders (e.g. autohotkey or atext on mac). How does one assign a keyboard shortcut for the menu item Insert > Table/Matrix > New... , preferably using only mathematica? Thanks! Answer In the MenuSetup.tr (for linux located in the $InstallationDirectory/SystemFiles/FrontEnd/TextResources/X/ directory), I changed the line MenuItem["&New...", "CreateGridBoxDialog"] to read MenuItem["&New...", "CreateGridBoxDialog", MenuKey["m", Modifiers-...