Mathematica 9 is now available
Services & Resources / Wolfram Forums / MathGroup Archive
-----

MathGroup Archive 2009

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: Length of a held expression

  • To: mathgroup at smc.vnet.net
  • Subject: [mg96588] Re: Length of a held expression
  • From: Nikolaus Rath <Nikolaus at rath.org>
  • Date: Mon, 16 Feb 2009 16:41:09 -0500 (EST)
  • References: <gn8jdj$7qa$1@smc.vnet.net>

Hi,

Nikolaus Rath <Nikolaus at rath.org> writes:
> Hello,
>
> How can I get the length of a list in a Hold[] expression?

It seems that in my attempt to produce a short example, I also
simplified away the actual problem. So here it comes in slightly
longer form.

I have written a function that propagates uncertainties in the
parameters of a function into the uncertainty of the result. It is
used as follows:

  error[a*b, {a, b}, {aErr, bErr}]

--> {a b, Sqrt[Abs[aErr b]^2 + Abs[a bErr]^2]}

so it yields the formula again, together with its error.

However, usually the parameter already have values assigned to them
when I call the function. As was correctly pointed out, I can easily
circumvent this problem by packing the call into a Block[]:

  a = 10;
  b = 20;
  aErr = 1;
  bErr = 2;
  Block[{a,b},
      error[a*b, {a, b}, {aErr, bErr}]]

     
However, I was wondering if it might not be possible to handle this
case entirely in the error function, so that I can call

  a = 10;
  b = 20;
  aErr = 1;
  bErr = 2;
  error[a*b, {a, b}, {aErr, bErr}]

and get the correct result. *So I am not really solving an actual
problem here*, I'm just playing with Mathematica's programming model
to see if it would allows me to do such a thing.


I figured out that, in order to be really able to work with the
unevaluated expression I cannot to wrap it in Hold[], but I have to
"escape" all the parameters that might otherwise be evaluated. So what
I'm doing is this:


SetAttributes[error, HoldAll];
error::varno = "There must be the same number of variables and errors";
error[expr_, vars_, errs_] :=
  Module[{safeExpr, safeVars, res, escapeRule, restoreRule, varno},
    varno = Length[vars];
  
   If[varno != Length[errs],
    Message[error::varno];
    Throw[$Failed];
    ];
  
   (* This replaces the given variables (which may have global definition=
s) by local ones *)
   escapeRule = Table[
     Extract[Hold[vars], {1, i}, HoldPattern] -> safeVars[i],
     {i, varno}];
  
   (* This restores the original values of the variables *)
   restoreRule = Table[safeVars[i] -> vars[[i]], {i, varno}];
  
   (* Escape variables, so that we can differentiate the expression *)
   safeExpr = ReleaseHold[Hold[expr] /. escapeRule];
  
   (* Calculate result with error *)
   {expr,
    Sqrt[Plus @@ Table[
       Abs[D[safeExpr, safeVars[i]] errs[[i]] /. restoreRule ]^2,
       {i, varno}]]}
   ]

This indeed works nicely, except for one thing: in order to replace
all the global variables in the expression by local ones, I have to
iterate over the list of parameters, which in turn requires me to know
it's length.

However, if I'm calculating the length with Length[vars] as above,
vars is evaluated first which may, in theory, change its length. (I
cannot really come up with an example where this may actually happen,
but as I said I'm not trying to solve a real problem anyway).


Now that I've written this all up so nicely, I also realize that the
solution with Length[Unevaluated[vars]] will also work for this case.
I'm mailing this anyway now, since I've already spend so much time
writing it. Maybe someone else can come up with a more elegant version
to do the above, so this mail wasn't entirely pointless :-).



Best,

   -Nikolaus

--
 =C2=BBTime flies like an arrow, fruit flies like a Banana.=C2=AB

  PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6  02CF A9AD B7F8 AE4E 425C


  • Prev by Date: Re: Chain Matrix
  • Next by Date: Re: Re: Shortest Path Problem
  • Previous by thread: Re: Length of a held expression
  • Next by thread: Re: Length of a held expression