8
$\begingroup$

I would like to know if there is a direct way to remove the rules from a list of rules.

I know that, simply, this can be done with:

 [in]  := {a,b} /. {a->1,b->2}
 [out] := {1,2}

But the output from FindMinimum returns a list with the second element as a list of rules. i.e.:

 [in]  := FindMinimum[f,x]
 [out] := {0.1234,{x->321}}

Successfully, I got rid of it the rule by using Map (/.)

 [in]  := { #[[1]], x /. #[[2]] } & @ FindMinimum[f,x]
 [out] := {0.1234,321}

But is there any other, more elegant, way?

Scratch ideas of my desired output:

Does exist a function to remove all the rules and leave behind just the values? Kind of a "RemoveRules" function

 [in]  := RemoveRules[ FindMinimum[f,x] ]
 [out] := {0.1234,321}

I've observed in more advanced coding, that _ does "nothing" over mapped lists. Maybe like this?

 [in]  := {_,x} /. FindMinimum[f,x] 
 [out] := {0.1234,321}
$\endgroup$
2
  • $\begingroup$ The function 'Values' does not work, as all the elements of the list are not rules. (the first element is a value, the second is a rule) $\endgroup$ Apr 28, 2022 at 17:50
  • 1
    $\begingroup$ This is not correct, I mean the comment you made here - see my answer to that. $\endgroup$
    – bmf
    Apr 28, 2022 at 21:34

6 Answers 6

9
$\begingroup$

I want to add this reply in response to the comment written under the OP.

The function Values does not work, as all the elements of the list are not rules. (the first element is a value, the second is a rule)

Well, it works if you Apply appropriately

Values @@@ FindMinimum[x Cos[x], {x, 2}]

values

$\endgroup$
18
  • 1
    $\begingroup$ This feels like a weird sort of hack. It was very unexpected to me. Basically we have Values@@1 === 1, but NOT Values@1 === 1, and in fact the latter emits an error. I would be uncomfortable suggesting this as a solution unless someone can show documentation or at least some semantic justification. $\endgroup$
    – lericr
    Apr 28, 2022 at 23:44
  • $\begingroup$ @lericr thanks for sharing your thoughts. I think, though, that we should be interested in Values@@@1 which works fine as you can see and not at Values@1. Am I confusing myself? $\endgroup$
    – bmf
    Apr 28, 2022 at 23:49
  • 4
    $\begingroup$ @lericr Apply applied to atoms does nothing. See "Possible Issues" of the docs for Apply. E.g. Plot @@@ 1. you could call this a documented behavior of Apply I suppose, but I agree that code should express intent. Since Values itself does not operate on numbers, I feel there is a mismatch, too. $\endgroup$
    – Michael E2
    Apr 29, 2022 at 0:01
  • 1
    $\begingroup$ "... against the rule of the site -for site maintenance and style of answering" --- I didn't say it was against any such rule. I was talking programming style, which is a matter of personal opinion and taste, I think, on which people may differ. For instance Plot @@@ Riffle[Range@Length@#, #] &@{{Sin[x], {x, 0, 2 Pi}}, {Cos[x], {x, 0, 2 Pi}}} gives me a list of plots with indices riffled in front of them, but it's a very odd way to apply Plot, more confusing than riffling after plotting. $\endgroup$
    – Michael E2
    Apr 29, 2022 at 0:25
  • 1
    $\begingroup$ @bmf I don't have a strong opinion. You might have noticed I abused Apply in one of the methods in my answer. :) $\endgroup$
    – Michael E2
    Apr 29, 2022 at 18:27
8
$\begingroup$

Let

ruleNixer = Rule[_, v_] :> v;

Example1 from the docs:

FindMinimum[x Cos[x], {x, 2}]

{-3.28837, {x -> 3.42562}}

FindMinimum[x Cos[x], {x, 2}] /. ruleNixer

{-3.28837, {3.42562}}

This can be flattened as needed.

Example 2:

FindMinimum[{x + y, 
   x + 2 y >= 3 && x >= 0 && y >= 0 && y \[Element] Integers}, {x, 
   y}] /. ruleNixer
{2., {0., 2}}

The second example clearly shows that getting rid of rules has limited usefulness. For instance, there are two variables x and y and the 0, 2 are values for those variables respectively. Removing rules removes that information too. This looks like an XY-Problem.

$\endgroup$
8
$\begingroup$

These methods work correctly with any number of variables of any dimensionality:

f1 = Last[#, #] & /@ Flatten@# &;
f2[{m_, r_}] := Flatten[{m, Values[r]}, 1]

Examples:

min1 = FindMinimum[{x . {1, 2, 3}, x \[Element] Sphere[]}, x]
min2 = FindMinimum[{x + y, {x, y} \[Element] Disk[]}, {x, y}]
{-3.74166, {x -> {-0.267261, -0.534522, -0.801784}}}

{-1.41422, {x -> -0.707108, y -> -0.707108}}
f1@min1
f1@min2
f2@min1
f2@min2
{-3.74166, {-0.267261, -0.534522, -0.801784}}

{-1.41422, -0.707108, -0.707108}

{-3.74166, {-0.267261, -0.534522, -0.801784}}

{-1.41422, -0.707108, -0.707108}
$\endgroup$
8
$\begingroup$

Odds and ends

Single and two-variable examples:

out = FindMinimum[Sin[x], x]
out2 = FindMinimum[Sin[x] + Cos[y], {x, y}]
(*
{-1., {x -> -1.5708}}
{-2., {x -> -1.5708, y -> 3.14159}}
*)

Unflattened results (can always Flatten[] them):

out /. Rule -> (#2 &)
out2 /. Rule -> (#2 &)
Apply[#2 &, out2, {2}] (* N.B. #2& @@@ -2. yields -2. *)
Extract[out2, {{1}, {2, All, 2}}]
FoldList[Values[#2] &, out2]
(*
{-1., {-1.5708}}
{-2., {-1.5708, 3.14159}}
...
*)

Flattened results (works on both one- and two-variable):

Flatten[out2 /. Rule -> (#2 &)] (* see previous set of examples *)
Cases[out2, _?NumericQ, 3](* or Cases[out2,_Real,3] for FindMinimum *)
Extract[out2, Join[{{1}}, Table[{2, j, 2}, {j, Length@Last[out2]}]]]
FoldList[Sequence @@ Values@#2 &, out2]
Level[out2, {-1}][[;; ;; 2]]
{#, ## & @@ (#2 & @@@ #2)} & @@ out2 
(*  {-2., -1.5708, 3.14159}  *)

One-variable only:

Extract[out, {{1}, {2, 1, 2}}]
(*  {-1., -1.5708}  *)

See previous see for multivariable Extract method. Often when working in a multivariable project, I define vars to be the variables and use it so I don't have to type the variables out every time:

vars = {x, y};
out2 = FindMinimum[Sin[x] + Cos[y], vars];
Extract[out2, Join[{{1}}, Thread[{2, Range@Length@vars, 2}]]]
(*  {-2., -1.5708, 3.14159}  *)

Don't forget this unasked-for method of dealing with deconstructing the solution (I'd prefer to keep the independent variable solution component as replacement rules and just separate them from the optimum):

{ymin, xmin} = FindMinimum[Sin[x], x];

Update: Another way:

sol = Last@FindMinimum[f[x, y], {x, y}];
{f, x, y} /. sol (* or {x, y, f} /. sol *)

But I wouldn't use it if reevaluating f is expensive. FindArgMin[f, vars] returns a "solution" but not in the standard form of replacement rules. So if you want neither the value of f nor a Rule-form solution, use

FindArgMin[Sin[x], x]
FindArgMin[Sin[x] + Cos[y], {x, y}];
(*  {-1.5708}  <-- N.B. a 1-vector, not a scalar *)
(*  {-1.5708, 3.14159}  *)

And complementarily, for the function value without the argument values, there is

FindMinValue[f[x], x]
$\endgroup$
2
  • 1
    $\begingroup$ (+1) Some of your methods with flattening won't work for multidimensional variables. For example, Flatten[out2 /. Rule -> (#2 &)] would be better written as Flatten[out2 /. Rule -> (#2 &), 1] or Flatten[out2] /. Rule -> (#2 &). $\endgroup$ Apr 29, 2022 at 3:29
  • $\begingroup$ @AlexeyPopkov Might not one want a solution totally flat in any problem? Whether a two variable problem is stated in terms of x and y or a two-dimensional x, the solution is the same and for, say, CSV, you'd want it flat. I can also see why one might want it the way you suggest. To me, Flatten[Reverse@out2 /. Rule -> (#2 &)] seems a commonly found structure in which value of the dependent variable follows those of the independent. For the general problem, "to remove rules from lists." Flatten[sol] /. ... destroys a solution set. We have only one simple example — not much to go on. $\endgroup$
    – Michael E2
    Apr 29, 2022 at 5:53
7
$\begingroup$

If you're needing to handle output from FindMinimum specifically, then since you know that structure you know how to "re-structure" it:

Extract[FindMinimum[x Cos[x], {x, 2}], {{1}, {2, 1, 2}}]

or

MapAt[Last@*First, FindMinimum[x Cos[x], {x, 2}], -1]

or any number of such variants.

If you're asking more generally, "how to extract the 'value' part from a Rule", then that's the same as asking, "how to extract the second part from a Rule", or equivalently, "how to extract the last part of a Rule". And so given any ruleExpr, you can do any of these (or any equivalent thing with related list-aware functions):

Last[ruleExpr]
ruleExpr[[2]]
ruleExpr[[-1]]

EDIT

Since you discovered Values, here is one way you could use that:

MapAt[First@*Values, FindMinimum[x Cos[x], {x, 2}], -1]
$\endgroup$
3
$\begingroup$

We could also employ a deconstructing function:

f[a_?NumericQ] := a
f[a : {__Rule}] := Last /@ a

Examples:

sol = FindMinimum[x Cos[x], {x, 2}]

{-3.28837, {x -> 3.42562}}

f /@ sol

{-3.28837, {3.42562}}

sol = FindMinimum[Sin[x] + Cos[y], {x, y}]

{-2., {x -> -1.5708, y -> 3.14159}}

f /@ sol

{-2., {-1.5708, 3.14159}}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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