I am new to Mathematica, and using a Module to perform a procedure, then return a value. However, Mathematica seems to be evaluating and returning symbolic values instead of the numerical value I want.
Questions I have are: When don't you use semicolons? And when do you use Return[value] instead of just writing "value"?
DumpVar[x_] := Print[ToString[HoldForm[x]], ":", x];
SetAttributes[DumpVar, {Listable, HoldAll}]
width = 1;
interval = width/2;
panelCoeff = 2;
lightAngle = Pi/3;
(*Panel and light equations*)
panel[x_] = Abs[panelCoeff x];(*panelCoeff ((x)^2);*)
light[x_] = Tan[lightAngle]*x;
getAngleAttack[offset_] :=
Module[{bounce1x, l1a, lightSlope, panelSlope},
light[x_] = light'[x] (x - offset) + panel[interval];
DumpVar[offset];
lightSlope = N[light'[offset]];
u1S = light'[offset];
u1[x_] = (u1S (x - offset)) + panel[interval];
bounce1x =
x /. N[NSolve[u1[x] == panel[x] && x < interval && x > -interval,
x]];
u1r[x_] = panel'[bounce1x] (x - bounce1x) + panel[bounce1x];
If[Length[bounce1x] > 0,
bounce1x = bounce1x[[1]];,
bounce1x = offset;
]
If[bounce1x > -interval && bounce1x < interval,
lightSlope = N[u1'[bounce1x]];
If[x <= 0,
panelSlope := N[panelCoeff],
panelSlope := -N[panelCoeff]];
DumpVar[lightSlope];
DumpVar[panelSlope];
l1a =
N[ArcTan[(lightSlope -
panelSlope)/(1 + (panelSlope lightSlope))]];
DumpVar[l1a];
l1a
Return[l1a]
]
Return[l1a];
];
myint = getAngleAttack[0];
(*myint = N[f[10]];*)
DumpVar[myint];
Plot[{panel[x], light[x]}, {x, -.6, .6}]
myint = getAngleAttack[.5];
DumpVar[myint];
My goal is to be able to graph and integrate this function.
In the middle of your block you have:
If[Length[bounce1x] > 0,
bounce1x = bounce1x[[1]];,
bounce1x = offset;
]
The format of If
is as follows: If[Condition, ValueIfTrue, ValueIfFalse]
So If[True, 3, 2]
returns 3, and If[False, 3, 2]
returns 2. Your semicolons here are unnecessary, but you do need one at the end of the if statement:
If[Length[bounce1x] > 0,
bounce1x = bounce1x[[1]],
bounce1x = offset
];
Otherwise, Mathematica will interpret that as multiplication of that statement times whatever the next one to show up will be. In this case, you're returning null
from that If
statement, and it's being multiplied by the return value of the next If
statement that comes up.
For Module
the syntax is: Module[{localvars}, ReturnValue]
Which means whatever is the last statement that shows up without a semicolon is the ReturnValue. So for example the following module:
Module[{y},
y = x * x;
If[x < 0, -y, +y]
]
will return -y when x < 0, and +y otherwise. The one exception this is when Return
shows up. Just like in most languages, you can return early from a function by using Return
:
Module[{y},
y = x * x;
If[x < 0,
Return[-y],
Return[+y]];
(* We never reach this point to return null *)
];
With respect to your Module
, I think this may be what you're trying to accomplish:
getAngleAttack[offset_] :=
Module[{bounce1x, l1a, lightSlope, panelSlope},
light[x_] = light'[x] (x - offset) + panel[interval];
DumpVar[offset];
lightSlope = N[light'[offset]];
u1S = light'[offset];
u1[x_] = (u1S (x - offset)) + panel[interval];
bounce1x =
x /. N[NSolve[u1[x] == panel[x] && x < interval && x > -interval,
x]];
u1r[x_] = panel'[bounce1x] (x - bounce1x) + panel[bounce1x];
If[Length[bounce1x] > 0,
bounce1x = bounce1x[[1]],
bounce1x = offset];
If[bounce1x > -interval && bounce1x < interval,
lightSlope = N[u1'[bounce1x]];
If[x <= 0,
panelSlope := N[panelCoeff],
panelSlope := -N[panelCoeff]];
DumpVar[lightSlope];
DumpVar[panelSlope];
l1a = N[
ArcTan[(lightSlope - panelSlope)/(1 + (panelSlope lightSlope))]];
DumpVar[l1a];
Return[l1a]
];
l1a]
Another thing you should watch out for is any variables you use inside of a Module
. If you run the following piece of code, you'll get 4, -113/5, 32
as the output values:
d = 4 (* d was 4 *)
Module[{a, b, c},
a = 3;
b = 2;
c = 5;
d = 32; (* Uh oh! I just overwrite whatever d was *)
a^2 + b / c - d]
d (* d is now 32 *)
To avoid this, define any variables you're using as local variables within the start of the Module
: Module[{a, b, c, d}, ...]
I'd like to add a couple of things to Mike's excellent answer.
First, semi-colons are way of building compound expressions, and as Mike pointed out, they suppress the output of the immediately preceding statement. But, they're most useful in allowing you to chain multiple expressions together where only a single expression is expected, like in the body of a Module
, as you're doing. However, they're useful for simpler things like this contrived example
a = 5;
b = (Print[a]; a - 3)
Note the parentheses; ;
has a lower precedence than =
, so
b = Print[a]; a - 3
would set b to the return value of Print
which is Null
.
To incorporate what Sjoerd was saying in his comment, the expression
b = (Print[a]; a - 3)
is interpreted as
Set[b, CompoundExpression[ Print[a], a - 3] ]
while the second, incorrect, form is interpreted as
CompoundExpression[ Set[b, Print[a]], a - 3]
If you want to see what form an expression takes, use FullForm[Hold[ expression ]]
which reveals the internal form of an expression. You need to use Hold
when you don't want anything to be executed prior to examining its form, as would be the case with Set
.
Second, when using an If
expression to Set
a variable to different values, it can be pulled out of the If
statement, as follows
bounce1x = If[Length[bounce1x] > 0, bounce1x[[1]], offset];
Since If
will return either bounce1x[[1]]
or offset
. This can greatly simplify your expressions. This also works with SetDelayed
(:=
), like for panelSlope
panelSlope := If[x <= 0, N[panelCoeff], -N[panelCoeff]];
However, I wouldn't use SetDelayed
here as you don't need to recalculate panelSlope
every time you use it. Also, you can simplify that a little by using UnitStep
,
panelSlope = (1 - 2 UnitStep[x]) N[panelCoeff];
or, even
panelSlope = If[x<=0, 1, -1] N[panelCoeff];
(Sign
wouldn't be appropriate here, as it will return zero when its parameter is 0.)
Lastly, there's a bug in your code with regards to l1a
. Your Module
returns it, but if the bounce1x > -interval && bounce1x < interval
condition is not met, the If
statement where it is set is not entered. So, it will return something of the form l1a$###
where ###
are numbers. Also, I'd get rid of the Return[ l1a ]
in that If
statement entirely, as it is not necessary, l1a
is set within the If
statement.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With