Today, I answered a question of mine that asked two month ago. Please see here
Now I would like to add the argument checking in this function. Then I used a method that Mr.Wizard answered
Requirement for the arguments of Bernstein[n,i,u]
n
must be a integer like $1,2,3,...$;i
must be a integer like $1,2,3,...$;i
should between0
andn-1
.
For instance, the built-in BernsteinBasis
gives the warning information as below:
BernsteinBasis[1.2, 2, 3]
BernsteinBasis::intnm: Non-negative machine-sized integer expected at position 1 in BernsteinBasis[1.2,2,3]. >>
BernsteinBasis[1.2, 2.1, 3]
BernsteinBasis::intnm: Non-negative machine-sized integer expected at position 1 in BernsteinBasis[1.2,2.1,3]. >>
BernsteinBasis::intnm: Non-negative machine-sized integer expected at position 2 in BernsteinBasis[1.2,2.1,3]. >>
BernsteinBasis[4, 5, u]
BernsteinBasis::invidx2:Index 5 should be a machine-sized integer between 0 and 4. >>
checkArgs
Attributes[checkArgs] = {HoldAll};
(*check the number of arguments*)
checkArgs [func_[args___]] /; Length@{args} != 3 :=
Message[func::argrx, func, Length@{args}, 3]
(*check the type of the first arguments*)
checkArgs [func_[a_, b_, c_]] /; ! MatchQ[a, _Integer?NonNegative] :=
Message[func::intnm, func[a, b, c], 1]
(*check the type of second arguments*)
checkArgs [func_[a_, b_, c_]] /; ! MatchQ[b, _Integer?NonNegative] :=
Message[func::intnm, func[a, b, c], 2]
checkArgs[func_[a_, b_, c_]] /; ! (0 <= b <= a - 1) :=
Message[func::invidx, b, 0, a - 1]
(*other valid cases*)
checkArgs[other_] := True
Main implementation
Bernstein::invidx =
"The index `1` should be a non-negative machine-sized integer betwwen `2` and `3`.";
SetAttributes[Bernstein, {Listable, NHoldAll, NumericFunction}]
(*special cases*)
Bernstein[n_, i_, u_]?checkArgs /; i < 0 || i > n := 0
Bernstein[0, 0, u_]?checkArgs := 1
Bernstein[n_, i_, u_?NumericQ]?checkArgs :=
Binomial[n, i] u^i (1 - u)^(n - i)
(*expansion of the basis of Bernstein*)
Bernstein /: PiecewiseExpand[Bernstein[n_, i_, u_]] :=
Piecewise[
{{Binomial[n, i] u^i (1 - u)^(n - i), 0 <= u <= 1},
{0, u > 1 || u < 0}}]
(*the derivatives of the basis of Bernstein*)
Bernstein /: Derivative[0, 0, k_Integer?Positive][Bernstein] :=
Function[{n, i, u},
D[
n (Bernstein[n - 1, i - 1, u] - Bernstein[n - 1, i, u]),
{u, k - 1}]
]
However, it gives the following information.
$RecursionLimit::reclim: Recursion depth of 256 exceeded. >>
$RecursionLimit::reclim: Recursion depth of 256 exceeded. >>
$RecursionLimit::reclim: Recursion depth of 256 exceeded. >>
General::stop: Further output of $RecursionLimit::reclim will be suppressed during this calculation. >>
Bernstein::intnm: Non-negative machine-sized integer expected at position >Bernstein[n_,i_,u_] in 1. >>
Update
Thanks for Mr.Wizard's revision that adding HoldForm
in checkArgs
to remove the recursion.
In addition, Mr.Wizard given me a hint that ultilizing the Message as a side-effect in the comment
Now I have a reference here
SyntaxInformation[f] = {"ArgumentsPattern" -> {_}};
f[1] := True
f[_] := False
f[x___] /; Message[f::argx, "f", Length@{x}] := Null
Additional, The Toad has a comment as below:
I just remembered why I don't use this in my packages... if you have different messages being thrown based on the form of the input (as I often have), then throwing messages as a side-effect of not matching the form will result in all messages being thrown
However, this demo just for one argument, and when the number of argument greater than $1$, I have any idea to deal with Message with side-effect.
Comments
Post a Comment