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.
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 Randres I; in Julia one writesfactor(120),gens(R)andfree_resolution(I).Lists are written
[1, 2, 3]instead of{1, 2, 3}, and they are indexed from 1: Macaulay2'sL#0(orL_0) isL[1], and#Lislength(L).Control structures need an
end:for i from 1 to 3 do ...becomesfor i in 1:3 ... end, andif c then A else Bbecomesif c A else B end.Comments start with
#instead of--, andhelp foois?foo.A polynomial ring is created together with its variables, see Many constructors return more than one object:
R = QQ[x,y]becomesR, (x, y) = polynomial_ring(QQ, [:x, :y]), andS = R/IbecomesS, _ = quo(R, I).
Differences in semantics
/and//mean the opposite of what you expect. In Macaulay2,7/2is the rational number $\frac{7}{2}$ and7//2is the integer3. In Julia,7/2is the floating point number3.5,7//2is the rational number $\frac{7}{2}$, and integer division isdiv(7, 2). Beware that2^100evaluates to0, see Integers and rational numbers.There is no current ring. In Macaulay2, creating
S = QQ[x,y]makes the symbolsxandyrefer toS, anduse Rmakes them refer toRagain. In OSCAR, a name is only rebound by an assignment: afterS, (x, y) = polynomial_ring(ZZ, [:x, :y]), the namexrefers to the generator ofS, whileR[1]andgens(R)still give those ofR, asR_0andgens Rdo 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 IandleadTerm Iuse 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 xTo 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_seriesandbetti_table, work overgrade(R)[1]rather than overR.A quotient ring does not take over the variables. In Macaulay2,
S = R/Imakesxandyrefer to elements ofSfrom then on:i1 : R = QQ[x,y]; S = R/ideal(x^2-y); i2 : x^2 == y o2 = trueIn OSCAR,
quo(R, I)returns the quotient ring together with the projection map,xstays an element ofR, 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
quitisexit(). There is no counterpart ofrestart; leave Julia and start it again.- Global functions are not protected:
order = 5silently replaces OSCAR'sorderin your session, andorder = Oscar.orderbrings it back. code fis@less f(x), which shows the source of the method that the callf(x)would use;qleaves the viewer.@edit f(x)opens it in an editor.peek xisdump(x; maxdepth = 1), which lists the fields ofx. For an ideal, the fieldgbholds the Gröbner bases computed so far, aspeek I.cacheshows in Macaulay2. The fields are internals and may change.needsPackage "Foo"isusing Foo, after a one-timePkg.add("Foo"). OSCAR's own components, the experimental ones included, are all loaded byusing Oscar.- There is no
debug needsPackage. Unexported functions exist and are reachable at any time by qualifying the name with the module, as inOscar.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.@localsinside a function returns its local variables as a dictionary, and the packages Debugger.jl (@enter f(x)) and Infiltrator.jl (@infiltrate, then@localsat the breakpoint) add interactive debugging.
Common Macaulay2 commands and their OSCAR counterparts
Rings and polynomials
| Macaulay2 | OSCAR |
|---|---|
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 R | coefficient_ring(R), ngens(R), gens(R) |
ring f | parent(f) |
degree f | total_degree(f) |
leadTerm f, leadCoefficient f, leadMonomial f | leading_term(f), leading_coefficient(f), leading_monomial(f) |
terms f, support f, exponents f | terms(f), vars(f), exponents(f) |
size f | length(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 f | is_homogeneous(f) |
homogenize(f, z) | h = homogenizer(R, :z); h(f) |
S = R/I | S, _ = 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.
| Macaulay2 | OSCAR |
|---|---|
I = ideal(f, g) | I = ideal(R, [f, g]) |
numgens I, I_0 | ngens(I), I[1] |
gens gb I | groebner_basis(I) |
dim I, codim I, degree I | dim(I), codim(I), degree(I) |
dim I for the variety of I | dim(variety(I)) |
f % I | normal_form(f, I) |
f % I == 0 | f in I |
leadTerm I | leading_ideal(I) |
radical I | radical(I) |
primaryDecomposition I, minimalPrimes I | primary_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 * J | intersect(I, J), I + J, I * J |
syz M | syzygy_generators(gens(I)) |
res I | free_resolution(I) |
betti res I | betti_table(free_resolution(quo(grade(R)[1], I)[1])) |
hilbertSeries(R/I) | hilbert_series(quo(grade(R)[1], I)[1]) |
jacobian f | jacobian_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.
| Macaulay2 | OSCAR |
|---|---|
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 M | nrows(M), ncols(M) |
det M, rank M, transpose M | det(M), rank(M), transpose(M) |
inverse M | inv(M) |
gens ker M | kernel(M; side = :right) |
Lists and numbers
| Macaulay2 | OSCAR |
|---|---|
{1, 2, 3}, #L, L#0 | [1, 2, 3], length(L), L[1] |
1..10 | 1: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 L | sum(L), prod(L), maximum(L) |
sort L, reverse L | sort(L), reverse(L) |
set L, toList S | Set(L), collect(S) |
new HashTable from {a=>1}, H#a | Dict(:a => 1), H[:a] |
S #? x, H #? k | x in S, haskey(H, k) |
ZZ, QQ, GF 9, ZZ/7 | ZZ, QQ, GF(9), residue_ring(ZZ, 7) |
isPrime n, nextPrime n, factor n | is_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) |