The following code works for me:

```
UHP = HyperbolicPlane().UHP() # UHP is the upper half plane IH
HM = HyperbolicPlane().HM() # HM is the hyperboloid model
a1, a2, a3 = pi/4, pi/4, pi/4 # given angles, we draw a hyperbolic triangle with these angles
def c(a1, a2, a3):
return (cos(a1) + cos(a2)*cos(a3)) / sin(a2) / sin(a3) # !!! sin(a3) is in denominator !!!
c1, c2, c3 = c(a1, a2, a3), c(a2, a3, a1), c(a3, a1, a2) # algebraic in the given example
# sides are CC(arccosh(c1)), CC(arccosh(c2)), CC(arccosh(c3))
def s(v, w):
"""v, w are vectors with three entries, we return the Minkowski product with signature ++-"""
return v*diagonal_matrix([1, 1, -1])*w # no need of a transposition
# a, b, p, q, r are used in the following coordinates in Hyperboloid model
# as a parametrization of points
myvars = var("a b p q r");
a, b, p, q, r = myvars
V1 = vector([0, 0, 1])
V2 = vector([0, a, b])
V3 = vector([p, q, r])
sols = solve([ s(V2, V2) == -1, s(V3, V3) == -1,
s(V1, V2) == -c3, s(V2, V3) == -c1, s(V3, V1) == -c2 ]
, myvars, solution_dict=True)
sols = [sol for sol in sols if sol[a] > 0 and sol[q] > 0] # so V2, V3 maps to IH
sol = sols[0] # first solution
a0, b0, p0, q0, r0 = [sol[v].simplify_full() for v in myvars]
S1, S2, S3 = vector([0, 0, 1]), vector([0, a0, b0]), vector([p0, q0, r0])
M1, M2, M3 = HM.get_point(S1), HM.get_point(S2), HM.get_point(S3)
H1, H2, H3 = UHP(M1), UHP(M2), UHP(M3) # using the coercion from HM to UHP
Q1, Q2, Q3 = H1.coordinates(), H2.coordinates(), H3.coordinates()
p = hyperbolic_polygon(pts=[Q1, Q2, Q3], model="UHP", fill=True, alpha=0.3)
g = Graphics()
g += p.plot()
g.show(axes=True, aspect_ratio=1)
```

Then the picture is as follows, and when i would have to guess which fraction(s) of $\pi$ the angles may be, i'd pick the quarter:

sage comes with more models of the hyperbolic plane, `UHP`

is one (OP), but the hyperboloid model `HM`

is also present. And we have a coercion from one world to the other one:

```
sage: UHP.has_coerce_map_from(HM)
True
```

So at this point, the geometry works for us, we can simply solve the system and coerce from the `HM`

-points directly to the `UHP`

-points. The point $M_1=(0,0,1)$ goes by the way to the point $H_1=i\in\Bbb H$ (and not to the cusp zero, it is hard to go there in time.) All computed values are exact, the complex numbers corresponding to $H_1,H_2,H_3$ are $Q_1,Q_2,Q_3$, and for them we have for instance their minimal polynomial over $\Bbb Q$:

```
sage: Q1
I
sage: Q1.minpoly()
x^2 + 1
sage: Q2
(-I*sqrt(2) - 2*I)/((sqrt(2)*sqrt(sqrt(2) + 1) - 1)*(sqrt(2) + 1) + sqrt(2)*sqrt(sqrt(2) + 1) - 2*sqrt(2) - 3)
sage: Q2.minpoly()
x^8 + 20*x^6 - 26*x^4 + 20*x^2 + 1
sage: Q3
((sqrt(2) + 1)^(3/2) - I*sqrt(2) + sqrt(sqrt(2) + 1) - 2*I)/((sqrt(2) + 1)*(sqrt(sqrt(2) + 1) - 1) - 2*sqrt(2) + sqrt(sqrt(2) + 1) - 3)
sage: Q3.minpoly()
x^8 - 4*x^6 + 22*x^4 - 4*x^2 + 1
```

**LATER EDIT:**
The above code is limited by `solve`

to the cases when solutions can be
obtained in this manner. The `solve`

