--- /dev/null
+r"""
+Generate random things.
+"""
+
+from sage.matrix.constructor import matrix
+from sage.rings.real_lazy import ComplexLazyField
+from sage.rings.all import ZZ
+
+def random_unitary_matrix(F,n):
+ r"""
+ Generate a random unitary matrix of size ``n`` with entries
+ in the field ``F``.
+
+ INPUT:
+
+ - ``F`` -- a field; specifically, a subfield of the complex
+ numbers having characteristic zero.
+
+ - ``n`` -- integer; the size of the random matrix you want.
+
+ OUTPUT:
+
+ A random ``n``-by-``n`` unitary matrix with entries in ``F``. A
+ ``ValueError`` is raised if ``F`` is not an appropriate field.
+
+ REFERENCES:
+
+ - Hans Liebeck and Anthony Osborne. The Generation of All Rational
+ Orthogonal Matrices. The American Mathematical Monthly, Vol. 98,
+ No. 2. (February, 1991), pp. 131-133.
+
+ SETUP::
+
+ sage: from mjo.random import random_unitary_matrix
+
+ TESTS::
+
+ sage: n = ZZ.random_element(10)
+ sage: U = random_unitary_matrix(QQ,n)
+ sage: U.is_unitary()
+ True
+ sage: U.base_ring() is QQ
+ True
+
+ ::
+
+ sage: n = ZZ.random_element(10)
+ sage: K = QuadraticField(-1,'i')
+ sage: U = random_unitary_matrix(K,n)
+ sage: U.is_unitary()
+ True
+ sage: U.base_ring() is K
+ True
+ """
+ if not F.is_field():
+ raise ValueError("F must be a field")
+ elif not F.is_subring(ComplexLazyField()):
+ raise ValueError("F must be a subfield of the complex numbers")
+ elif not F.characteristic().is_zero():
+ raise ValueError("F must have characteristic zero")
+
+ I = matrix.identity(F,n)
+ A = matrix.random(F,n)
+ S = A - A.conjugate_transpose()
+ U = (S-I).inverse()*(S+I)
+ D = matrix.identity(F,n)
+ for i in range(n):
+ if ZZ.random_element(2).is_zero():
+ D[i,i] *= F(-1)
+ return D*U