Message Boards Message Boards

GROUPS:

Take real or complex entries of eigensystem or separate them as a whole

Posted 4 months ago
1126 Views
|
33 Replies
|
10 Total Likes
|

I want to do the conditional assignment of variables as shown below:

{val, vec}={{-((1 + I)/Sqrt[2]), (1 + I)/Sqrt[2], -((1 - I)/Sqrt[2]), (1 - I)/
  Sqrt[2]}, {{(1 - I)/Sqrt[2], I, (1 + I)/Sqrt[2], 
   1}, {-((1 - I)/Sqrt[2]), I, -((1 + I)/Sqrt[2]), 1}, {(1 + I)/Sqrt[
   2], -I, (1 - I)/Sqrt[2], 
   1}, {-((1 + I)/Sqrt[2]), -I, -((1 - I)/Sqrt[2]), 1}}};

If [(Select[{val, vec}//Transpose, Element[#,Reals]&]//Length)>0,
{rval,rvec}=Select[{val, vec}//Transpose, Element[#,Reals]&]
] 

But I didn't come up with a more concise method to achieve this goal. Any hints will be appreciated.

Regards,
Zhao

POSTED BY: Hongyi Zhao
33 Replies
Posted 4 months ago

What are you trying to do? On brief inspection, it seems to me like Select[{val, vec} // Transpose, Element[#, Reals] &] cannot ever be true.

Please provide a simplified example that illustrates a specific question that you have.

POSTED BY: Eric Rimbey
Posted 4 months ago

I want to calculate the eigensystem of a real matrix, and then extract the real eigenvectors and eigenvalues, if such terms exist. However, I cannot know whether such a situation exists in advance, so it must be determined in real time based on the actual calculation results.

For example, see the following calculations:

In[7]:= gen1={{-1,2,-1},{-(3/2),3/2,-(1/2)},{-(1/2),3/2,-(3/2)}};
{val, vec}=Eigensystem[%,Cubics -> True]//ComplexExpand

gen2={
{0,0,0,-1},
{1,0,0,0},
{0,-1,0,0},
{0,0,-1,0}
};
{val, vec}=gen2//Eigensystem[#,Cubics -> True]&//ComplexExpand

Out[8]= {{-1, 
I, -I}, {{1/2, 1/2, 1}, {3/2 - I/2, 3/2 + I/2, 1}, {3/2 + I/2, 
3/2 - I/2, 1}}}

Out[10]= {{-((1 + I)/Sqrt[2]), (1 + I)/Sqrt[2], -((1 - I)/Sqrt[2]), (
1 - I)/Sqrt[
2]}, {{(1 - I)/Sqrt[2], I, (1 + I)/Sqrt[2], 1}, {-((1 - I)/Sqrt[2]),
I, -((1 + I)/Sqrt[2]), 1}, {(1 + I)/Sqrt[2], -I, (1 - I)/Sqrt[2], 
1}, {-((1 + I)/Sqrt[2]), -I, -((1 - I)/Sqrt[2]), 1}}}

As you can see, in the first example, there are real eigenvalues and eigenvectors, but in the second example, there is no such result.

POSTED BY: Hongyi Zhao
Posted 4 months ago

What were you expecting this to give you?

{val, vec}//Transpose
POSTED BY: Eric Rimbey
Posted 4 months ago

See the following:

In[17]:= gen1={{-1,2,-1},{-(3/2),3/2,-(1/2)},{-(1/2),3/2,-(3/2)}};
{val1, vec1}=Eigensystem[%,Cubics -> True]//ComplexExpand;

Select[{val1, vec1}//Transpose, Element[#,Reals]&]
Select[{val1, vec1}, Element[#,Reals]&]

Out[19]= {{-1, {1/2, 1/2, 1}}}

Out[20]= {}

As you can see, without Transpose the real eigen value and eigen vector pairs can't be selected out.

POSTED BY: Hongyi Zhao
Posted 4 months ago

Obviously I can execute the code and see what it produces. The point of the question was for you to explain to me in words the semantics of the situation. At the time I asked the question I was suspicious that you had unintentionally generated a structure that would always cause your Element check to fail. I later came to realize that your structure was as you desired but you misunderstood how Element worked.

POSTED BY: Eric Rimbey
Posted 4 months ago

What qualifies? If an element at the top level of {val, vec}//Transpose contains only real values at every level?

POSTED BY: Eric Rimbey
Posted 4 months ago

Because real eigen value corresponding to real eigen vector, and vice versa. So, I think this is enough.

POSTED BY: Hongyi Zhao
Posted 4 months ago

Can you just stop making me reverse engineer your code, please? Give me a sample input that you want to process, explain what processing you're trying to do, and give me an expected result to test against.

Like, in one case, the first element of {val, vec} // Transpose is {-1, {1/2, 1/2, 1}}. Do you want that specific element to be selected or rejected?

In another case, the first element of {val, vec} // Transpose is {(-1 - I)/Sqrt[2], {(1 - I)/Sqrt[2], I, (1 + I)/Sqrt[2], 1}}. Do you want that specific element to be selected or rejected?

POSTED BY: Eric Rimbey
Posted 4 months ago

I want to select all real eigenvalue/vector pairs, so in the first example, I should select it, but in the second example, I should not.

POSTED BY: Hongyi Zhao
Posted 4 months ago

Maybe what you want is

Select[{val, vec} // Transpose, FreeQ[_Complex]]
POSTED BY: Eric Rimbey
Posted 4 months ago

Yes. This does the trick:

In[47]:= gen1={{-1,2,-1},{-(3/2),3/2,-(1/2)},{-(1/2),3/2,-(3/2)}};
{val1, vec1}=Eigensystem[%,Cubics -> True]//ComplexExpand

Select[{val1, vec1}//Transpose, Element[#,Reals]&]
Select[{val1, vec1} // Transpose, FreeQ[_Complex]]

Out[48]= {{-1, 
  I, -I}, {{1/2, 1/2, 1}, {3/2 - I/2, 3/2 + I/2, 1}, {3/2 + I/2, 
   3/2 - I/2, 1}}}

Out[49]= {{-1, {1/2, 1/2, 1}}}

Out[50]= {{-1, {1/2, 1/2, 1}}}

But my real goal is to simplify the logic of the If statement in the following code to complete the same assignment operation.

In[101]:= gen1={{-1,2,-1},{-(3/2),3/2,-(1/2)},{-(1/2),3/2,-(3/2)}};
{val1, vec1}=Eigensystem[%,Cubics -> True]//ComplexExpand;

If [(Select[{val1, vec1}//Transpose, FreeQ[_Complex]]//Length)>0,
{rval1,rvec1}=Select[{val1, vec1}//Transpose, FreeQ[_Complex]]//Transpose
]

Out[103]= {{-1}, {{1/2, 1/2, 1}}}
POSTED BY: Hongyi Zhao
Posted 4 months ago

Something like this might work

Cases[{val, vec} // Transpose // N, {_Real, {__Real}}]
POSTED BY: Eric Rimbey
Posted 4 months ago

Conversion to numerical value may cause loss of precision, so I don't want to do this.

POSTED BY: Hongyi Zhao
Posted 4 months ago

Okay, so we had two questions.

Question 1:

Given a structure like this, {a, {b, c, d}}, where a,b,c,d are all numbers, how can I determine that all of the numbers are non-complex? For example, given a list of such structures like this, {{2, {2, 2, 2}}, {I, {2, 2, 2}}, {2, {2, I, 2}}}, how could I use Select and some predicate to obtain the result {{2, {2, 2, 2}}}?

Answer 1:

Select[{{2, {2, 2, 2}}, {I, {2, 2, 2}}, {2, {2, I, 2}}}, FreeQ[_Complex]]

Question 2:

Given a condition like this, If[Length[complicatedList] > 0, myVariable = complicatedList], how can I avoid repeating complicatedList? complicatedList is actually an expression that filters and restructures a list and so is quite a large expression. I don't want to repeat it because it makes the code hard to read and error prone.

Answer 2:

First off, I recommend that you don't put the assignment inside the If. Burying assignments is a great way to cause confusion later. Instead, shoot for something like this:

myVariable = If[Length[complicatedList] > 0, complicatedList, Missing["no ducklings found"]]

This will make it much easier to trace and debug things later. You could use something else other than Missing, a default value for example. Just make sure that the assignment always happens. But this doesn't get rid of the duplication. You could use With for that:

myVariable =
 With[
  {temp = complicatedList},
  If[Length[temp] > 0, temp, Missing["no ducklings found"]]]

If you prefer terse and don't mind the hidden assignments, you could do this:

If[(myVariable = Length[complicatedList]) > 0, myVariable, myVariable = Missing["no ducklings found"]]

If for some reason the expression Length[complicatedList]) > 0 can fail to definitively produce either True or False, then you should use the 4-argument form of If.

POSTED BY: Eric Rimbey
Posted 4 months ago

The With version seems better, but the last method seem wrong:

In[437]:= {val, vec}={{-1, I, -I}, {{1/2, 1/2, 1}, {3/2 - I/2, 3/2 + I/2, 1}, {3/2 + I/2, 
   3/2 - I/2, 1}}};
myVariable =
 With[
  {temp = Select[{val, vec}//Transpose, FreeQ[_Complex]]},
  If[Length[temp] > 0, temp, Missing["no ducklings found"]]]

myVariable =If[(myVariable = Length[Select[{val, vec}//Transpose, FreeQ[_Complex]]]) > 0, myVariable, myVariable = Missing["no ducklings found"]]

Out[438]= {{-1, {1/2, 1/2, 1}}}

Out[439]= 1
POSTED BY: Hongyi Zhao
Posted 4 months ago

Yes, that was a mistake. Good catch! Can you see how to fix it? Also, this kind of mistake is easy to make, so I almost exclusively use With in such situations.

POSTED BY: Eric Rimbey
Posted 4 months ago

Can you see how to fix it?

I gave it a rough thought when I posted, but didn't seem to come up with an obvious solution.

POSTED BY: Hongyi Zhao
Posted 4 months ago
If[Length[myVariable = complicatedList] > 0, myVariable, myVariable = Missing["no ducklings found"]]

By the way, the same sort of mistake was in my other example:

myVariable = If[Length[complicatedList] > 0, complicatedList, Missing["no ducklings found"]]

I'm very frustrated at this mistake, because we're now overlooking the whole point I was trying to make about how to ask good questions. Did you get the point? Will you try that in the future? Or should I just give up?

POSTED BY: Eric Rimbey
Posted 4 months ago

I'm very frustrated at this mistake, because we're now overlooking the whole point I was trying to make about how to ask good questions. Did you get the point? Will you try that in the future? Or should I just give up?

A good or bad habit takes a long time and a lot of practice to form or correct. As far as a single problem is concerned, its role is at best to imperceptibly influence certain habits. So, I think, no matter what, it is not a bad thing. In the world, there is no absolute good or bad, everything depends on specific circumstances. It's like saying: There is no absolute truth!

POSTED BY: Hongyi Zhao
Posted 4 months ago

Here is another approach:

a = {{1, 0, 0}, {0, 0, 1}, {0, -1, 0}};
b = {{1, 0, 0}, {0, 0, 1}, {0, 1, 0}};
c = {{0, 0, 0, -1}, {1, 0, 0, 0}, {0, -1, 0, 0}, {0, 0, -1, 0}};

getRealES[m_] := Select[Eigensystem[m] // Transpose, FreeQ[Complex]] /. {} -> "None real"

In[5]:= getRealES[a]
getRealES[b]
getRealES[c]

Out[5]= {{1, {1, 0, 0}}}
Out[6]= {{-1, {0, -1, 1}}, {1, {0, 1, 1}}, {1, {1, 0, 0}}}
Out[7]= "None real"
POSTED BY: Hans Milton
Posted 4 months ago

Just a further comment on this question.

If the purpose is to distinguish all real and complex eigensystems, the following method is sufficient:

In[582]:= Unprotect[a,b,c];
Clear[a,b,c];
a = {{1, 0, 0}, {0, 0, 1}, {0, -1, 0}};
b = {{1, 0, 0}, {0, 0, 1}, {0, 1, 0}};
c = {{0, 0, 0, -1}, {1, 0, 0, 0}, {0, -1, 0, 0}, {0, 0, -1, 0}};
getRealES[m_] := Select[Eigensystem[m,Cubics -> True]//ComplexExpand, FreeQ[Complex]] /. {} -> "None real"

getRealES[a]
getRealES[b]
getRealES[c]

Out[588]= "None real"

Out[589]= {{-1, 1, 1}, {{0, -1, 1}, {0, 1, 1}, {1, 0, 0}}}

Out[590]= "None real"
POSTED BY: Hongyi Zhao
Posted 4 months ago

What's the difference between the following two usages?

FreeQ[_Complex]
FreeQ[Complex]
POSTED BY: Hongyi Zhao
Posted 4 months ago

In this case there is no difference. Two ways of saying the same thing.

POSTED BY: Hans Milton
Posted 4 months ago

A variant:

getRealES2[m_] := Select[Eigensystem[m] // Transpose, Element[#, Reals] &] /. {} :> Print["None real"]
POSTED BY: Hans Milton
Posted 4 months ago

In nature, you're defining a function by using SetDelayed (:=). So I can't find any reason to further use the following command: RuleDelayed (:>). I mean, a plain Rule (->) should be enough here.

Please correct me if I'm wrong

POSTED BY: Hongyi Zhao
Posted 4 months ago

You are right Zhao. A plain Rule works fine.

POSTED BY: Hans Milton
Posted 4 months ago

The following is a confirmation of the equivalence of the above two methods:

In[681]:= Unprotect[a,b,c];
Clear[a,b,c];
a = {{1, 0, 0}, {0, 0, 1}, {0, -1, 0}};
b = {{1, 0, 0}, {0, 0, 1}, {0, 1, 0}};
c = {{0, 0, 0, -1}, {1, 0, 0, 0}, {0, -1, 0, 0}, {0, 0, -1, 0}};

getRealES[m_] := Select[Eigensystem[m,Cubics -> True]//ComplexExpand, FreeQ[Complex]] /. {} -> "None real"
getRealES2[m_] := Select[Eigensystem[m,Cubics -> True]//ComplexExpand, Element[#, Reals] &] /. {} :> Print["None real"]

In[688]:= getRealES[a]
getRealES[b]
getRealES[c]

Out[688]= "None real"

Out[689]= {{-1, 1, 1}, {{0, -1, 1}, {0, 1, 1}, {1, 0, 0}}}

Out[690]= "None real"

In[691]:= getRealES2[a]
getRealES2[b]
getRealES2[c]

During evaluation of In[691]:= None real

Out[692]= {{-1, 1, 1}, {{0, -1, 1}, {0, 1, 1}, {1, 0, 0}}}

During evaluation of In[691]:= None real
POSTED BY: Hongyi Zhao
Posted 4 months ago

Bad code typing Zhao!

It should be:

Eigensystem[m] // Transpose

Not, as in your code:

Eigensystem[m, Cubics -> True] // ComplexExpand

Very confusing for those who want follow this thread and run the code examples by themselves

POSTED BY: Hans Milton
Posted 4 months ago

Maybe not so bad, because they can compare different possibilities, just as shown in the reply by Daniel Lichtblau.

POSTED BY: Hongyi Zhao
Posted 4 months ago

I reverse my last post. RuleDelayed is there for a reason. Without it I have seen this happening:

enter image description here

POSTED BY: Hans Milton
Posted 4 months ago

Good catch. Really, it seems that RuleDelayed is necessary.

POSTED BY: Hongyi Zhao

As pointed out, the question is quite unclear. I gather the idea is to take real eigenvalues and corresponding eigenvectors. Maybe something like this?

gen1 = {{-1, 2, -1}, {-(3/2), 3/2, -(1/2)}, {-(1/2), 3/2, -(3/2)}};
{vals, vecs} = Eigensystem[gen1, Cubics -> True] // ComplexExpand;

predicate = FreeQ[N[#], Complex] &;
realvals = Select[vals, predicate];
realvecs = Pick[vecs, Map[predicate, vals]];
realsys = {realvals, realvecs}

(* Out[252]= {{-1}, {{1/2, 1/2, 1}}} *)
POSTED BY: Daniel Lichtblau
Posted 4 months ago

As pointed out, the question is quite unclear.

I've re-titled this question as follows, with the hope that it can clear some confusion:

Take real or complex entries of eigensystem or separate them as a whole.

As for your FreeQ[N[#], Complex] &, I tried the following methods, and they all do the trick:

In[29]:= vals
Select[vals, FreeQ[N[#], Complex] &]
Select[vals, FreeQ[Complex] ]
Select[vals, FreeQ[_Complex] ]
Select[vals, Element[#, Reals]& ]

Out[29]= {-1, I, -I}

Out[30]= {-1}

Out[31]= {-1}

Out[32]= {-1}

Out[33]= {-1}

But I don't quite understand why do you use N command here.

POSTED BY: Hongyi Zhao
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract