AMPL syntax error offset 1067 - ampl

I have a syntax error in my code,is there someone who can help me?
set surgery;
set OOR;
set OR{surgery};
set surgeon ordered;
set aa{surgeon};
param S>0;
param time{i in surgery}>=0;
#param aa{i in surgery}>=0;#病人对应的医生
var st{i in surgery,m in OR[i]}>=0;
var et{i in surgery,m in OR[i]}>=0;
var x{i in surgery,m in OR[i]} integer binary;
#var y{i in surgery,a in stage, b in stage:a<>b} binary;
var z{c in surgeon,k in aa[c],l in aa[c],m in OR[k],n in OR[l]:k>l or k<l} binary;
var n{i in surgery,k in surgery,m in OR[i] inter OR[k]:k>i or k<i} binary;
var C;
minimize t:C;
subject to seven{i in surgery,m in OR[i]}:
st[i,m]+time[i]*x[i,m]<=C;#目标
subject to choose{i in surgery}:
sum{m in OR[i]}x[i,m]=1;#至少选择一个
subject to time2{i in surgery,j in OR[i]}:
et[i,j]=st[i,j]+time[i]*x[i,j];#et计算公式
subject to OR1{i in surgery,k in surgery,m in OR[i] inter OR[k]:k>i}:
et[i,m]-st[k,m]<=S*n[i,k,m];
subject to OR2{i in surgery,k in surgery,m in OR[i] inter OR[k]:k>i}:
et[k,m]-st[i,m]<=S*(1-n[i,k,m]);
subject to doctor1{c in surgeon,k in aa[c],l in aa[c],m in OR[k],n in OR[l]:k>l}:
et[l,n]-st[k,m]<=S*z[c,k,l,m,n];
subject to doctor2{c in surgeon,k in aa[c],l in aa[c],m in OR[k],n in OR[l]:k>l}:
et[k,m]-st[l,n]<=S*(1-z[c,k,l,m,n]);
the above is my code and i got a message that:
4.mod, line 37 (offset 1067):
syntax error
and the line 37 is: subject to doctor1{c in surgeon,k in aa[c],l in aa[c],m in OR[k],n in OR[l]:k>l}:
who can tell the reason? thank you so much !

You have already defined n as an indexed variable on line 15 of the program. Now you're referring to n within your constraint definition. I'm guessing it's not supposed to be the same "n" as the one you created as a variable. In any case, you're not allowed to use a variable within the indexing of a constraint like this, so AMPL gives an error message.
The AMPL "syntax error" messages are not very helpful in figuring out the cause of problems like this. One thing that gave me a clue was that even though the "m in OR[k]" part has exactly the same format as "l in OR[l]" and appears before it, that one doesn't trigger an error message.
{c in surgeon,k in aa[c],**m in OR[k]**,l in aa[c],**n in OR[l]**: k>l}
I tried swapping the k & m terms with the l & n terms:
{c in surgeon,l in aa[c],n in OR[l],k in aa[c],m in OR[k]: k>l}
and the error was still associated with "n in OR[l]". This made it pretty clear that there was something special about either n or l, so I went looking elsewhere in the program and noticed that you'd already declared n.
(BTW, this is a good reason to use meaningful variable names rather than just calling things "n" and "aa"...)

Related

Why FF_5 is not posting EBS records to subledgers?

