3
$\begingroup$

I am toying with an anharmonic oscillator with potential

LJ[delta_, w_] := (w^2 - delta*w^4)

and I want to find the turning points for oscillations in the right well.

Thanks to fellow users of this site, I got to the point where I define this function, which returns the coordinate of a turning point, given the coordinate of its mate

 findZ2[z0_] := 
 First@Values@
 ToRules@Reduce[{-LJ[0.1, x] == -LJ[0.1, z0], x != z0, 
 0 <= x <= 4}, {x}]

I create a list

rangop = Subdivide[2.5, findZ2[0], 8] // Rest
{2.58278, 2.66557, 2.74835, 2.83114, 2.91392, 2.99671, 3.07949, 3.16228}  

and try

Map[findZ2, rangop]  

receining the warning

Values::argx: Values called with 2 arguments; 1 argument is expected.

and output

{1.82462, 1.70139, 1.56415, {x -> 1.40878}, 1.22843, 1.00982, 0.718835, 0}

from which the culprit, the 4th element, is clearly visible. Why Values seems not to act on the 4th only?

If I define the function (removing the First@Values@ from the previously defined findZ2)

   findZ25[z0_] :=  ToRules@Reduce[{-LJ[0.1, x] == -LJ[0.1, z0], x != z0, 0 <= x <= 4}, {x}]
   Map[findZ25, rangop]

it outputs

{{x -> 1.82462}, {x -> 1.70139}, {x -> 1.56415}, {x -> 1.40878}, {x ->
           2.83114}, {x -> 1.22843}, {x -> 1.00982}, {x -> 0.718835}, {x -> 
           0}}

and everything seems in order. Now I issue

 Values[%]

and I get

{{1.82462}, {1.70139}, {1.56415}, {1.40878}, {2.83114}, {1.22843}, 
       {1.00982}, {0.718835}, {0}}

as expected, it removes all the associations. As a matter of fact, I am using this definition as a workaround, that is

 Flatten@Values@Map[findZ25, rangop]

does what I wanted in the first place, I get a list of turning point coordinates, related to their mates' coordinates in the list rangop.

Still, I would love to understand, why is it failing for the 4th element when the function findZ2 is used, that is when the Map command is issues at the end

Map[findZ2, rangop] 

after the associations should have been removed? Thanks a lot

$\endgroup$
0
4
$\begingroup$

Let's explore this step by step:

findZ2 /@ rangop
(* {1.93649, 1.82462, 1.70139, 1.56415, {x -> 2.83114}[
  1.40878], 1.22843, 1.00982, 0.718835, 0} *)

findZ2[rangop[[5]]]
(* {x -> 2.83114}[1.40878] *)

So the problem is not with the Map, but with how findZ2 works with a particular value.

When we unroll the definition of findZ2, we see what the problem is:

With[{z0 = 2.8311388300841895`}, 
 Reduce[{-LJ[0.1, x] == -LJ[0.1, z0], x != z0, 0 <= x <= 4}, {x}]]
(* x == 1.40878 || x == 2.83114 *)

ToRules[%]
(* Sequence[{x -> 1.40878}, {x -> 2.83114}] *)

Values[%]
(* {{x -> 2.83114}[1.40878]} *)

When you apply Values to a Sequence, what is effectively called is (remember, Sequence is not a list and is spliced automatically into any function):

Values[{x -> 2.83114}, {x -> 2.83114}]

and here is how Values behaves where it is supplied with a second argument:

Values[expr,h] gives a list of values in expr, wrapping each of them with head h before evaluation.

I hope that helps!

Update. If you want to make findZ2 robust to finding more than one value, you can do something like

findZ2[z0_] := First@Cases[
   Reduce[{-LJ[0.1, x] == -LJ[0.1, z0], x != z0, 0 <= x <= 4}, {x}],
   _?NumberQ,
   Infinity]

findZ2 /@ rangop
(* {1.93649, 1.82462, 1.70139, 1.56415, 1.40878, 1.22843, 1.00982, \
0.718835, 0} *)

Update 2. Values was updated in v12.0 (I suspect to accept the second argument, but can't tell for sure), so it should simply fail in the previous versions when supplied with two arguments instead of one.

$\endgroup$
6
  • $\begingroup$ that is great thanks, but first things first, how do you get the output between (* *) after the first command? The 4th element is given as {x -> 2.83114}[ 1.40878]. Secondly, why would this happen only for that particular value? When I apply a different order, everything works well, including that specific value. If you could expand a bit, it would be really instructive. $\endgroup$
    – Smerdjakov
    Apr 7 '20 at 20:33
  • $\begingroup$ 1) You used // Rest when you assigned rangop, so your list became 1 element shorter. 2) For all the other values, Reduce returns a single solution; but for this one, it returns 2. That's why your code works in the former but not in the latter case. $\endgroup$
    – Victor K.
    Apr 7 '20 at 20:38
  • $\begingroup$ Note that when you were applying your redefined findZ25 function, the resulting list had 9 elements, despite the original list your were mapping over had only 8. That's because the sequence returned by ToRules@Reduce was spliced into resulting list. Try List[1, 2, Sequence[3, 4], 5] and see what happens. $\endgroup$
    – Victor K.
    Apr 7 '20 at 20:41
  • $\begingroup$ I see, that explains almost everything. But how can ´With[{z0 = 2.8311388300841895´}, Reduce[{-LJ[0.1, x] == -LJ[0.1, z0], x != z0, 0 <= x <= 4}, {x}]] (* x == 1.40878 || x == 2.83114 *)´, it means the ´x != z0´ is not working for one specific element, that seems weird. $\endgroup$
    – Smerdjakov
    Apr 7 '20 at 20:49
  • 1
    $\begingroup$ we all know, right..thanks a ton, most useful $\endgroup$
    – Smerdjakov
    Apr 7 '20 at 20:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.