2
$\begingroup$

I'd like to add asserts which check for condition, print useful message and abort computation on failure.

IE,

Assert[MatrixQ[mat], "mat not a matrix: "~StringJoin~ToString[mat]]

Currently using this in a function, the message is printed, but the computation continues.

I've tried various recipes in stop notebook evaluation when Assert fails , and none of them worked for me in Mathematica 12.0 (either they don't abort computation, or don't print the message, or they kill the whole kernel instead of just aborting current computation), any suggestions?

Test case:

zeroOutColumn[mat_, col_] := Module[{mask},
   Assert[MatrixQ[mat], "mat not a matrix: "~StringJoin~ToString[mat]];
   Assert[1 <= col <= Last[Dimensions[mat]], "col not a valid column"];
   mask = Array[Boole[#2 != col] &, Dimensions[mat]];
   mat*mask
   ];
zeroOutColumn[automaticHess, 80]
$\endgroup$
1
  • $\begingroup$ Is this any help?: assertFunction[HoldComplete@Assert[code_, tag_]] := (Print[tag]; Abort[]); $AssertFunction = assertFunction[##] & $\endgroup$
    – Michael E2
    Sep 22, 2019 at 14:47

2 Answers 2

1
$\begingroup$

Here is a very hacky way to achieve your goals. Conditionally redefine MakeExpression so that it fails when an assertion occurs. The evaluator will immediately stop evaluating the current cell, although it will continue to try to evaluate other cells that may be in the evaluation queue:

On[Assert]
$AssertFunction := (
    StylePrint[#[[1,2]],"Assert"];
    SelectionMove[EvaluationNotebook[], All, Notebook,AutoScroll->False];
    FrontEndTokenExecute @ "RemoveFromEvaluationQueue";
    SelectionMove[NextCell[CellStyle -> "Assert"], After, Cell, AutoScroll->False];
    $Assertion=True;
)&

MakeExpression[x_, form_] /; TrueQ@$Assertion := ($Assertion=False;Null)

Example.

Before evaluation (notice 3 cells are selected):

enter image description here

After evaluation:

ix

Notice that only Out[175] evaluated, as it was before the assert, and the assert function killed everything after the Assert.

$\endgroup$
2
  • $\begingroup$ Hm, this does something strange -- if I run my test case twice (added into question body), the second time I run it, nothing is produced. I'm also wondering if I'm misusing Assert here -- there are internal functions that abort computation + print warning when things are bad, is that done in a different way? $\endgroup$ Aug 23, 2019 at 13:40
  • $\begingroup$ If Assert is the last line in a cell then the $Assertion is not reset to False and will affect the first evaluation in future evaluations. $\endgroup$
    – Kuba
    Feb 26, 2021 at 23:42
1
$\begingroup$

This code block is from production code running on 12.1.1.0. It removes everything remaining in evaluation queue, helping to simulate "Abort Evaluation" from Evaluation menu. Then it uses nice trick from Kuba to clear out very last evaluation using "ScheduledTask"

SelectionMove[EvaluationNotebook[], All, Notebook, 
  AutoScroll -> False];
FrontEndExecute@FrontEndToken@"RemoveFromEvaluationQueue";
NotebookLocate[currentCellTag];
SessionSubmit@ScheduledTask[$Pre =., 1.];
$Pre = Abort[] &;
Abort[]

Later when I have some time I will wrap in a function and test for your use case.

For those interested here is a function that checks for messages coming from a statement, and pops up a "Continue|Abort|Pause" dialog upon such messages, using the code block above.

checkForMessagesDialogOptionToFullAbortNotebook::usage = 
  "checkForMessagesDialogOptionToFullAbortNotebook";
SetAttributes[checkForMessagesDialogOptionToFullAbortNotebook, 
  HoldFirst];
checkForMessagesDialogOptionToFullAbortNotebook[expression0_, 
  currentCellTag_String] := Block[
  {evd, dialogReturn, checkboxState},
  evd = EvaluationData[expression0];
  If[Length@evd["Messages"] > 0,
   (
    SetSelectedNotebook[EvaluationNotebook[]];
    NotebookLocate[currentCellTag];
    checkboxState = False;
    dialogReturn = DialogInput[
      Column[{
        currentCellTag,
        "Please note error messages in red.",
        "Program is misbehaving. Do you wish to abort?",
        "(Cancel to continue.)",
        Row[{
          Checkbox[Dynamic[checkboxState]],
          " Add 20 second pause"
          }],
        Row[{
          DefaultButton[DialogReturn["abort"]],
          CancelButton[DialogReturn["continue"]]
          }]
        }, Center],
      Modal -> True,
      WindowTitle -> "abort misbehaving program?"
      ];
    If[dialogReturn === "abort",
     (* very clever code from https://mathematica.stackexchange.com/a/
     99582/13738 *)
     (* for programmically doing the equivilant to menu Evaluation | 
     Abort Evaluation *)
     If[checkboxState, Pause[20.]];
     SelectionMove[EvaluationNotebook[], All, Notebook, 
      AutoScroll -> False];
     FrontEndExecute@FrontEndToken@"RemoveFromEvaluationQueue";
     NotebookLocate[currentCellTag];
     SessionSubmit@ScheduledTask[$Pre =., 1.];
     $Pre = Abort[] &;
     Abort[]
     ];
    If[dialogReturn === "continue" && checkboxState, Pause[20.]]
    )
   ];
  evd
  ]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.