| 2557 | | sage: N.eigenspaces() |
|---|
| 2558 | | Traceback (most recent call last): |
|---|
| 2559 | | ... |
|---|
| 2560 | | NotImplementedError: won't use generic algorithm for inexact base rings, pass the option even_if_inexact=True if you really want this. |
|---|
| 2561 | | |
|---|
| 2562 | | But you can ask for (and receive!) garbage: |
|---|
| 2563 | | sage: M.eigenspaces(even_if_inexact=True) #random |
|---|
| 2564 | | [ |
|---|
| 2565 | | (2.6180340, Vector space of degree 2 and dimension 0 over Real Field with 30 bits of precision |
|---|
| 2566 | | User basis matrix: |
|---|
| 2567 | | []), |
|---|
| 2568 | | (0.38196601, Vector space of degree 2 and dimension 0 over Real Field with 30 bits of precision |
|---|
| 2569 | | User basis matrix: |
|---|
| 2570 | | []) |
|---|
| 2571 | | ] |
|---|
| 2572 | | |
|---|
| 2573 | | sage: N.eigenspaces(even_if_inexact=True) #random |
|---|
| 2574 | | [ |
|---|
| 2575 | | (2.6180340, Vector space of degree 2 and dimension 0 over Complex Field with 30 bits of precision |
|---|
| 2576 | | User basis matrix: |
|---|
| 2577 | | []), |
|---|
| 2578 | | (0.38196601, Vector space of degree 2 and dimension 0 over Complex Field with 30 bits of precision |
|---|
| 2579 | | User basis matrix: |
|---|
| 2580 | | []) |
|---|
| 2581 | | ] |
|---|
| 2582 | | |
|---|
| 2583 | | |
|---|
| 2584 | | """ |
|---|
| 2585 | | x = self.fetch('eigenspaces') |
|---|
| 2586 | | if not x is None: |
|---|
| 2587 | | return x |
|---|
| 2588 | | |
|---|
| 2589 | | if not self.base_ring().is_exact() and not even_if_inexact: |
|---|
| 2590 | | raise NotImplementedError, "won't use generic algorithm for inexact base rings, pass the option even_if_inexact=True if you really want this." |
|---|
| | 2586 | sage: N.eigenspaces_left() # random output from numerical issues |
|---|
| | 2587 | [ |
|---|
| | 2588 | (2.6180340, Vector space of degree 2 and dimension 0 over Complex Field with 30 bits of precision |
|---|
| | 2589 | User basis matrix: |
|---|
| | 2590 | []), |
|---|
| | 2591 | (0.38196601, Vector space of degree 2 and dimension 0 over Complex Field with 30 bits of precision |
|---|
| | 2592 | User basis matrix: |
|---|
| | 2593 | []) |
|---|
| | 2594 | ] |
|---|
| | 2595 | """ |
|---|
| | 2596 | x = self.fetch('eigenspaces_left') |
|---|
| | 2597 | if not x is None: |
|---|
| | 2598 | if algebraic_multiplicity: |
|---|
| | 2599 | return x |
|---|
| | 2600 | else: |
|---|
| | 2601 | return [(e[0],e[1]) for e in x] |
|---|
| | 2602 | |
|---|
| | 2603 | if not self.base_ring().is_exact(): |
|---|
| | 2604 | from warnings import warn |
|---|
| | 2605 | warn("Using generic algorithm for an inexact ring, which will probably give incorrect results due to numerical precision issues.") |
|---|
| | 2606 | |
|---|
| | 2607 | |
|---|
| 2615 | | self.cache('eigenspaces', V) |
|---|
| | 2632 | self.cache('eigenspaces_left', V) |
|---|
| | 2633 | if algebraic_multiplicity: |
|---|
| | 2634 | return V |
|---|
| | 2635 | else: |
|---|
| | 2636 | return Sequence([(e[0],e[1]) for e in V], cr=True) |
|---|
| | 2637 | |
|---|
| | 2638 | def eigenspaces_right(self, var='a', algebraic_multiplicity=False): |
|---|
| | 2639 | r""" |
|---|
| | 2640 | Compute right eigenspaces of a matrix. |
|---|
| | 2641 | |
|---|
| | 2642 | If algebraic_multiplicity=False, return a list of pairs |
|---|
| | 2643 | (e, V) |
|---|
| | 2644 | where e runs through all eigenvalues (up to Galois |
|---|
| | 2645 | conjugation) of this matrix, and V is the corresponding right |
|---|
| | 2646 | eigenspace. |
|---|
| | 2647 | |
|---|
| | 2648 | If algebraic_multiplicity=True, return a list of pairs |
|---|
| | 2649 | (e, V, n) |
|---|
| | 2650 | where e and V are as above and n is the algebraic multiplicity |
|---|
| | 2651 | of the eigenvalue. If the eigenvalue is a root of a |
|---|
| | 2652 | polynomial, then the algebraic multiplicity is for each root |
|---|
| | 2653 | separately. |
|---|
| | 2654 | |
|---|
| | 2655 | The eigenspaces are returned sorted by the corresponding characteristic |
|---|
| | 2656 | polynomials, where polynomials are sorted in dictionary order starting |
|---|
| | 2657 | with constant terms. |
|---|
| | 2658 | |
|---|
| | 2659 | INPUT: |
|---|
| | 2660 | var -- variable name used to represent elements of |
|---|
| | 2661 | the root field of each irreducible factor of |
|---|
| | 2662 | the characteristic polynomial |
|---|
| | 2663 | I.e., if var='a', then the root fields |
|---|
| | 2664 | will be in terms of a0, a1, a2, ..., ak. |
|---|
| | 2665 | |
|---|
| | 2666 | WARNING: Uses a somewhat naive algorithm (simply factors the |
|---|
| | 2667 | characteristic polynomial and computes kernels directly over |
|---|
| | 2668 | the extension field). TODO: Maybe implement the better |
|---|
| | 2669 | algorithm that is in dual_eigenvector in sage/modular/hecke/module.py. |
|---|
| | 2670 | |
|---|
| | 2671 | EXAMPLES: |
|---|
| | 2672 | We compute the right eigenspaces of a $3\times 3$ rational matrix. |
|---|
| | 2673 | sage: A = matrix(QQ,3,3,range(9)); A |
|---|
| | 2674 | [0 1 2] |
|---|
| | 2675 | [3 4 5] |
|---|
| | 2676 | [6 7 8] |
|---|
| | 2677 | sage: es = A.eigenspaces_right(); es |
|---|
| | 2678 | [ |
|---|
| | 2679 | (0, Vector space of degree 3 and dimension 1 over Rational Field |
|---|
| | 2680 | User basis matrix: |
|---|
| | 2681 | [ 1 -2 1]), |
|---|
| | 2682 | (a1, Vector space of degree 3 and dimension 1 over Number Field in a1 with defining polynomial x^2 - 12*x - 18 |
|---|
| | 2683 | User basis matrix: |
|---|
| | 2684 | [ 1 1/5*a1 + 2/5 2/5*a1 - 1/5]) |
|---|
| | 2685 | ] |
|---|
| | 2686 | sage: es = A.eigenspaces_right(algebraic_multiplicity=True); es |
|---|
| | 2687 | [ |
|---|
| | 2688 | (0, Vector space of degree 3 and dimension 1 over Rational Field |
|---|
| | 2689 | User basis matrix: |
|---|
| | 2690 | [ 1 -2 1], 1), |
|---|
| | 2691 | (a1, Vector space of degree 3 and dimension 1 over Number Field in a1 with defining polynomial x^2 - 12*x - 18 |
|---|
| | 2692 | User basis matrix: |
|---|
| | 2693 | [ 1 1/5*a1 + 2/5 2/5*a1 - 1/5], 1) |
|---|
| | 2694 | ] |
|---|
| | 2695 | sage: e, v, n = es[0]; v = v.basis()[0] |
|---|
| | 2696 | sage: delta = v*e - A*v |
|---|
| | 2697 | sage: abs(abs(delta)) < 1e-10 |
|---|
| | 2698 | True |
|---|
| | 2699 | |
|---|
| | 2700 | |
|---|
| | 2701 | The same computation, but with implicit base change to a field: |
|---|
| | 2702 | sage: A = matrix(ZZ,3,range(9)); A |
|---|
| | 2703 | [0 1 2] |
|---|
| | 2704 | [3 4 5] |
|---|
| | 2705 | [6 7 8] |
|---|
| | 2706 | sage: A.eigenspaces_right() |
|---|
| | 2707 | [ |
|---|
| | 2708 | (0, Vector space of degree 3 and dimension 1 over Rational Field |
|---|
| | 2709 | User basis matrix: |
|---|
| | 2710 | [ 1 -2 1]), |
|---|
| | 2711 | (a1, Vector space of degree 3 and dimension 1 over Number Field in a1 with defining polynomial x^2 - 12*x - 18 |
|---|
| | 2712 | User basis matrix: |
|---|
| | 2713 | [ 1 1/5*a1 + 2/5 2/5*a1 - 1/5]) |
|---|
| | 2714 | ] |
|---|
| | 2715 | |
|---|
| | 2716 | |
|---|
| | 2717 | TESTS: |
|---|
| | 2718 | Warnings are issued if the generic algorithm is used over inexact fields. Garbage may result in these cases because of numerical precision issues. |
|---|
| | 2719 | sage: R=RealField(30) |
|---|
| | 2720 | sage: M=matrix(R,2,[2,1,1,1]) |
|---|
| | 2721 | sage: M.eigenspaces_right() # random output from numerical issues |
|---|
| | 2722 | [(2.6180340, |
|---|
| | 2723 | Vector space of degree 2 and dimension 0 over Real Field with 30 bits of precision |
|---|
| | 2724 | User basis matrix: |
|---|
| | 2725 | []), |
|---|
| | 2726 | (0.38196601, |
|---|
| | 2727 | Vector space of degree 2 and dimension 0 over Real Field with 30 bits of precision |
|---|
| | 2728 | User basis matrix: |
|---|
| | 2729 | [])] |
|---|
| | 2730 | sage: R=ComplexField(30) |
|---|
| | 2731 | sage: N=matrix(R,2,[2,1,1,1]) |
|---|
| | 2732 | sage: N.eigenspaces_right() # random output from numerical issues |
|---|
| | 2733 | [(2.6180340, |
|---|
| | 2734 | Vector space of degree 2 and dimension 0 over Complex Field with 30 bits of precision |
|---|
| | 2735 | User basis matrix: |
|---|
| | 2736 | []), |
|---|
| | 2737 | (0.38196601, |
|---|
| | 2738 | Vector space of degree 2 and dimension 0 over Complex Field with 30 bits of precision |
|---|
| | 2739 | User basis matrix: |
|---|
| | 2740 | [])] |
|---|
| | 2741 | """ |
|---|
| | 2742 | return self.transpose().eigenspaces_left(var=var, algebraic_multiplicity=algebraic_multiplicity) |
|---|
| | 2743 | |
|---|
| | 2744 | right_eigenspaces = eigenspaces_right |
|---|
| | 2745 | |
|---|
| | 2746 | def eigenvalues(self): |
|---|
| | 2747 | r""" |
|---|
| | 2748 | Return a sequence of the eigenvalues of a matrix, with |
|---|
| | 2749 | multiplicity. If the eigenvalues are roots of polynomials in |
|---|
| | 2750 | CC, then QQbar elements are returned that represent each |
|---|
| | 2751 | separate root. |
|---|
| | 2752 | |
|---|
| | 2753 | EXAMPLES: |
|---|
| | 2754 | sage: a = matrix(QQ, 4, range(16)); a |
|---|
| | 2755 | [ 0 1 2 3] |
|---|
| | 2756 | [ 4 5 6 7] |
|---|
| | 2757 | [ 8 9 10 11] |
|---|
| | 2758 | [12 13 14 15] |
|---|
| | 2759 | sage: sorted(a.eigenvalues(), reverse=True) |
|---|
| | 2760 | [32.46424919657298?, 0, 0, -2.464249196572981?] |
|---|
| | 2761 | |
|---|
| | 2762 | sage: a=matrix([(1, 9, -1, -1), (-2, 0, -10, 2), (-1, 0, 15, -2), (0, 1, 0, -1)]) |
|---|
| | 2763 | sage: a.eigenvalues() |
|---|
| | 2764 | [-0.9386318578049146?, 15.50655435353258?, 0.2160387521361705? + 4.713151979747493?*I, 0.2160387521361705? - 4.713151979747493?*I] |
|---|
| | 2765 | |
|---|
| | 2766 | A symmetric matrix a+a.transpose() should have real eigenvalues |
|---|
| | 2767 | sage: b=a+a.transpose() |
|---|
| | 2768 | sage: ev = b.eigenvalues(); ev |
|---|
| | 2769 | [-8.35066086057957?, -1.107247901349379?, 5.718651326708515?, 33.73925743522043?] |
|---|
| | 2770 | |
|---|
| | 2771 | The eigenvalues are elements of QQbar, so they really |
|---|
| | 2772 | represent exact roots of polynomials, not just approximations. |
|---|
| | 2773 | sage: e = ev[0]; e |
|---|
| | 2774 | -8.35066086057957? |
|---|
| | 2775 | sage: p = e.minpoly(); p |
|---|
| | 2776 | x^4 - 30*x^3 - 171*x^2 + 1460*x + 1784 |
|---|
| | 2777 | sage: p(e) == 0 |
|---|
| | 2778 | True |
|---|
| | 2779 | sage: e.as_number_field_element() |
|---|
| | 2780 | (Number Field in a with defining polynomial y^4 - 2*y^3 - 507*y^2 + 4988*y - 8744, |
|---|
| | 2781 | -a + 8, |
|---|
| | 2782 | Ring morphism: |
|---|
| | 2783 | From: Number Field in a with defining polynomial y^4 - 2*y^3 - 507*y^2 + 4988*y - 8744 |
|---|
| | 2784 | To: Algebraic Real Field |
|---|
| | 2785 | Defn: a |--> 16.35066086057957?) |
|---|
| | 2786 | |
|---|
| | 2787 | """ |
|---|
| | 2788 | x = self.fetch('eigenvalues') |
|---|
| | 2789 | if not x is None: |
|---|
| | 2790 | return x |
|---|
| | 2791 | |
|---|
| | 2792 | if not self.base_ring().is_exact(): |
|---|
| | 2793 | from warnings import warn |
|---|
| | 2794 | warn("Using generic algorithm for an inexact ring, which will probably give incorrect results due to numerical precision issues.") |
|---|
| | 2795 | |
|---|
| | 2796 | from sage.rings.qqbar import QQbar |
|---|
| | 2797 | G = self.fcp() # factored charpoly of self. |
|---|
| | 2798 | V = [] |
|---|
| | 2799 | i=0 |
|---|
| | 2800 | for h, e in G: |
|---|
| | 2801 | if h.degree() == 1: |
|---|
| | 2802 | alpha = [-h[0]/h[1]] |
|---|
| | 2803 | else: |
|---|
| | 2804 | F = h.root_field('%s%s'%('a',i)) |
|---|
| | 2805 | alpha = F.gen(0).galois_conjugates(QQbar) |
|---|
| | 2806 | V.extend(alpha*e) |
|---|
| | 2807 | i+=1 |
|---|
| | 2808 | V = Sequence(V) |
|---|
| | 2809 | self.cache('eigenvalues', V) |
|---|
| | 2811 | |
|---|
| | 2812 | |
|---|
| | 2813 | |
|---|
| | 2814 | def eigenvectors_left(self): |
|---|
| | 2815 | r""" |
|---|
| | 2816 | Compute the left eigenvectors of a matrix. |
|---|
| | 2817 | |
|---|
| | 2818 | For each distinct eigenvalue, returns a list of the form |
|---|
| | 2819 | (e,V,n) |
|---|
| | 2820 | where e is the eigenvalue, V is a list of eigenvectors forming |
|---|
| | 2821 | a basis for the corresponding left eigenspace, and n is the |
|---|
| | 2822 | algebraic multiplicity of the eigenvalue. |
|---|
| | 2823 | |
|---|
| | 2824 | EXAMPLES: |
|---|
| | 2825 | We compute the left eigenvectors of a $3\times 3$ rational matrix. |
|---|
| | 2826 | sage: A = matrix(QQ,3,3,range(9)); A |
|---|
| | 2827 | [0 1 2] |
|---|
| | 2828 | [3 4 5] |
|---|
| | 2829 | [6 7 8] |
|---|
| | 2830 | sage: es = A.eigenvectors_left(); es |
|---|
| | 2831 | [(0, [ |
|---|
| | 2832 | (1, -2, 1) |
|---|
| | 2833 | ], 1), |
|---|
| | 2834 | (-1.348469228349535?, [(1, 0.3101020514433644?, -0.3797958971132713?)], 1), |
|---|
| | 2835 | (13.348469228349534?, [(1, 1.289897948556636?, 1.5797958971132712?)], 1)] |
|---|
| | 2836 | sage: eval, [evec], mult = es[0] |
|---|
| | 2837 | sage: delta = eval*evec - evec*A |
|---|
| | 2838 | sage: abs(abs(delta)) < 1e-10 |
|---|
| | 2839 | True |
|---|
| | 2840 | """ |
|---|
| | 2841 | x = self.fetch('eigenvectors_left') |
|---|
| | 2842 | if not x is None: |
|---|
| | 2843 | return x |
|---|
| | 2844 | |
|---|
| | 2845 | if not self.base_ring().is_exact(): |
|---|
| | 2846 | from warnings import warn |
|---|
| | 2847 | warn("Using generic algorithm for an inexact ring, which may result in garbarge from numerical precision issues.") |
|---|
| | 2848 | |
|---|
| | 2849 | V = [] |
|---|
| | 2850 | from sage.rings.qqbar import QQbar |
|---|
| | 2851 | from sage.categories.homset import hom |
|---|
| | 2852 | eigenspaces = self.eigenspaces_left(algebraic_multiplicity=True) |
|---|
| | 2853 | evec_list=[] |
|---|
| | 2854 | n = self._nrows |
|---|
| | 2855 | evec_eval_list = [] |
|---|
| | 2856 | for ev in eigenspaces: |
|---|
| | 2857 | eigval = ev[0] |
|---|
| | 2858 | eigbasis = ev[1].basis() |
|---|
| | 2859 | eigmult = ev[2] |
|---|
| | 2860 | if hasattr(eigval, 'galois_conjugates'): |
|---|
| | 2861 | eigval_conj = eigval.galois_conjugates(QQbar) |
|---|
| | 2862 | for e in eigval_conj: |
|---|
| | 2863 | m = hom(eigval.parent(), e.parent(), e) |
|---|
| | 2864 | space = (e.parent())**n |
|---|
| | 2865 | evec_list = [(space)([m(i) for i in v]) for v in eigbasis] |
|---|
| | 2866 | evec_eval_list.append( (e, evec_list, eigmult)) |
|---|
| | 2867 | else: |
|---|
| | 2868 | evec_eval_list.append((eigval, eigbasis, eigmult)) |
|---|
| | 2869 | return evec_eval_list |
|---|
| | 2870 | |
|---|
| | 2871 | left_eigenvectors = eigenvectors_left |
|---|
| | 2872 | |
|---|
| | 2873 | def eigenvectors_right(self): |
|---|
| | 2874 | r""" |
|---|
| | 2875 | Compute the right eigenvectors of a matrix. |
|---|
| | 2876 | |
|---|
| | 2877 | For each distinct eigenvalue, returns a list of the form |
|---|
| | 2878 | (e,V,n) |
|---|
| | 2879 | where e is the eigenvalue, V is a list of eigenvectors forming |
|---|
| | 2880 | a basis for the corresponding right eigenspace, and n is the |
|---|
| | 2881 | algebraic multiplicity of the eigenvalue. |
|---|
| | 2882 | |
|---|
| | 2883 | EXAMPLES: |
|---|
| | 2884 | We compute the right eigenvectors of a $3\times 3$ rational matrix. |
|---|
| | 2885 | sage: A = matrix(QQ,3,3,range(9)); A |
|---|
| | 2886 | [0 1 2] |
|---|
| | 2887 | [3 4 5] |
|---|
| | 2888 | [6 7 8] |
|---|
| | 2889 | sage: es = A.eigenvectors_right(); es |
|---|
| | 2890 | [(0, [ |
|---|
| | 2891 | (1, -2, 1) |
|---|
| | 2892 | ], 1), |
|---|
| | 2893 | (-1.348469228349535?, [(1, 0.1303061543300932?, -0.7393876913398137?)], 1), |
|---|
| | 2894 | (13.348469228349534?, [(1, 3.069693845669907?, 5.139387691339814?)], 1)] |
|---|
| | 2895 | sage: eval, [evec], mult = es[0] |
|---|
| | 2896 | sage: delta = eval*evec - A*evec |
|---|
| | 2897 | sage: abs(abs(delta)) < 1e-10 |
|---|
| | 2898 | True |
|---|
| | 2899 | """ |
|---|
| | 2900 | return self.transpose().eigenvectors_left() |
|---|
| | 2901 | |
|---|
| | 2902 | right_eigenvectors = eigenvectors_right |
|---|
| | 2903 | |
|---|
| | 2904 | def eigenmatrix_left(self): |
|---|
| | 2905 | r""" |
|---|
| | 2906 | Return matrices D and P, where D is a diagonal matrix of |
|---|
| | 2907 | eigenvalues and P is the corresponding matrix where the rows |
|---|
| | 2908 | are corresponding eigenvectors so that P*self = D*P. |
|---|
| | 2909 | |
|---|
| | 2910 | EXAMPLES: |
|---|
| | 2911 | sage: A = matrix(QQ,3,3,range(9)); A |
|---|
| | 2912 | [0 1 2] |
|---|
| | 2913 | [3 4 5] |
|---|
| | 2914 | [6 7 8] |
|---|
| | 2915 | sage: D, P = A.eigenmatrix_left() |
|---|
| | 2916 | sage: D |
|---|
| | 2917 | [ 0 0 0] |
|---|
| | 2918 | [ 0 -1.348469228349535? 0] |
|---|
| | 2919 | [ 0 0 13.348469228349534?] |
|---|
| | 2920 | sage: P |
|---|
| | 2921 | [ 1 -2 1] |
|---|
| | 2922 | [ 1 0.3101020514433644? -0.3797958971132713?] |
|---|
| | 2923 | [ 1 1.289897948556636? 1.5797958971132712?] |
|---|
| | 2924 | sage: P*A == D*P |
|---|
| | 2925 | True |
|---|
| | 2926 | """ |
|---|
| | 2927 | from sage.misc.flatten import flatten |
|---|
| | 2928 | evecs = self.eigenvectors_left() |
|---|
| | 2929 | D = sage.matrix.constructor.diagonal_matrix(flatten([[e[0]]*e[2] for e in evecs])) |
|---|
| | 2930 | rows = [] |
|---|
| | 2931 | for e in evecs: |
|---|
| | 2932 | rows.extend(e[1]+[e[1][0].parent().zero_vector()]*(e[2]-len(e[1]))) |
|---|
| | 2933 | P = sage.matrix.constructor.matrix(rows) |
|---|
| | 2934 | return D,P |
|---|
| | 2935 | |
|---|
| | 2936 | left_eigenmatrix = eigenmatrix_left |
|---|
| | 2937 | |
|---|
| | 2938 | def eigenmatrix_right(self): |
|---|
| | 2939 | r""" |
|---|
| | 2940 | Return matrices D and P, where D is a diagonal matrix of |
|---|
| | 2941 | eigenvalues and P is the corresponding matrix where the columns |
|---|
| | 2942 | are corresponding eigenvectors so that self*P = P*D. |
|---|
| | 2943 | |
|---|
| | 2944 | EXAMPLES: |
|---|
| | 2945 | sage: A = matrix(QQ,3,3,range(9)); A |
|---|
| | 2946 | [0 1 2] |
|---|
| | 2947 | [3 4 5] |
|---|
| | 2948 | [6 7 8] |
|---|
| | 2949 | sage: D, P = A.eigenmatrix_right() |
|---|
| | 2950 | sage: D |
|---|
| | 2951 | [ 0 0 0] |
|---|
| | 2952 | [ 0 -1.348469228349535? 0] |
|---|
| | 2953 | [ 0 0 13.348469228349534?] |
|---|
| | 2954 | sage: P |
|---|
| | 2955 | [ 1 1 1] |
|---|
| | 2956 | [ -2 0.1303061543300932? 3.069693845669907?] |
|---|
| | 2957 | [ 1 -0.7393876913398137? 5.139387691339814?] |
|---|
| | 2958 | sage: A*P == P*D |
|---|
| | 2959 | True |
|---|
| | 2960 | """ |
|---|
| | 2961 | D,P=self.transpose().eigenmatrix_left() |
|---|
| | 2962 | return D,P.transpose() |
|---|
| | 2963 | |
|---|
| | 2964 | right_eigenmatrix = eigenmatrix_right |
|---|
| | 2965 | |
|---|