| 941 | def random_element(self, poly_degree=2, *args, **kwds): |
| 942 | r""" |
| 943 | Returns a random algebraic number. |
| 944 | |
| 945 | INPUT: |
| 946 | |
| 947 | - ``poly_degree`` - default: 2 - degree of the random |
| 948 | polynomial over the integers of which the returned |
| 949 | algebraic number is a root. This is not the degree of |
| 950 | the minimal polynomial of the number. Increase this |
| 951 | parameter to achieve a greater diversity of algebraic |
| 952 | numbers, at a cost of greater computation time. You can |
| 953 | also vary the distribution of the coefficients but that |
| 954 | will not vary the degree of the extension containing |
| 955 | the element. |
| 956 | |
| 957 | - ``args``, ``kwds`` - arguments and keywords passed to |
| 958 | the random number generator for elements of ``ZZ``, the |
| 959 | integers. See |
| 960 | :meth:`~sage.rings.integer_ring.IntegerRing_class.random_element` |
| 961 | for details, or see example below. |
| 962 | |
| 963 | OUTPUT: |
| 964 | |
| 965 | An element of ``QQbar``, the field of algebraic |
| 966 | numbers (see :mod:`sage.rings.qqbar`). |
| 967 | |
| 968 | ALGORITHM: |
| 969 | |
| 970 | A polynomial with degree between 1 and ``poly_degree``, |
| 971 | with random integer coefficients is created. A root of this |
| 972 | polynomial is chosen at random. The default degree is |
| 973 | 2 and the integer coefficients come from a distribution |
| 974 | heavily weighted towards $0, \pm 1, \pm 2$. |
| 975 | |
| 976 | EXAMPLES:: |
| 977 | |
| 978 | sage: a = QQbar.random_element() |
| 979 | sage: a # random |
| 980 | 0.2626138748742799? + 0.8769062830975992?*I |
| 981 | sage: a in QQbar |
| 982 | True |
| 983 | |
| 984 | sage: b = QQbar.random_element(poly_degree=20) |
| 985 | sage: b # random |
| 986 | -0.8642649077479498? - 0.5995098147478391?*I |
| 987 | sage: b in QQbar |
| 988 | True |
| 989 | |
| 990 | Parameters for the distribution of the integer coefficients |
| 991 | of the polynomials can be passed on to the random element method |
| 992 | for integers. For example, current default behavior of this method |
| 993 | returns zero about 15% of the time; if we do not include zero as a |
| 994 | possible coefficient, there will never be a zero constant term, and |
| 995 | thus never a zero root. :: |
| 996 | |
| 997 | sage: z = [QQbar.random_element(x=1, y=10) for _ in range(20)] |
| 998 | sage: QQbar(0) in z |
| 999 | False |
| 1000 | |
| 1001 | If you just want real algebraic numbers you can filter them out. |
| 1002 | Using an odd degree for the polynomials will insure some degree of |
| 1003 | success. :: |
| 1004 | |
| 1005 | sage: r = [] |
| 1006 | sage: while len(r) < 3: |
| 1007 | ... x = QQbar.random_element(poly_degree=3) |
| 1008 | ... if x in AA: |
| 1009 | ... r.append(x) |
| 1010 | sage: (len(r) == 3) and all([z in AA for z in r]) |
| 1011 | True |
| 1012 | |
| 1013 | TESTS: |
| 1014 | |
| 1015 | sage: QQbar.random_element('junk') |
| 1016 | Traceback (most recent call last): |
| 1017 | ... |
| 1018 | TypeError: polynomial degree must be an integer, not junk |
| 1019 | sage: QQbar.random_element(poly_degree=0) |
| 1020 | Traceback (most recent call last): |
| 1021 | ... |
| 1022 | ValueError: polynomial degree must be greater than zero, not 0 |
| 1023 | |
| 1024 | Random vectors already have a 'degree' keyword, so |
| 1025 | we cannot use that for the polynomial's degree. :: |
| 1026 | |
| 1027 | sage: v = random_vector(QQbar, degree=2, poly_degree=3) |
| 1028 | sage: v # random |
| 1029 | (0.4694381338921299?, -0.500000000000000? + 0.866025403784439?*I) |
| 1030 | """ |
| 1031 | import sage.rings.all |
| 1032 | import sage.misc.prandom |
| 1033 | try: |
| 1034 | poly_degree = sage.rings.all.ZZ(poly_degree) |
| 1035 | except TypeError: |
| 1036 | msg = "polynomial degree must be an integer, not {0}" |
| 1037 | raise TypeError(msg.format(poly_degree)) |
| 1038 | if poly_degree < 1: |
| 1039 | msg = "polynomial degree must be greater than zero, not {0}" |
| 1040 | raise ValueError(msg.format(poly_degree)) |
| 1041 | R = PolynomialRing(sage.rings.all.ZZ, 'x') |
| 1042 | p = R.random_element(degree=poly_degree, *args, **kwds) |
| 1043 | # degree zero polynomials have no roots |
| 1044 | # totally zero poly has degree -1 |
| 1045 | # add a random leading term |
| 1046 | if p.degree() < 1: |
| 1047 | g = R.gen(0) |
| 1048 | m = sage.misc.prandom.randint(1, poly_degree) |
| 1049 | p = p + g**m |
| 1050 | roots = p.roots(ring=QQbar, multiplicities=False) |
| 1051 | |
| 1052 | # p will have at least one root; pick one at random |
| 1053 | # could we instead just compute one root "randomly"? |
| 1054 | m = sage.misc.prandom.randint(0, len(roots)-1) |
| 1055 | return roots[m] |
| 1056 | |