@@ -1035,6 +1035,123 @@ def height(self):
10351035 except NotImplementedError :
10361036 raise NotImplementedError ('height not implemented in this case' )
10371037
1038+ def is_isomorphic (self , other , absolutely = False ):
1039+ r"""
1040+ Return ``True`` is this Drinfeld module is isomorphic to
1041+ ``other``.
1042+
1043+ INPUT:
1044+
1045+ - ``absolutely`` -- a boolean (default: ``False``); if ``True``,
1046+ check the existence of an isomorphism defined on the base
1047+ field; if ``False`` check over an algebraic closure.
1048+
1049+ EXAMPLES::
1050+
1051+ sage: Fq = GF(5)
1052+ sage: A.<T> = Fq[]
1053+ sage: K.<z> = Fq.extension(3)
1054+ sage: phi = DrinfeldModule(A, [z, 0, 1, z])
1055+ sage: t = phi.ore_variable()
1056+
1057+ We create a second Drinfeld module, which is isomorphic to `\phi`
1058+ and then check that they are indeed isomorphic::
1059+
1060+ sage: psi = phi.velu(z)
1061+ sage: phi.is_isomorphic(psi)
1062+ True
1063+
1064+ In the example below, `\phi` and `\psi` are isogeneous but not
1065+ isomorphic::
1066+
1067+ sage: psi = phi.velu(t + 1)
1068+ sage: phi.is_isomorphic(psi)
1069+ False
1070+
1071+ Here is an example of two Drinfeld modules which are isomorphic
1072+ on an algebraic closure but not on the base field::
1073+
1074+ sage: phi = DrinfeldModule(A, [z, 1])
1075+ sage: psi = DrinfeldModule(A, [z, z])
1076+ sage: phi.is_isomorphic(psi)
1077+ False
1078+ sage: phi.is_isomorphic(psi, absolutely=True)
1079+ True
1080+
1081+ On certain fields, testing isomorphisms on the base field may
1082+ fail::
1083+
1084+ sage: K = A.fraction_field()
1085+ sage: T = K.gen()
1086+ sage: phi = DrinfeldModule(A, [T, 0, 1])
1087+ sage: psi = DrinfeldModule(A, [T, 0, T])
1088+ sage: psi.is_isomorphic(phi)
1089+ Traceback (most recent call last):
1090+ ...
1091+ NotImplementedError: cannot solve the equation u^24 == T
1092+
1093+ However, it never fails over the algebraic closure::
1094+
1095+ sage: psi.is_isomorphic(phi, absolutely=True)
1096+ True
1097+
1098+ TESTS::
1099+
1100+ A Drifeld module is always isomorphic to itself::
1101+
1102+ sage: phi = DrinfeldModule(A, [T] + [K.random_element() for _ in range(3)] + [1])
1103+ sage: phi.is_isomorphic(phi)
1104+ True
1105+
1106+ Two Drinfeld modules of different ranks are never isomorphic::
1107+
1108+ sage: psi = DrinfeldModule(A, [T] + [K.random_element() for _ in range(5)] + [1])
1109+ sage: phi.is_isomorphic(psi)
1110+ False
1111+
1112+ """
1113+ if self .category () is not other .category ():
1114+ raise ValueError ("Drinfeld modules are not in the same category" )
1115+ if self is other :
1116+ return True
1117+ r = self .rank ()
1118+ if other .rank () != r :
1119+ return False
1120+ q = self ._Fq .cardinality ()
1121+ A = self .gen ()
1122+ B = other .gen ()
1123+ e = Integer (0 )
1124+ ue = self ._base (1 )
1125+ for i in range (1 , r + 1 ):
1126+ ai = A [i ]
1127+ bi = B [i ]
1128+ if ai == 0 and bi == 0 :
1129+ continue
1130+ if ai == 0 or bi == 0 :
1131+ return False
1132+ if e != q - 1 :
1133+ # u^e = ue
1134+ # u^(q^i - 1) = ai/bi
1135+ e , s , t = e .xgcd (q ** i - 1 )
1136+ ue = ue ** s * (ai / bi )** t
1137+ for i in range (1 , r + 1 ):
1138+ if A [i ]:
1139+ f = (q ** i - 1 ) // e
1140+ if A [i ] != B [i ] * ue ** f :
1141+ return False
1142+ if absolutely :
1143+ return True
1144+ else :
1145+ ue = ue .backend (force = True )
1146+ try :
1147+ _ = ue .nth_root (e )
1148+ except ValueError :
1149+ return False
1150+ except (AttributeError , NotImplementedError ):
1151+ raise NotImplementedError ("cannot solve the equation u^%s == %s" % (e , ue ))
1152+ return True
1153+
1154+
10381155 def is_supersingular (self ):
10391156 r"""
10401157 Return ``True`` whether the Drinfeld module is supersingular.
0 commit comments