Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mathematica Module Not Returning Value

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.

like image 833
Geekgirl Avatar asked Nov 15 '11 16:11

Geekgirl


2 Answers

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}, ...]

like image 138
Mike Bailey Avatar answered Sep 20 '22 11:09

Mike Bailey


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.

like image 28
rcollyer Avatar answered Sep 23 '22 11:09

rcollyer