I'm trying to post document through tcode FF_5 (electronic bank statements) as SWIFT MT940 - international format, with immediate posting parameter. Bank Accounting Posting works fine, but Subledger posting doesn't work correctly.
After debugging I found information that document is being posted by FM: 'POSTING_INTERFACE_DOCUMENT'. Inside return table - t_bapiret2 I'm getting message "Batch Input for screen SAPLFCPD 0100 does not exist" (Type: S, ID: 00, NR: 344). When I'm trying to post this without background processing I have to insert name of customer into field BSEC-NAME1 of this screen and it posts fine.
I want to automize this process. How should I pass data to ftpost[] or bdcdata[] tables to inject information about Customer Name? I tried to do it in various ways in debugging mode but none of them worked for me.
Sample BDCDATA[] record that I created:
ft-program = 'SAPLFCPD'.
ft-dynpro = '0100'.
ft-dynbegin = 'X'.
APPEND ft.
CLEAR ft.
ft-fname = 'BSEC-NAME1'.
ft-fval = 'TEST'.
APPEND ft.
EDIT:
Sample bank statement:
:20:MT940
:25:/PL22112110212000180204832110
:28C:56
:60F:C220525PLN89107,30
:61:2205250525D269,98N152NONREF//6450501100324535
152 0
:86:020~00152
~20ZAM.PL111111111, FVKOR/0022
~2111/2205/2401120
~22˙
~23˙
~24˙
~25˙
~3010202964
~310000620200678839
~32CUSTOMER NAME
~33˙
~38PL23102029640000620200678839
~60˙
~63˙
:62F:C220525PLN88837,32
:64:C220525PLN88837,32
-
This is one-time Client, he has no master data information that's why I want to inject it.
I would really appreciate any help.
I added some code to process it as BDC, right now entries are available in SM35.
Code looks like this:
ENHANCEMENT 1 ES_BDC_FEBAN. "active version
data lv_session TYPE APQI-GROUPID.
lv_session = |{ SY-DATUM }{ SY-TIMLO(4) }|.
DATA: lv_name1 LIKE bsec-name1.
GET PARAMETER ID 'FEBAN_NAME1' FIELD lv_name1.
IF lv_name1 IS NOT INITIAL.
CALL FUNCTION 'BDC_OPEN_GROUP'
EXPORTING
client = SY-MANDT " Client
group = LV_SESSION " Session name
keep = 'X' " Indicator to keep processed sessions
user = SY-UNAME " Batch input user
EXCEPTIONS
client_invalid = 1 " Client is invalid
destination_invalid = 2 " Target system is invalid/no longer relevant
group_invalid = 3 " Batch input session name is invalid
group_is_locked = 4 " Batch input session is protected elsewhere
holddate_invalid = 5 " Lock date is invalid
internal_error = 6 " Internal error of batch input (see SYSLOG)
queue_error = 7 " Error reading/writing the queue (see SYSLOG)
running = 8 " Session is already being processed
system_lock_error = 9 " System error when protecting BI session
user_invalid = 10 " BI user is not valid
others = 11
.
IF SY-SUBRC <> 0.
ENDIF.
MODE = 'Q'.
clear: FUNCT, SGFUNCT.
* funct = 'B'.
* SGFUNCT = 'B'.
ft-program = 'SAPLFCPD'.
ft-dynpro = '0100'.
ft-dynbegin = 'X'.
APPEND ft TO ft[].
CLEAR: ft-program, ft-dynpro, ft-dynbegin.
ft-fnam = 'BSEC-NAME1'.
ft-fval = lv_name1.
APPEND ft TO ft[].
CALL FUNCTION 'BDC_INSERT'
EXPORTING
tcode = tcode
TABLES
dynprotab = ft.
call function 'BDC_CLOSE_GROUP' .
COMMIT WORK AND WAIT.
SUBMIT RSBDCSUB EXPORTING LIST TO MEMORY
WITH mappe EQ lv_session
WITH von EQ sy-datum
WITH bis EQ sy-datum
WITH z_verarb EQ 'X'
WITH fehler EQ ''
WITH logall EQ 'X'
AND RETURN.
ENDIF.
ENDENHANCEMENT.
Variables entries:
Tcode = 'FB01'
FT[]:
<asx:abap version="1.0" xmlns:asx="http://www.sap.com/abapxml"><asx:values><_--5CTYPE_--3D_--25_T00004S00000371O0000147040><item><PROGRAM>SAPMF05A</PROGRAM><DYNPRO>0100</DYNPRO><DYNBEGIN>X</DYNBEGIN><FNAM/><FVAL/></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BDC_CURSOR</FNAM><FVAL>RF05A-NEWKO</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BKPF-BLDAT</FNAM><FVAL>25.05.2022</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BKPF-BLART</FNAM><FVAL>WB</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BKPF-BUKRS</FNAM><FVAL>1700</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BKPF-BUDAT</FNAM><FVAL>25.05.2022</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BKPF-WAERS</FNAM><FVAL>PLN</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BKPF-XBLNR</FNAM><FVAL>PBE01PL41022056</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BKPF-BKTXT</FNAM><FVAL>0000375800001</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>RF05A-NEWBS</FNAM><FVAL>40</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>RF05A-NEWKO</FNAM><FVAL>1232000000</FVAL></item><item><PROGRAM>SAPMF05A</PROGRAM><DYNPRO>0300</DYNPRO><DYNBEGIN>X</DYNBEGIN><FNAM/><FVAL/></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BSEG-WRBTR</FNAM><FVAL>269,98</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BSEG-VALUT</FNAM><FVAL>25.05.2022</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BSEG-ZUONR</FNAM><FVAL>0000375800001PLN</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BSEG-SGTXT</FNAM><FVAL>NONREF 020152 ZAM.PL146751217, FVKOR/002211/2205/2</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BDC_CURSOR</FNAM><FVAL>RF05A-NEWKO</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>RF05A-NEWBS</FNAM><FVAL>50</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>RF05A-NEWKO</FNAM><FVAL>1430101010</FVAL></item><item><PROGRAM>SAPLKACB</PROGRAM><DYNPRO>0002</DYNPRO><DYNBEGIN>X</DYNBEGIN><FNAM/><FVAL/></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BDC_OKCODE</FNAM><FVAL>/00</FVAL></item><item><PROGRAM>SAPMF05A</PROGRAM><DYNPRO>0300</DYNPRO><DYNBEGIN>X</DYNBEGIN><FNAM/><FVAL/></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BSEG-WRBTR</FNAM><FVAL>269,98</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BSEG-VALUT</FNAM><FVAL>25.05.2022</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BSEG-ZUONR</FNAM><FVAL>PL1467512</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BSEG-SGTXT</FNAM><FVAL>NONREF 020152 ZAM.PL111111111, FVKOR/002211/2205/2</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BDC_CURSOR</FNAM><FVAL>RF05A-NEWKO</FVAL></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BDC_OKCODE</FNAM><FVAL>/11</FVAL></item><item><PROGRAM>SAPLKACB</PROGRAM><DYNPRO>0002</DYNPRO><DYNBEGIN>X</DYNBEGIN><FNAM/><FVAL/></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BDC_OKCODE</FNAM><FVAL>/00</FVAL></item><item><PROGRAM>SAPLFCPD</PROGRAM><DYNPRO>0100</DYNPRO><DYNBEGIN>X</DYNBEGIN><FNAM/><FVAL/></item><item><PROGRAM/><DYNPRO>0000</DYNPRO><DYNBEGIN/><FNAM>BSEC-NAME1</FNAM><FVAL>CUSTOMER NAME</FVAL></item></_--5CTYPE_--3D_--25_T00004S00000371O0000147040></asx:values></asx:abap>
Data might looks slightly differently from debugger and bank statement.
There are 2 entries in SM35, first is processed correctly, but 2nd one has log entries like this:
Can somebody help me please?
Most likely you are confusing working principles of FEBAN and FF_5.
In SM35 you will see BI sessions created by FF_5. You need to process them to post real postings.
Also I recommend to retry the failed postings via FEBP transaction, which is called by FF_5 under the hood. It does almost the same as FF_5, and uses FF_5 data, but has the ability to repost the failed records.
The one interesting parameter FEBP has is Bk Pstg Only "Only post to G/L", which may be setting silently by FF_5 which may prevent you to post to subledgers. Though I can't confirm this, it's only assumption.
P.S. Also I recommend to never ever change automatically generated batch sessions like you do, not SAPLFCPD nor any others.
Problem solved. I passed records in ft[] in wrong order.
Very usefull thing is using tcode SHDB as simulation how records should be passed. At my case FT[] table should contain
SAPMF05A scr. 0100
[... required fields ...]
SAPLFCPD scr. 0100
BSEC-NAME1 <-- Injected missing field
SAPMF05A scr. 0300
[... required fields ...]
SAPMF05A SCR. 0301
[... required fields ... -> SAVE]
Topic can be closed. Thank you.

