Notes for Macaulay2 users

OSCAR and Macaulay2 overlap in commutative algebra and algebraic geometry; OSCAR uses Singular for much of this. This page describes differences between Macaulay2 and OSCAR, and lists common Macaulay2 commands together with their OSCAR counterparts.

Help wanted

This page is a start. Please tell us what is missing, see Notes for users of other computer algebra systems.

Differences in syntax

  • Function arguments are always parenthesized. Macaulay2 allows factor 120, gens R and res I; in Julia one writes factor(120), gens(R) and free_resolution(I).

  • Lists are written [1, 2, 3] instead of {1, 2, 3}, and they are indexed from 1: Macaulay2's L#0 (or L_0) is L[1], and #L is length(L).

  • Control structures need an end: for i from 1 to 3 do ... becomes for i in 1:3 ... end, and if c then A else B becomes if c A else B end.

  • Comments start with # instead of --, and help foo is ?foo.

  • A polynomial ring is created together with its variables, see Many constructors return more than one object: R = QQ[x,y] becomes R, (x, y) = polynomial_ring(QQ, [:x, :y]), and S = R/I becomes S, _ = quo(R, I).

Differences in semantics

  • / and // mean the opposite of what you expect. In Macaulay2, 7/2 is the rational number $\frac{7}{2}$ and 7//2 is the integer 3. In Julia, 7/2 is the floating point number 3.5, 7//2 is the rational number $\frac{7}{2}$, and integer division is div(7, 2). Beware that 2^100 evaluates to 0, see Integers and rational numbers.

  • There is no current ring. In Macaulay2, creating S = QQ[x,y] makes the symbols x and y refer to S, and use R makes them refer to R again. In OSCAR, a name is only rebound by an assignment: after S, (x, y) = polynomial_ring(ZZ, [:x, :y]), the name x refers to the generator of S, while R[1] and gens(R) still give those of R, as R_0 and gens R do in Macaulay2. Every element knows its parent, that is, the algebraic structure it lives in (see Every object has a parent), and elements of different rings cannot be mixed.

    julia> R, (x, y) = polynomial_ring(QQ, [:x, :y]);
    
    julia> S, (x, y) = polynomial_ring(ZZ, [:x, :y]);
    
    julia> parent(x)
    Multivariate polynomial ring in 2 variables x, y
      over integer ring
    
    julia> parent(R[1])
    Multivariate polynomial ring in 2 variables x, y
      over rational field
    
    julia> R[1] + x
    ERROR: Cannot promote to common type
    [...]
  • The monomial ordering is not part of the ring. A Macaulay2 ring carries a monomial ordering, and gb I and leadTerm I use it. In OSCAR, the ordering is passed to the functions that depend on it. Both default to the degree reverse lexicographical ordering.

    i1 : R = QQ[x,y, MonomialOrder => Lex];
    
    i2 : leadTerm ideal(x^2 + x + y, x*y^2 + y*x + 1)
    
                 5
    o2 = ideal (y , x)

    corresponds to

    julia> R, (x, y) = polynomial_ring(QQ, [:x, :y]);
    
    julia> I = ideal(R, [x^2 + x + y, x*y^2 + y*x + 1]);
    
    julia> leading_ideal(I; ordering = lex(R))
    Ideal generated by
      y^5
      x

    To run a whole block of code with another ordering, as in a Macaulay2 ring created with it, use with_ordering(R, lex(R)) do ... end.

  • Gradings are explicit. A polynomial ring in OSCAR is not graded unless you say so. Functions that need a grading, such as hilbert_series and betti_table, work over grade(R)[1] rather than over R.

  • A quotient ring does not take over the variables. In Macaulay2, S = R/I makes x and y refer to elements of S from then on:

    i1 : R = QQ[x,y]; S = R/ideal(x^2-y);
    
    i2 : x^2 == y
    
    o2 = true

    In OSCAR, quo(R, I) returns the quotient ring together with the projection map, x stays an element of R, and the map moves elements into the quotient.

    julia> R, (x, y) = polynomial_ring(QQ, [:x, :y]);
    
    julia> Q, p = quo(R, ideal(R, [x^2 - y]));
    
    julia> x^2 == y
    false
    
    julia> p(x)^2 == p(y)
    true

Interactive sessions

  • quit is exit(). There is no counterpart of restart; leave Julia and start it again.
  • Global functions are not protected: order = 5 silently replaces OSCAR's order in your session, and order = Oscar.order brings it back.
  • code f is @less f(x), which shows the source of the method that the call f(x) would use; q leaves the viewer. @edit f(x) opens it in an editor.
  • peek x is dump(x; maxdepth = 1), which lists the fields of x. For an ideal, the field gb holds the Gröbner bases computed so far, as peek I.cache shows in Macaulay2. The fields are internals and may change.
  • needsPackage "Foo" is using Foo, after a one-time Pkg.add("Foo"). OSCAR's own components, the experimental ones included, are all loaded by using Oscar.
  • There is no debug needsPackage. Unexported functions exist and are reachable at any time by qualifying the name with the module, as in Oscar.group_element; only exported names work without the prefix.
  • There is no built-in debugger that stops inside a function with its local variables in view. An error prints a stack trace, Base.@locals inside a function returns its local variables as a dictionary, and the packages Debugger.jl (@enter f(x)) and Infiltrator.jl (@infiltrate, then @locals at the breakpoint) add interactive debugging.

