7

I want to have the argument 'a' for myf2 in form of optional argument, but at the same time I need to evaluate the function only if 'a' is Numeric, see also my previous question.

Options[myf2] = {"a" -> 1};
myf2[b_?NumericQ, opts : OptionsPattern[]] := Module[{y, x, a},
   a = OptionValue["a"];
   If[NumericQ[a], First[y /.NDSolve[{a y'[x] == b y[x] Cos[x + y[x]], y[0] == 1}, 
       y, {x, 0, 30}]][10]]
   ];

datamyf2 = {#, myf2[1, #] + 0.01 RandomReal[]}&/@Range[0.5, 1.5,0.1]

model = NonlinearModelFit[datamyf2, myf2[b, "a" -> a], b, a]

When I tried to add the NumericQ test for 'a' in myf2, the problem is that it returns Null upon evaluating with symbol 'y' {myf2[1, "a" -> y]}, instead of leaving it unevaluated at all (as for the case when 'a' was specified as regular argument with a_?NumericQ)

How can I than specify that it should have numeric value for 'a' in the option?

Thanks!

Cendo
  • 681
  • 3
  • 13
  • 1
    Is there a good reason why you want a to be an optional argument? At least in your example it doesn't look optional to me. – sebhofer Aug 07 '13 at 09:43
  • I posted an example function, but in real application I'm using quite many optional arguments in a physical simulation function. In that case optional arguments are very handy, see i.e. (http://reference.wolfram.com/mathematica/tutorial/SettingUpFunctionsWithOptionalArguments.html) – Cendo Aug 07 '13 at 09:53
  • I'm still not convinced by this approach. I would rather define different parameter sets (e.g. as lists of replacement rules) and pass these sets to the function. – sebhofer Aug 07 '13 at 09:59
  • Thanks for the Accept! However, I always recommend that users wait 24-hours before selecting an answer so as to give everyone around the world a chance to reply before a question appears concluded. – Mr.Wizard Aug 07 '13 at 10:25

1 Answers1

8

This question appears to be about Options, not optional arguments. While it is true that OptionsPattern[] is a form of optional argument that is not typically how options themselves are described. Edit: I see that the tutorial refers to options as "named optional arguments" so I guess my understanding of convention was incorrect.

The meat of your question seems to be how to check an option value according to a pattern and return your expression (function call) unevaluated if it does not pass. You can do this with a Condition on the right-hand side of the definition:

Options[fn] = {"a" -> 1};

fn[b_?NumericQ, OptionsPattern[]] := 
  stuff[OptionValue["a"], b] /; NumericQ @ OptionValue["a"]

fn[3.5]
fn[3.5, "a" -> 7]
fn[3.5, "a" -> y]
stuff[1, 3.5]

stuff[7, 3.5]

fn[3.5, "a" -> y]

Note that opts : was not needed here as OptionValue is being used rather than e.g. FilterRules.

You could also make use of sharing between a condition and function body for more complicated tests or simply to avoid having to use OptionValue["a"] twice. (See mid-way through Using a PatternTest versus a Condition for pattern matching for an explanation of this behavior.)

ClearAll[fn]

Options[fn] = {"a" -> 1};

fn[b_?NumericQ, OptionsPattern[]] := 
  Module[{a = OptionValue["a"]}, stuff[a, b] /; NumericQ[a]]

fn[3.5]
fn[3.5, "a" -> 7]
fn[3.5, "a" -> y]
stuff[1, 3.5]

stuff[7, 3.5]

fn[3.5, "a" -> y]

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371