Juliaopt JuMP CbcSolver how to print progress

I coding in julia using JuMP of Juliopt.
I would like to know how to print the solve progress using CbcSolver?
I already used the log level parameter:
m = Model(solver = CbcSolver(log=1))
it works and you can choose between 0 to 3, higher more details.
but my problem is that the log level only prints after the solver finish, i already put the the time limit parameter "sec" but when it is set for higher values never stops and i don't know why!!
m = Model(solver = CbcSolver(sec=90,log=1))
I was going to try callbacks but Cbc does not support callback.
I am positive that there is a way to print because when i use the opensolver in excel a set Cbc to solve it shows the progress.I just dont know how to do this!!

Dymola Results of checkModel()

checkmodel([Some Model]) opens the GUI "Dymola Messages", tab "Translation" and displays Errors, Warnings, and Messages.
Does anyone know how to write these infos to a logfile or get them as kind of return value of checkModel(). All I've found in the documentation was, that checkModel() only returns a success-boolean. Are these infos saved temporarily somewhere?
Note, that I only want to apply checkModel() but not actually translating the code.
I finally found a solution at least for Dymola 2016 and newer, so if someone is interested - here it is (it is not very user-friendly, but it works):
The key-command is getLastError() which not only returns the last error (as one could think...), but all errors that are detected by checkModel() as well as the overall statistics.
All informations are sampled in one string, in which the last lines looks like:
"[...]
Local classes checked, checking <[Some Path]>
ERROR: 2 errors were found
WARNING: 13 warnings were issued
= false
"
Following operations will return the number of actual errors (for warnings it is more or less the same):
b = checkmodel([Some Model])
s = getLastError()
ind1 = Modelica.Utilities.Strings.findLast(s,"ERROR:")
ind2 = Modelica.Utilities.Strings.findLast(s," errors were found")
nErrors = Modelica.Utilities.Strings.substring(s,ind1+6,ind2) //6 = len(ERROR:)
nErrors = Modelica.Utilities.Strings.replace(nErrors," ","")
nErrors
= "2"
Note:
I used findLast as I know, that the lines of interest are at the very end of the string. So this is significantly faster than using find
This only works, if the line "ERROR: ...." actually exists. Otherwise, the substring call will throw an error.
Of course this could be done in less lines, but maybe this version is easier to read.
NOTE: This will only works with Dymola 2016 and newer. The return-string of getLastError is of a different structure in Dymola 2015 and older.
The following should handle it:
clearlog(); // To start fresh
Advanced.TranslationInCommandLog=true;
checkModel(...);
savelog(...);
This is mentioned in the Dymola User Manual Volume 1, section "Parameter studies by running Dymola a number of time in “batch mode”" on pg 630 or so.

