# Architecture of affine schemes

## Requirements on rings and ideals

Any type of ring $R$ to be used within the schemes framework must come with its own ideal type `IdealType<:Ideal`

for which we require the following interface to be implemented:

```
# constructor of ideals in R
ideal(R::RingType, g::Vector{<:RingElem})::Ideal
# constructor for quotient rings
quo(R::RingType, I::IdealType)::Tuple{<:Ring, <:Map}
# ideal membership test
in(f::RingElem, I::IdealType)::Bool
# a (fixed) set of generators
gens(I::IdealType)::Vector{<:RingElem}
# writing an element as linear combination of the generators
coordinates(f::RingElem, I::IdealType)::Vector{<:RingElem}
```

The latter function must return a vector $v = (a_1,\dots, a_r)$ of elements in $R$ such that $f = a_1 \cdot g_1 + \dots + a_r \cdot g_r$ where $g_1,\dots,g_r$ is the set of `gens(I)`

. When $f$ does not belong to $I$, it must error. Note that the ring returned by `quo`

must again be admissible for the `AbsAffineScheme`

interface.

With a view towards the use of the `ambient_coordinate_ring(X)`

for computations, it is customary to also implement

`saturated_ideal(I::IdealType)::MPolyIdeal`

returning an ideal $J$ in the `ambient_coordinate_ring(X)`

with the property that $a \in I$ for some element $a \in R$ if and only if `lifted_numerator(a)`

is in $J$.

## Interplay between ambient coordinate ring and coordinate ring

Let $X$ be an affine variety. In practice, all computations in the coordinate ring `R = OO(X)`

will be deferred to computations in `P = ambient_coordinate_ring(X)`

in one way or the other; this is another reason to include the ambient affine space in our abstract interface for affine schemes. In order to make the `ambient_coordinate_ring(X)`

accessible for this purpose, we need the following methods to be implemented for elements $a\in R$ of type `RingElemType`

:

```
lifted_numerator(a::RingElemType)
lifted_denominator(a::RingElemType)
```

These must return representatives of the numerator and the denominator of $a$. Note that the denominator is equal to `one(P)`

in case $R \cong P$ or $R \cong P/I$.

Recall that the coordinates $x_i$ of $X$ are induced by the coordinates of the ambient affine space. Moreover, we will assume that for homomorphisms from $R$ there is a method

`hom(R::RingType, S::Ring, a::Vector{<:RingElem})`

where `RingType`

is the type of $R$ and `a`

the images of the coordinates $x_i$ in $S$. This will be important when we come to morphisms of affine schemes below.

Algebraically speaking, embedding the affine scheme $X = Spec(R)$ over $𝕜$ into an affine space with coordinate ring $P = 𝕜[x₁,…,xₙ]$ corresponds to a morphism of rings $P → R$ with the property that for every other (commutative) ring $S$ and any homomorphism $φ : R → S$ there is a morphism $ψ : P → S$ factoring through $φ$ and such that $φ$ is uniquely determined by $ψ$. Note that the morphism $P → R$ is induced by natural coercions.

## Existing types of affine schemes and how to derive new types

The abstract type for affine schemes is

`AbsAffineScheme`

— Type`AbsAffineScheme{BaseRingType, RingType<:Ring}`

An affine scheme $X = Spec(R)$ with $R$ of type `RingType`

over a ring $𝕜$ of type `BaseRingType`

.

For any concrete instance of this type, we require the following functions to be implemented:

`base_ring(X::AbsAffineScheme)`

,`OO(X::AbsAffineScheme)`

.

A concrete instance of this type is

`AffineScheme`

— Type`AffineScheme{BaseRingType, RingType}`

An affine scheme $X = Spec(R)$ with $R$ a Noetherian ring of type `RingType`

over a base ring $𝕜$ of type `BaseRingType`

.

It provides an implementation of affine schemes for rings $R$ of type `MPolyRing`

, `MPolyQuoRing`

, `MPolyLocRing`

, and `MPolyQuoLocRing`

defined over the integers or algebraic field extensions of $\mathbb Q$. This minimal implementation can be used internally, when deriving new concrete types `MyAffineScheme<:AbsAffineScheme`

such as, for instance, group schemes, toric schemes, schemes of a particular dimension like curves and surfaces, etc. To this end, one has to store an instance `Y`

of `AffineScheme`

in `MyAffineScheme`

and implement the methods

`underlying_scheme(X::MyAffineScheme)::AffineScheme # return Y as above`

Then all methods implemented for `AffineScheme`

are automatically forwarded to any instance of `MyAffineScheme`

.

**Note:** The above method necessarily returns an instance of `AffineScheme`

! Of course, it can be overwritten for any higher type `MyAffineScheme<:AbsAffineScheme`

as needed.

## Existing types of affine scheme morphisms and how to derive new types

Any abstract morphism of affine schemes is of the following type:

`AbsAffineSchemeMor`

— Type```
AbsAffineSchemeMor{DomainType<:AbsAffineScheme,
CodomainType<:AbsAffineScheme,
PullbackType<:Map,
MorphismType,
BaseMorType
}
```

Abstract type for morphisms $f : X → Y$ of affine schemes where

- $X = Spec(S)$ is of type
`DomainType`

, - $Y = Spec(R)$ is of type
`CodomainType`

, - $f^* : R → S$ is a ring homomorphism of type
`PullbackType`

, - $f$ itself is of type
`MorphismType`

(required for the Map interface), - if $f$ is defined over a morphism of base schemes $BX → BY$ (e.g. a field extension), then this base scheme morphism is of type
`BaseMorType`

; otherwise, this can be set to`Nothing`

.

Any such morphism has the attributes `domain`

, `codomain`

and `pullback`

. A concrete and minimalistic implementation exist for the type `AffineSchemeMor`

:

`AffineSchemeMor`

— Type```
AffineSchemeMor{DomainType<:AbsAffineScheme,
CodomainType<:AbsAffineScheme,
PullbackType<:Map
}
```

A morphism $f : X → Y$ of affine schemes $X = Spec(S)$ of type `DomainType`

and $Y = Spec(R)$ of type `CodomainType`

, both defined over the same `base_ring`

, with underlying ring homomorphism $f^* : R → S$ of type `PullbackType`

.

This basic functionality consists of

`compose(f::AbsAffineSchemeMor, g::AbsAffineSchemeMor)`

,`identity_map(X::AbsAffineScheme)`

,`restrict(f::AbsAffineSchemeMor, X::AbsAffineScheme, Y::AbsAffineScheme; check::Bool=true)`

,`==(f::AbsAffineSchemeMor, g::AbsAffineSchemeMor)`

,`preimage(f::AbsAffineSchemeMor, Z::AbsAffineScheme)`

.

In particular, for every concrete instance of a type `MyAffineScheme<:AbsAffineScheme`

that implements `underlying_scheme`

, this basic functionality of `AffineSchemeMor`

should run naturally.

We may derive higher types of morphisms of affine schemes `MyAffineSchemeMor<:AbsAffineSchemeMor`

by storing an instance `g`

of `AffineSchemeMor`

inside an instance `f`

of `MyAffineSchemeMor`

and implementing

`underlying_morphism(f::MyAffineSchemeMor)::AffineSchemeMor # return g`

For example, this allows us to define closed embeddings.