5
$\begingroup$

I am doing some numeric computations, involving FindMinimum and FindDistributionParameters. I think these functions have some stochastic element because the answers I get on identical input sometimes are different. In rare occasions, I get an error message indicating no convergence. If this happens, I would like to repeat the calculation from the start, and repeat until convergence. If possible, I do not want to generate any messages, since in the end I am sure it will converge.

So I am looking for a wrapper of the form:

wrap[computation[]]

where computation[] is a complicated function involving FindMinimum and FindDistributionParameters that might generate messages. If messages are generated, I want wrap to detect these messages, not print them, and simply attempt to execute computation[] again. Repeat this until computation[] does not generate messages, and simply return the output of computation[].

Update: Sometimes computation[] seems to get stuck, taking a very long time. Is it possible to add a second argument to wrap[..., time], so that if computation[] takes longer than time to complete, it aborts, and starts running computation[] again?

$\endgroup$
17
  • $\begingroup$ Check ? reference.wolfram.com/language/ref/Check.html i think you can use Catch and Throw to exit a loop when a value shows up $\endgroup$
    – Alucard
    Sep 21, 2017 at 8:38
  • $\begingroup$ check also: TimeConstrained and $MessageList $\endgroup$
    – kglr
    Sep 21, 2017 at 8:47
  • $\begingroup$ @kglr But how can I keep the loop going, until no messages are generated? $\endgroup$
    – a06e
    Sep 21, 2017 at 8:52
  • $\begingroup$ becko, While[$MessageList =!= {}, computation[]]? $\endgroup$
    – kglr
    Sep 21, 2017 at 9:11
  • $\begingroup$ Check[computation[],computation[] ] ? $\endgroup$
    – Alucard
    Sep 21, 2017 at 9:21

1 Answer 1

7
$\begingroup$

If you want to repeat evaluation of some expression until no messages have been generated (possibly indefinitely) you can use Check recursively.

SetAttributes[repeatOnMessage, HoldAll];
repeatOnMessage[expr_] := Quiet@Check[expr, repeatOnMessage[expr]]

Let's define a test function that issues a message (and takes some time doing so) most of the time.

f::msg = "some message has been issued.";
f[] := If[RandomReal[] > 0.1, (Pause[1]; Message[f::msg]), "result"]

Now the following loops until a result is returned (possibly indefinitely if f were to never return without a message):

repeatOnMessage[f[]]

To address your second question you can use TimeConstrained inside repeatOnMessage as in

failed::msg = "Computation has been aborted";
repeatOnMessage[TimeConstrained[f[], 0.5, Message[failed::msg]]]

Note that using the third argument of TimeConstrained is needed to issue a message, otherwise TimeConstrained returns $Aborted which is not caught by Check inside repeatOnMessage.

In a real setting it would probably be wise to use TimeConstrained on the call of repeatOnMessage itself, to not have it recurse indefinitely if the expression does never return without a message.

TimeConstrained[repeatOnMessage[TimeConstrained[f[], 0.5, Message[failed::msg]]], 4]

Using this scheme allows you to

  1. specify how long each inner call may take to reach a result before retrying

  2. specify how long the expression should be reevaluated before giving up completely (and what to do in this case)

$\endgroup$
4
  • $\begingroup$ I think that repeatOnMessage[TimeConstrained[f[], 0.5, Message[failed::msg]]] will repeat the calculation whenever f[] takes less than 0.5 seconds to complete. This is the opposite of what I want. $\endgroup$
    – a06e
    Sep 21, 2017 at 13:12
  • $\begingroup$ @becko repeatOnMessage[expr] repeats evaluating expr whenever a message is issues from within expr. That is all it does. TimeConstrained[f[], 0.5, Message[failed::msg]] does evaluate f[] and issues a message if the time constrained is reached. repeatOnMessage then kicks in and tries evaluating TimeConstrained[f[], 0.5, Message[failed::msg]] again. $\endgroup$
    – Sascha
    Sep 21, 2017 at 13:51
  • $\begingroup$ Actually, TimeConstrained[f[], 0.5, Message[failed::msg]] issues a message if the time constraint is not met. reference.wolfram.com/language/ref/TimeConstrained.html. $\endgroup$
    – a06e
    Sep 21, 2017 at 14:12
  • 1
    $\begingroup$ Isn't this what you want? Evaluation is aborted by TimeConstrained if it takes longer than 0.5s and the result returned if a result is found in time. Try TimeConstrained[(Pause[1]; "finished in time!"), 0.5, "not finished in time!"] to see what is returned when. $\endgroup$
    – Sascha
    Sep 21, 2017 at 14:26

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.