Runtime Error CONVT_NO_NUMBER in program SAPLMEPO (ME21n)

When I'm creating a purchase order that have 10 items (or above), a run time error occurred. Below is the error message.
Category: ABAP Programming Error
Runtime Errors: CONVT_NO_NUMBER
ABAP Program: SAPLMEPO
Include MM06EF0B_BUCHEN
Application Component MM-PUR
An exception occurred that is explained in detail below.
This exception cannot be caught in the context of the current statement. The reason for the exception is: An attempt was made to interpret value "*" as a number. As this value contravenes the rules for displaying numbers correctly, this was not possible.
Below is the code where an exception occurred:
DATA indx.
indx = 1.
* Need to merge KNT and XEKKN
* algorithm is: if knt is old, use knt. Else use the equivalent from xekkn
LOOP AT knt.
IF knt-updkz EQ oldpos.
MOVE-CORRESPONDING knt TO lt_ekkn.
ELSE.
READ TABLE xekkn INDEX indx.
MOVE-CORRESPONDING xekkn to lt_ekkn.
indx = indx + 1.
ENDIF.
APPEND lt_ekkn.
ENDLOOP. "v 2068862
It seems that the data type of indx (char 1), but when PO item index = 9, then index = 10 (actual value is * in debug mode ), so exception is happened.
How should I solve this problem?
I also post this issue here: https://scn.sap.com/message/16146617
You are right in assuming that indx is a C(1) since you (or the author of the code) did not specify a type. Changing the line to
DATA indx TYPE i.
should solve the issue.

Setting up diagnostic error messages in large Mathematica projects

