cheb1 := function(n)
  chebyshev1_ := func< z, n |
    case< n | 0 : Parent(z)!1, 1 : z,
      default : 2*z*$$(z,n-1)-$$(z,n-2) >>;

  P<z> := PolynomialRing(Integers());
  return chebyshev1_(z,n);
end function;

// time cheb1(30);
// 4.500

cheb2 := function(n)
  chebyshev2_ := procedure(~Z,z,n)
    if not IsDefined(Z`cheb_poly,n+1) then
      $$(~Z,z,n-1);
      Append(~Z`cheb_poly, 2*z*Z`cheb_poly[n]-Z`cheb_poly[n-1]);
    end if;
  end procedure;

  AddAttribute(Rng,"cheb_poly");
  P<z> := PolynomialRing(Integers());
  P`cheb_poly := [P| 1, z];
  chebyshev2_(~P,z,n);
  return P`cheb_poly[n+1];
end function;

// time cheb2(30);
// 0.000

cheb3 := function(n)
  chebyshev3_ := procedure(~Z,z,n)
    if not IsDefined(Z,n+1) then
      $$(~Z,z,n-1);
      Append(~Z, 2*z*Z[n]-Z[n-1]);
    end if;
  end procedure;

  P<z> := PolynomialRing(Integers());
  Z := [P| 1, z];
  chebyshev3_(~Z,z,n);
  return Z[n+1];
end function;