way was taken to respect the OP idea to get the points, still remaining in a standard, elementary situation. When angles like $\pi/5$, $\pi/5$, $\pi/5$ are taken instead, then solutions are no longer explicit, so the `solve`

direction fails. So the above code is adapted to use an ideal in the polynomial ring in the same unknowns, the equations are easily transposed as generators of the ideal, and then the set of solutions is the "variety" associated to the ideal. From them, we pick also a first one that maps to $\Bbb H$. In order to be able to work algebraically, exact computations, $n_1,n_2,n_3$ should be below integers (or suitable rational numbers, numerators) not too big. The slightly changed code is as follows:

```
UHP = HyperbolicPlane().UHP() # UHP is the upper half plane IH
HM = HyperbolicPlane().HM() # HM is the hyperboloid model
n1, n2, n3 = 5, 5, 4
a1, a2, a3 = pi/n1, pi/n2, pi/n3 # given angles, we draw a hyperbolic triangle with these angles
N = 2*lcm([n1, n2, n3])
F.<u> = CyclotomicField(N)
def c(a1, a2, a3):
return (cos(a1) + cos(a2)*cos(a3)) / sin(a2) / sin(a3) # !!! sin(a3) is in denominator !!!
c1, c2, c3 = c(a1, a2, a3), c(a2, a3, a1), c(a3, a1, a2) # algebraic in the given example
# sides are CC(arccosh(c1)), CC(arccosh(c2)), CC(arccosh(c3))
def toUHP(M):
"""M is a point in the HM model, we construct an ad-hoc version in UHP
"""
a, b, c = M.coordinates()
a, b, c = QQbar(a), QQbar(b), QQbar(c)
return UHP(-(a + i)*(c + 1)/((b - 1)*c - a^2 - b^2 + b - 1))
def s(v, w):
"""v, w are vectors with three entries, we return the Minkowski product with signature ++-"""
return v*diagonal_matrix([1, 1, -1])*w # no need of a transposition
# a, b, p, q, r are used in the following coordinates in Hyperboloid model
# as a parametrization of points
R.<a,b,p,q,r> = PolynomialRing(F)
V1 = vector([0, 0, 1])
V2 = vector([0, a, b])
V3 = vector([p, q, r])
J = R.ideal([s(V2, V2) + 1, s(V3, V3) + 1,
s(V1, V2) + c3, s(V2, V3) + c1, s(V3, V1) + c2])
V = J.variety(ring=QQbar)
sols = [sol for sol in V if sol[a] > 0 and sol[q] > 0] # so V2, V3 maps to IH
sol = sols[0] # first solution
a0, b0, p0, q0, r0 = [sol[v].real() for v in R.gens()]
S1, S2, S3 = vector([0, 0, 1]), vector([0, a0, b0]), vector([p0, q0, r0])
M1, M2, M3 = HM.get_point(S1), HM.get_point(S2), HM.get_point(S3)
H1, H2, H3 = toUHP(M1), toUHP(M2), toUHP(M3) # using the ad-hoc coercion from HM to UHP
Q1, Q2, Q3 = H1.coordinates(), H2.coordinates(), H3.coordinates()
p = hyperbolic_polygon(pts=[Q1, Q2, Q3], model="UHP", fill=True, alpha=0.3)
g = Graphics()
g += p.plot()
g.show(axes=True, aspect_ratio=1)
```

Let us check the angles:

```
sage: H1, H2, H3
(Point in UHP I,
Point in UHP 7.753213798134539?*I,
Point in UHP -2.453248512528677? + 1.317112574501655?*I)
sage: H12 = UHP.get_geodesic(H1, H2)
sage: H23 = UHP.get_geodesic(H2, H3)
sage: H31 = UHP.get_geodesic(H3, H1)
sage: H12.angle(H23)
arccos(0.8090169943749474?)
sage: cos(H12.angle(H23)) == cos(a2)
0.8090169943749474? == 1/4*sqrt(5) + 1/4
sage: bool(cos(H12.angle(H23)) == cos(a2))
True
sage: bool(cos(H23.angle(H31)) == cos(a3))
True
sage: bool(cos(H31.angle(H12)) == cos(a1))
True
```