Whenever I create a large Mathematica project I run into this problem: Preventing avalanche of runtime errors in Mathematica, i.e., Mathematica's error message are opaque, archaic, and legion.
The idea then is to disable all of Mathematica's own error messages and implement type checking and error messages of your own in every Function and Module. However I have not found a simple and efficient way of doing this and end up with, e.g., some function generating an error 20 function calls deep and then get a whole cascade of error messages all the way back up to the main routine.
How would you set up a simple mechanism for this that only generates one error message at the function that experiences the error and a simple list of the chain of function calls?
EDIT: Since it has come up in a couple of answers; I am specifically looking for something lightweight regarding the output it produces (otherwise I could just stick with Mathematica's error messages) and obviously also lightweight in computational overhead. So while Stack and Trace are definitely light on the overhead, their output in complex projects is not quick to parse and some work needs to be done simplifying it.
YAsI - Yet Another (silly?) Idea ...
Re-reading your question ...
The idea then is to disable all of Mathematica's own error messages and implement type checking and error messages of your own in every Function and Module.
Found this:
$MessagePrePrint = ( #; Print[Stack[_][[;; -5]]]; Abort[]) &
v[x_, y_] := w[x, y];
w[x_, y_] := x/y;
StackComplete#v[1, 0];
During evaluation of In[267]:= {StackComplete[v[1,0]];,
StackComplete[v[1,0]], v[1,0], w[1,0], 1/0, 1/0, Message[Power::infy,1/0]}
Out[267]= $Aborted
conclusion ... Aborts at first message and leaves a "reasonable" stack trace. "Reasonable" means "Should be improved".
But it is completely non-intrusive!
To get the ball rolling here is one idea that I've been toying with; the creation of a pseudo stack.
First make a global variable theStack={} and then in every Function or Module start with AppendTo[theStack,"thisFuncName"] and end with theStack=Most#theStack. Assuming moderate (~a few tens) depth of function calls, this should not add any significant overhead.
Then implement your own typing/error checking and use Print#theStack;Abort[]; on errors.
Refinements of this method could include:
Figuring out a way to dynamically get "thisFuncionName" so that the AppendTo[] can be made into an identical function call for all Functions and Module.
Using Message[] Instead of Print[].
Pushing other important variables / stateful information on theStack.
One attempt to implement #Timo's idea (theStack)
Incomplete and perhaps flawed, but just to keep thinking about it:
Clear["Global`*"];
funcDef = t_[args___] \[CircleMinus] a_ :>
{t["nude", args] := a,
ReleaseHold[Hold[t[args] :=
(If[! ValueQ[theStack], theStack = {}];
AppendTo[theStack, ToString[t]];
Check[ss = a, Print[{"-TheStack->", Evaluate#theStack}];
Print#Hold[a]; Abort[]];
theStack = Most#theStack;
Return[ss])
]]};
v[x_, y_]\[CircleMinus] (Sin# g[x, y]) /. funcDef;
g[x_, y_]\[CircleMinus] x/y /. funcDef;
v[2, 3]
v[2, 0]
Output:
Out[299]= Sin[2/3]
During evaluation of In[295]:= Power::infy: Infinite expression 1/0 encountered. >>
During evaluation of In[295]:= {-TheStack->,{v,g}}
During evaluation of In[295]:= Hold[2/0]
Out[300]= $Aborted
A suggestion for extracting stack, maybe something that relies on Trace?
An example of using Trace below, from Chris Chiasson. This code saves evaluation tree of 1 + Sin[x + y] + Tan[x + y] into ~/temp/msgStream.m
Developer`ClearCache[];
SetAttributes[recordSteps, HoldAll];
recordSteps[expr_] :=
Block[{$Output = List#OpenWrite["~/temp/msgStream.m"]},
TracePrint[Unevaluated[expr], _?(FreeQ[#, Off] &),
TraceInternal -> True];
Close /# $Output;
Thread[
Union#Cases[
ReadList["~/temp/msgStream.m", HoldComplete[Expression]],
symb_Symbol /;
AtomQ#Unevaluated#symb &&
Context#Unevaluated#symb === "System`" :>
HoldComplete#symb, {0, Infinity}, Heads -> True],
HoldComplete]
];
recordSteps[1 + Tan[x + y] + Sin[x + y]]
To answer Samsdram's question, the code below (also from Chris) gives evaluation tree of a Mathematica expression. Here is the post from MathGroup with source code and examples.
(Attributes## = {HoldAllComplete}) & /# {traceToTreeAux, toVertex,
HoldFormComplete, getAtoms, getAtomsAux}
MakeBoxes[HoldFormComplete[args___], form_] :=
MakeBoxes[HoldForm[args], form]
edge[{head1_, pos1_, xpr1_}, {head2_, pos2_, xpr2_}] :=
Quiet[Rule[{head1, vertexNumberFunction#pos1, xpr1}, {head2,
vertexNumberFunction#pos2, xpr2}], {Rule::"rhs"}]
getAtomsAux[atom_ /; AtomQ#Unevaluated#atom] :=
Sow[HoldFormComplete#atom, getAtomsAux]
getAtomsAux[xpr_] := Map[getAtomsAux, Unevaluated#xpr, Heads -> True]
getAtoms[xpr_] := Flatten#Reap[getAtomsAux#xpr][[2]]
toVertex[traceToTreeAux[HoldForm[heldXpr_], pos_]] := toVertex[heldXpr]
toVertex[traceToTreeAux[HoldForm[heldXprs___], pos_]] :=
toVertex#traceToTreeAux[Sequence[], pos]
(*this code is strong enough to not need the ToString commands,but \
some of the resulting graph vertices give trouble to the graphing \
routines*)
toVertex[
traceToTreeAux[xpr_, pos_]] := {ToString[
Short#Extract[Unevaluated#xpr, 0, HoldFormComplete], StandardForm],
pos, ToString[Short#First#originalTraceExtract#{pos}, StandardForm]}
traceToTreeAux[xpr_ /; AtomQ#Unevaluated#xpr, ___] := Sequence[]
traceToTreeAux[_HoldForm, ___] := Sequence[]
traceToTreeAux[xpr_, pos_] :=
With[{lhs = toVertex#traceToTreeAux[xpr, pos],
args = HoldComplete ## Unevaluated#xpr},
Identity[Sequence][
ReleaseHold[
Function[Null, edge[lhs, toVertex##], HoldAllComplete] /# args],
ReleaseHold#args]]
traceToTree[xpr_] :=
Block[{vertexNumber = -1, vertexNumberFunction,
originalTraceExtract},
vertexNumberFunction[arg_] :=
vertexNumberFunction[arg] = ++vertexNumber;
originalTraceExtract[pos_] :=
Extract[Unevaluated#xpr, pos, HoldFormComplete]; {MapIndexed[
traceToTreeAux, Unevaluated#xpr, {0, Infinity}]}]
TraceTreeFormPlot[trace_, opts___] :=
Block[{$traceExpressionToTree = True},
Through#{Unprotect, Update}#SparseArray`ExpressionToTree;
SparseArray`ExpressionToTree[trace, Infinity] = traceToTree#trace;
With[{result = ToExpression#ToBoxes#TreeForm[trace, opts]},
Through#{Unprotect, Update}#SparseArray`ExpressionToTree;
SparseArray`ExpressionToTree[trace, Infinity] =.;
Through#{Update, Protect, Update}#SparseArray`ExpressionToTree;
result]];
TraceTreeFormPlot[Trace[Tan[x] + Sin[x] - 2*3 - 55]]
Perhaps we have been over thinking this. What if we just tweaked the pattern matching on the arguments a little. For instance, if we modified the function to check for a numeric quantity and added some code to print an error if it fails. For instance,
TypeNumeric[x_] := If[! NumericQ[Evaluate[x]],
Print["error at "]; Print[Stack[]]; Print["Expression "]; Print[x]; Print["Did
not return a numeric value"];Return[False],
(*Else*)
Return[True];]
SetAttributes[TypeNumeric, HoldAll];
Step 2: If you have a function, f[x_] that requires a numeric quantity, just write it with the standard pattern test and all should be well
Input:
f[x_?TypeNumeric] := Sqrt[x]
f[Log[y]]
f[Log[5]]
Output:
error at
{f}
Expression
Log[y]
Did not return a numeric value
f[Log[y]]
Sqrt[Log[5]]
I believe this will work and, it makes robust type checking as simple as a writing a function or two. The problem is that this could be hugely inefficient because this code evaluates the expression x twice, once for the type checking and once for real. This could be bad if an expensive function call is involved.
I haven't figured out the way around this second problem and would welcome suggestions on that front. Are continuations the way out of this problem?
Hope this helps.