Common Macaulay2 commands and their OSCAR counterparts

Rings and polynomials

Macaulay2OSCAR
R = QQ[x,y]R, (x, y) = polynomial_ring(QQ, [:x, :y])
R = ZZ/32003[x,y]R, (x, y) = polynomial_ring(GF(32003), [:x, :y])
QQ[x,y,MonomialOrder=>Lex]groebner_basis(I; ordering = lex(R))
QQ[x_1..x_3]R, x = polynomial_ring(QQ, :x => 1:3), then x[1]
QQ[x_(1,1)..x_(2,3)]R, x = polynomial_ring(QQ, :x => (1:2, 1:3)), then x[1, 2]
coefficientRing R, numgens R, gens Rcoefficient_ring(R), ngens(R), gens(R)
ring fparent(f)
degree ftotal_degree(f)
leadTerm f, leadCoefficient f, leadMonomial fleading_term(f), leading_coefficient(f), leading_monomial(f)
terms f, support f, exponents fterms(f), vars(f), exponents(f)
size flength(collect(terms(f)))
diff(x, f)derivative(f, x)
substitute(f, {x=>1})evaluate(f, [x], [1])
factor f, gcd(f, g)factor(f), gcd(f, g)
resultant(f, g, x), discriminant(f, x)resultant(f, g, i), discriminant(f, i) for the i-th variable
isHomogeneous fis_homogeneous(f)
homogenize(f, z)h = homogenizer(R, :z); h(f)
S = R/IS, _ = quo(R, I)

Ideals and modules

Both systems compute Gröbner bases on demand; groebner_basis(I) is only needed if you want the basis itself, where Macaulay2 has gens gb I.

Macaulay2OSCAR
I = ideal(f, g)I = ideal(R, [f, g])
numgens I, I_0ngens(I), I[1]
gens gb Igroebner_basis(I)
dim I, codim I, degree Idim(I), codim(I), degree(I)
dim I for the variety of Idim(variety(I))
f % Inormal_form(f, I)
f % I == 0f in I
leadTerm Ileading_ideal(I)
radical Iradical(I)
primaryDecomposition I, minimalPrimes Iprimary_decomposition(I), minimal_primes(I)
eliminate(I, x)eliminate(I, [x])
I : J, saturate(I, J)quotient(I, J), saturation(I, J)
intersect(I, J), I + J, I * Jintersect(I, J), I + J, I * J
syz Msyzygy_generators(gens(I))
res Ifree_resolution(I)
betti res Ibetti_table(free_resolution(quo(grade(R)[1], I)[1]))
hilbertSeries(R/I)hilbert_series(quo(grade(R)[1], I)[1])
jacobian fjacobian_matrix(f)

Matrices

Macaulay2 matrices act on column vectors, so ker M is the right kernel; OSCAR's kernel(M) is the left kernel unless side = :right is given.

Macaulay2OSCAR
matrix{{1,2},{3,4}}matrix(ZZ, [1 2; 3 4])
id_(ZZ^2)identity_matrix(ZZ, 2)
M_(0,0)M[1, 1]
numrows M, numcols Mnrows(M), ncols(M)
det M, rank M, transpose Mdet(M), rank(M), transpose(M)
inverse Minv(M)
gens ker Mkernel(M; side = :right)

Lists and numbers

Macaulay2OSCAR
{1, 2, 3}, #L, L#0[1, 2, 3], length(L), L[1]
1..101:10
append(L, x), join(L, M)push!(L, x), vcat(L, M)
apply(L, f), select(L, f)map(f, L), filter(f, L)
position(L, f), member(x, L)findfirst(f, L), x in L
sum L, product L, max Lsum(L), prod(L), maximum(L)
sort L, reverse Lsort(L), reverse(L)
set L, toList SSet(L), collect(S)
new HashTable from {a=>1}, H#aDict(:a => 1), H[:a]
S #? x, H #? kx in S, haskey(H, k)
ZZ, QQ, GF 9, ZZ/7ZZ, QQ, GF(9), residue_ring(ZZ, 7)
isPrime n, nextPrime n, factor nis_prime(n), next_prime(n), factor(n)
gcd(a, b), lcm(a, b), binomial(n, k)gcd(a, b), lcm(a, b), binomial(n, k)