Revision 202f7130dde41cf4260970c8b3e8efb24cf27619 authored by Mohamed Barakat on 11 February 2022, 23:34:22 UTC, committed by GitHub on 11 February 2022, 23:34:22 UTC
bumped versions to trigger releases
2 parent s 26a82de + 416b60d
Raw File
Oscar.gi
#############################################################################
##
##  Oscar.gi               RingsForHomalg package            Mohamed Barakat
##
##  Copyright 2007-2008 Lehrstuhl B für Mathematik, RWTH Aachen
##
##  Implementation stuff for the external computer algebra system Oscar.
##
#############################################################################

####################################
#
# global variables:
#
####################################

InstallValue( HOMALG_IO_Oscar,
        rec(
            cas := "oscar",			## normalized name on which the user should have no control
            name := "Oscar",
            executable := [ "julia" ],		## this list is processed from left to right
            environment := [ "NEMO_THREADED=1" ],
            options := [ "--history-file=no", "--depwarn=error", "--color=no", "--code-coverage=none" ],
            #options := [ "--depwarn=error", "--color=no", "--code-coverage=none" ],
            BUFSIZE := 1024,
            READY := "!%&/)(",
            READY_printed := Concatenation( "\"", ~.READY, "\"" ),
            CUT_POS_BEGIN := 1,			## these are the most
            CUT_POS_END := 1,			## delicate values!
            eoc_verbose := "",
            eoc_quiet := ";0",	## an Oscar specific
            normalized_white_space := NormalizedWhitespace,	## an Oscar specific
            setring := _Oscar_SetRing,		## an Oscar specific
            ## prints polynomials in a format compatible with other CASs
            setinvol := _Oscar_SetInvolution,## an Oscar specific
            define := "=",
            delete := function( var, stream ) homalgSendBlocking( [ var, " = nothing" ], "need_command", stream, "delete" ); end,
            multiple_delete := _Oscar_multiple_delete,
            garbage_collector := function( stream ) homalgSendBlocking( [ "Base.GC.gc()" ], "need_command", stream, "garbage_collector" ); end,
            prompt := "\033[01mjulia>\033[0m ",
            output_prompt := "\033[1;30;43m<julia\033[0m ",
            display_color := "\033[0;30;47m",
            banner := """\
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |\
""",
            init_string := "import Singular; import Nemo; import AbstractAlgebra; using Hecke; Nemo.flint_set_num_threads(8)",
            InitializeCASMacros := InitializeOscarMacros,
            time := function( stream, t ) return Int( Int( homalgSendBlocking( [ "Int(time()*10^6)" ], "need_output", stream, "time" ) ) / 10^3 ) - t; end,
            memory_usage := function( stream, o ) return Int( homalgSendBlocking( [ "memory(", o, ")" ], "need_output", stream, "memory" ) ); end,
           )
);

HOMALG_IO_Oscar.READY_LENGTH := Length( HOMALG_IO_Oscar.READY_printed );

####################################
#
# representations:
#
####################################

# a new subrepresentation of the representation IshomalgExternalRingObjectRep:
DeclareRepresentation( "IsHomalgExternalRingObjectInOscarRep",
        IshomalgExternalRingObjectRep,
        [  ] );

# a new subrepresentation of the representation IsHomalgExternalRingRep:
DeclareRepresentation( "IsHomalgExternalRingInOscarRep",
        IsHomalgExternalRingRep,
        [  ] );

####################################
#
# families and types:
#
####################################

# a new type:
BindGlobal( "TheTypeHomalgExternalRingObjectInOscar",
        NewType( TheFamilyOfHomalgRings,
                IsHomalgExternalRingObjectInOscarRep ) );

# a new type:
BindGlobal( "TheTypeHomalgExternalRingInOscar",
        NewType( TheFamilyOfHomalgRings,
                IsHomalgExternalRingInOscarRep ) );

####################################
#
# global functions and variables:
#
####################################

## will be automatically invoked in homalgSendBlocking once stream.active_ring is set;
## so there is no need to invoke it explicitly for a ring which can never be
## created as the first ring in the stream!
InstallGlobalFunction( _Oscar_SetRing,
  function( R )
    local stream;
    
    stream := homalgStream( R );
    
    ## since _Oscar_SetRing might be called from homalgSendBlocking,
    ## we first set the new active ring to avoid infinite loops:
    stream.active_ring := R;
    
    if IsBound( HOMALG_IO_Oscar.setring_post ) then
        homalgSendBlocking( HOMALG_IO_Oscar.setring_post, "need_command", stream, "initialize" );
    fi;
    
end );

##
InstallGlobalFunction( _Oscar_SetInvolution,
  function( R )
    local RP;
    
    RP := homalgTable( R );
    
    if IsBound( RP!.SetInvolution ) then
        RP!.SetInvolution( R );
    fi;
    
end );

##
InstallGlobalFunction( _Oscar_multiple_delete,
  function( var_list, stream )
    local str, var;
    
    str:="";
    
    for var in var_list do
      str := Concatenation( str, String ( var ) , " = nothing;" );
    od;
    
    homalgSendBlocking( str, "need_command", stream, "multiple_delete" );
    
end );

##
InstallValue( OscarMacros,
        rec(

            init := """

function Singular.vector(R::Singular.PolyRing{T}, a::Array)::Singular.svector where T <:AbstractAlgebra.RingElem
   Singular.vector(R, a...)
end

function Singular.Module(R::Singular.PolyRing{T}, vecs::Array{Singular.svector{Singular.spoly{T}},1})::Singular.smodule where T <:AbstractAlgebra.RingElem
   Singular.Module(R, vecs...)
end

function Singular.Matrix(R::Singular.PolyRing{T}, r::Int, c::Int, a::Array{Singular.spoly{T},1})::Singular.smatrix where T<:AbstractAlgebra.RingElem
    Singular.transpose(Singular.Matrix(Singular.Module(R, [Singular.vector(R, a[c*(i-1)+1:c*i]) for i in 1:r])))
end

function Singular.Matrix(R::Singular.PolyRing, r::Int, c::Int, a::Array)::Singular.smatrix
    Singular.Matrix(R, r, c, [R(e) for e in a])
end

function Singular.Module(R::Singular.PolyRing{T}, a::Array{Singular.spoly{T},2})::Singular.smodule where T <:AbstractAlgebra.RingElem
    Singular.Module(R, [Singular.vector(R, a[1:size(a,1), i:i]) for i in 1:size(a,2)])
end

function Singular.Module(a::AbstractAlgebra.Generic.MatSpaceElem{T})::Singular.smodule where T <:AbstractAlgebra.RingElem
    Singular.Module(base_ring(a), AbstractAlgebra.Array(a))
end

function IsDiagonalMatrix(M::TypeOfMatrixForHomalg)::Bool
    for i in 1:nrows(M)
        for j in (i+1):ncols(M)
            iszero(M[i,j]) && return false
        end
    end
    for i in 1:nrows(M)
        for j in 1:(i-1)
            iszero(M[i,j]) && return false
        end
    end
    true
end

function Singular.check_parent(I::Singular.smodule{T}, J::Singular.smodule{T}) where T <: AbstractAlgebra.RingElem
   base_ring(I) != base_ring(J) && error("Incompatible modules")
end

function Singular.reduce(M::Singular.smodule, G::Singular.smodule)
   Singular.check_parent(M, G)
   R = base_ring(M)
   !G.isGB && error("Not a Groebner basis")
   ptr = Singular.libSingular.p_Reduce(M.ptr, G.ptr, R.ptr)
   return Singular.Module(R, ptr)
end

function SyzForHomalg(M::TypeOfMatrixForHomalg)::TypeOfMatrixForHomalg
    MatrixForHomalg(Singular.syz(Singular.Module(M)))
end

function Singular.dimension(I::Singular.smodule{S}) where S <: Union{Singular.spoly{T}, Singular.spoly{Singular.n_unknown{U}}} where {T <: Singular.FieldElem, U <: Nemo.FieldElem}
   I.isGB == false && error("I needs to be a Gröbner basis.")
   R = base_ring(I)
   return Int(Singular.libSingular.scDimInt(I.ptr, R.ptr))
end

function Singular.dimension(I::Singular.smodule{S}) where S <: Union{Singular.spoly{T}, Singular.spoly{Singular.n_unknown{U}}} where {T <: Singular.n_Z, U <: Nemo.Integer}
   I.isGB == false && error("I needs to be a Gröbner basis.")
   R = base_ring(I)
   return Int(Singular.libSingular.scDimInt(I.ptr, R.ptr))
end

function Dimension(M::TypeOfMatrixForHomalg)::Int64
    mM = Singular.Module(M)
    mM.isGB = true
    Singular.dimension(mM)
end

function (f::Singular.SAlgHom)(M::AbstractAlgebra.Generic.MatSpaceElem)
    MatrixForHomalg(codomain(f), [f(a) for a in Array(M)])
end

function ref_ff_rc!(M)
  rk = 0
  for i=1:nrows(M)
    c = Hecke.content(M[i, :])
    if !Hecke.isone(c)
      M[i, :] = Hecke.divexact(M[i, :], c)
    end
  end
  j = 1
  for i=1:nrows(M)
    best_j = 0
    best_t = typemax(Int)
    while j <= ncols(M)
      best_i = 0
      best_t = 0
      for ii = i:nrows(M)
        if Hecke.iszero(M[ii, j])
          continue
        end
        if best_i == 0
          best_i = ii
          best_t = length(M[ii, j])
        elseif best_t > length(M[ii, j])
          best_t = length(M[ii, j])
          best_i = ii
        end
      end
      if best_i == 0
        j += 1
        continue
      end
      if best_i > i
        M = Hecke.swap_rows!(M, i, best_i)
      end
      break
    end
    if j > ncols(M)
      return rk
    end
    rk += 1

    for k=i+1:nrows(M)
      if Hecke.iszero(M[k, j])
        continue
      end
      g = Hecke.gcd(M[k, j], M[i, j])
      if Hecke.isone(g)
        M[k, :] = M[i, j] * M[k, :] - M[k, j] * M[i, :]
      else
        M[k, :] = Hecke.divexact(M[i, j], g) * M[k, :] - Hecke.divexact(M[k, j], g) * M[i, :]
      end
      M[k, :] = Hecke.divexact(M[k, :], Hecke.content(M[k, :]))
    end
    j += 1
  end
  M[rk, :] = Hecke.divexact(M[rk, :], Hecke.content(M[rk, :]))
  return rk
end

function rref_ff_rc!(M)
  j = 2
  for i=2:nrows(M)
    while j <= ncols(M)
      if Hecke.iszero(M[i, j])
         j += 1
        continue
      end
      for k=1:i-1
        if Hecke.iszero(M[k, j])
          continue
        end
        g = Hecke.gcd(M[k, j], M[i, j])
        if Hecke.isone(g)
          M[k, :] = M[i, j] * M[k, :] - M[k, j] * M[i, :]
        else
          M[k, :] = Hecke.divexact(M[i, j], g) * M[k, :] - Hecke.divexact(M[k, j], g) * M[i, :]
        end
        M[k, :] = Hecke.divexact(M[k, :], Hecke.content(M[k, :]))
      end
      j += 1
      break
    end
  end
end

function cef_ff_rc!(M; ignore = 0)
  rk = 0
  for i=1:ncols(M)
    c = Hecke.content(M[:, i])
    if !Hecke.isone(c)
      M[:, i] = Hecke.divexact(M[:, i], c)
    end
  end
  j = 1
  m = nrows(M) - ignore
  for i=1:ncols(M)
    best_j = 0
    best_t = typemax(Int)
    while j <= m
      best_i = 0
      best_t = 0
      for ii = i:ncols(M)
        if Hecke.iszero(M[j, ii])
          continue
        end
        if best_i == 0
          best_i = ii
          best_t = length(M[j, ii])
        elseif best_t > length(M[j, ii])
          best_t = length(M[j, ii])
          best_i = ii
        end
      end
      if best_i == 0
        j += 1
        continue
      end
      if best_i > i
        M = Hecke.swap_cols!(M, best_i, i)
      end
      break
    end
    if j > m
      return rk
    end
    rk += 1

    for k=i+1:ncols(M)
      if Hecke.iszero(M[j, k])
        continue
      end
      g = Hecke.gcd(M[j, k], M[j, i])
      if Hecke.isone(g)
        M[:, k] = M[j, i] * M[:, k] - M[j, k] * M[:, i]
      else
        M[:, k] = Hecke.divexact(M[j, i], g) * M[:, k] - Hecke.divexact(M[j, k], g) * M[:, i]
      end
      M[:, k] = Hecke.divexact(M[:, k], Hecke.content(M[:, k]))
    end
    j += 1
  end
  M[:, rk] = Hecke.divexact(M[:, rk], Hecke.content(M[:, rk]))
  return rk
end

function rcef_ff_rc!(M)
  j = 2
  for i=2:ncols(M)
    while j <= nrows(M)
      if Hecke.iszero(M[j, i])
         j += 1
        continue
      end
      for k=1:i-1
        if Hecke.iszero(M[j, j])
          continue
        end
        g = Hecke.gcd(M[j, k], M[j, i])
        if Hecke.isone(g)
          M[:, k] = M[j, i] * M[:, k] - M[j, k] * M[:, i]
        else
          M[:, k] = Hecke.divexact(M[j, i], g) * M[:, k] - Hecke.divexact(M[j, k], g) * M[:, i]
        end
        M[:, k] = Hecke.divexact(M[:, k], Hecke.content(M[:, k]))
      end
      j += 1
      break
    end
  end
end
""",

    init2 := Concatenation( "include(\"", Filename( DirectoriesPackageLibrary( "RingsForHomalg", "gap" )[1], "Euclidean.jl" ), "\")" ),

    DiagMat := """

function DiagMat(e...)
    R = base_ring(e[1])
    l = length(e)
    function f(i,j)
        i == j && return e[i]
        ZeroMatrixForHomalg(R, nrows(e[i]), ncols(e[j]))
    end
    function g(i)
        a = map(j->f(i,j), 1:l)
        UnionOfRows(a...)
    end
    b = map(g, 1:l)
    UnionOfColumns(b...)
end
""",
    
    GetColumnIndependentUnitPositions := """

function GetColumnIndependentUnitPositions(M, poslist)
    rest = 1:nrows(M)
    pos = [ ]
    for j in 1:ncols(M)
        for k in reverse(rest)
            if !( [j, k] in poslist ) && isunit(M[k, j])
                push!(pos, [j, k])
                rest = filter(a -> iszero(M[a, j]), rest)
                break
            end
        end
    end

    if length(pos) == 0
        println("[]")
    else
        println(pos)
    end
end
""",

    GetRowIndependentUnitPositions := """

function GetRowIndependentUnitPositions(M, poslist)
    rest = 1:ncols(M)
    pos = [ ]
    for i in 1:nrows(M)
        for k in reverse(rest)
            if !( [i, k] in poslist ) && isunit(M[i, k])
                push!(pos, [i, k])
                rest = filter(a -> iszero(M[i, a]), rest)
                break
            end
        end
    end

    if length(pos) == 0
        println("[]")
    else
        println(pos)
    end
end
""",

    GetUnitPosition := """
function GetUnitPosition(M, poslist)
    m = ncols(M)
    n = nrows(M)
    for i in 1:m
        for j in 1:n
            if !( [i, j] in poslist ) && !( j in poslist ) && isunit(M[j, i])
                println([i, j])
                return
            end
        end
    end
    false
end
""",

    RowEchelonForm := """

function RowEchelonForm(M::TypeOfMatrixForHomalg; ignore::Int = 0)::TypeOfMatrixForHomalg
  N = copy(M)
  cef_ff_rc!(N, ignore = ignore)
  N[:, filter(i->!iszero(N[:, [i]]),1:ncols(M))]
end
""",

    ColumnEchelonForm := """

function ColumnEchelonForm(M::TypeOfMatrixForHomalg)::TypeOfMatrixForHomalg
  N = copy(M)
  ref_ff_rc!(N)
  N[filter(i->!iszero(N[[i], :]),1:nrows(M)), :]
end
""",

    ReducedRowEchelonForm := """

function ReducedRowEchelonForm(M::TypeOfMatrixForHomalg)::TypeOfMatrixForHomalg
  N = RowEchelonForm(M)
  rcef_ff_rc!(N)
  N
end
""",

    ReducedColumnEchelonForm := """

function ReducedColumnEchelonForm(M::TypeOfMatrixForHomalg)::TypeOfMatrixForHomalg
  N = ColumnEchelonForm(M)
  rref_ff_rc!(N)
  N
end
""",

    BasisOfRowModule := """

function BasisOfRowModule(M::TypeOfMatrixForHomalg)::TypeOfMatrixForHomalg
  MatrixForHomalg(Singular.std(Singular.Module(M), complete_reduction=true))
end
""",

    BasisOfColumnModule := """

function BasisOfColumnModule(M::TypeOfMatrixForHomalg)::TypeOfMatrixForHomalg
  Involution(BasisOfRowModule(Involution(M)))
end
""",

    BasisOfRowsCoeff := """

function BasisOfRowsCoeff(M::TypeOfMatrixForHomalg)
  B = BasisOfRowModule(M)
  T, rest = Singular.lift(Singular.Module(M), Singular.Module(B))
  B, MatrixForHomalg(T)
end
""",
  
    BasisOfColumnsCoeff := """

function BasisOfColumnsCoeff(M::TypeOfMatrixForHomalg)
  B, T = BasisOfRowsCoeff(Involution(M))
  Involution(B), Involution(T)
end
""",
  
    DecideZeroRows := """

function DecideZeroRows(A::TypeOfMatrixForHomalg, B::TypeOfMatrixForHomalg)::TypeOfMatrixForHomalg
  mA = Singular.Module(A)
  mB = Singular.Module(B)
  mB.isGB = true
  MatrixForHomalg(Singular.reduce(mA, mB))
end
""",

    DecideZeroColumns := """

function DecideZeroColumns(A::TypeOfMatrixForHomalg, B::TypeOfMatrixForHomalg)::TypeOfMatrixForHomalg
  Involution(DecideZeroRows(Involution(A), Involution(B)))
end
""",

    DecideZeroRowsEffectively := """

function DecideZeroRowsEffectively(A::TypeOfMatrixForHomalg, B::TypeOfMatrixForHomalg)
  mB = Singular.Module(B)
  mB.isGB = true
  M = DecideZeroRows(A, B)
  T, rest = Singular.lift(mB, Singular.Module(M-A))
  M, MatrixForHomalg(T)
end
""",

    DecideZeroColumnsEffectively := """

function DecideZeroColumnsEffectively(A::TypeOfMatrixForHomalg, B::TypeOfMatrixForHomalg)
  M, T = DecideZeroRowsEffectively(Involution(A), Involution(B))
  Involution(M), Involution(T)
end
""",
  
    SyzygiesGeneratorsOfRows := """

function SyzygiesGeneratorsOfRows(M::TypeOfMatrixForHomalg)::TypeOfMatrixForHomalg
  SyzForHomalg(M)
end
""",
    
    SyzygiesGeneratorsOfColumns := """

function SyzygiesGeneratorsOfColumns(M::TypeOfMatrixForHomalg)::TypeOfMatrixForHomalg
  Involution(SyzForHomalg(Involution(M)))
end
""",

    RelativeSyzygiesGeneratorsOfRows := """

function RelativeSyzygiesGeneratorsOfRows(M1::TypeOfMatrixForHomalg, M2::TypeOfMatrixForHomalg)::TypeOfMatrixForHomalg
  BasisOfRowModule(MatrixForHomalg(Singular.modulo(Singular.Module(M1), Singular.Module(M2))))
end
""",

    RelativeSyzygiesGeneratorsOfColumns := """

function RelativeSyzygiesGeneratorsOfColumns(M1::TypeOfMatrixForHomalg, M2::TypeOfMatrixForHomalg)::TypeOfMatrixForHomalg
  Involution(RelativeSyzygiesGeneratorsOfRows(Involution(M1), Involution(M2)))
end
""",

    RadicalSubobject := """

function RadicalSubobject(M::TypeOfMatrixForHomalg)::TypeOfMatrixForHomalg
  MatrixForHomalg(Singular.LibPrimdec.radical(Singular.Module(M)))
end
""",

    RadicalSubobject_Z := """

function RadicalSubobject_Z(M::TypeOfMatrixForHomalg)::TypeOfMatrixForHomalg
  MatrixForHomalg(Singular.LibPrimdecint.radicalZ(Singular.Module(M)))
end
""",

    Diff := """
function Diff(m, n) # following the Macaulay2 convention
  f = nrows(m)
  p = ncols(m)
  g = nrows(n)
  q = ncols(n)
  h = ZeroMatrixForHomalg(base_ring(m), f*g, p*q)
  for i = 1:f
    for j = 1:g
      for k = 1:p
        for l = 1:q
            h[g*(i-1)+j, q*(k-1)+l] = derivative(n[j,l], m[i,k])
        end
      end
    end
  end
  return h
end
""",
    
    )

);

if true then ## AbstactAlgebra matrices

OscarMacros.matrices := """

TypeOfMatrixForHomalg = AbstractAlgebra.Generic.MatSpaceElem

MatrixForHomalg = AbstractAlgebra.matrix

function AbstractAlgebra.matrix(R::Singular.PolyRing{T}, a::Array{Singular.spoly{T},2})::AbstractAlgebra.Generic.MatSpaceElem where T <:AbstractAlgebra.RingElem
    AbstractAlgebra.transpose(AbstractAlgebra.matrix(R, size(a)[2], size(a)[1], reshape(a, :)))
end

function AbstractAlgebra.matrix(a::Singular.smodule)::AbstractAlgebra.Generic.MatSpaceElem
    if ngens(a) == 0
        ## empty matrices currently crash AbstractAlgebra, and homalg will take care of these corner cases anyway
        return ZeroMatrixForHomalg(base_ring(a),1,1)
    end
    aa = [ AbstractAlgebra.Array(a[i]) for i in 1:ngens(a) ]
    AbstractAlgebra.matrix(base_ring(a), hcat(aa...))
end

function AbstractAlgebra.matrix(a::Singular.sideal)::AbstractAlgebra.Generic.MatSpaceElem
    if ngens(a) == 0
        ## empty matrices currently crash AbstractAlgebra, and homalg will take care of these corner cases anyway
        return ZeroMatrixForHomalg(base_ring(a),1,1)
    end
    aa = [a[i] for i in 1:ngens(a)]
    AbstractAlgebra.matrix(base_ring(a), reshape(aa, 1, ngens(a)))
end

function ZeroMatrixForHomalg(R, r, c)
    AbstractAlgebra.matrix(R, fill(zero(R), r, c))
end

function IdentityMatrixForHomalg(R, r)
    id = fill(zero(R), r, r)
    o = one(R)
    for i in 1:r
        id[i,i] = o
    end
    AbstractAlgebra.matrix(R, id)
end

Determinant = AbstractAlgebra.det

function UnionOfRows(A::AbstractAlgebra.MatElem...)
  r = nrows(A[1])
  c = ncols(A[1])
  R = base_ring(A[1])
  for i=2:length(A)
    @assert nrows(A[i]) == r
    @assert base_ring(A[i]) == R
    c += ncols(A[i])
  end
  X = similar(A[1], r, c)
  o = 1
  for i=1:length(A)
    for j=1:ncols(A[i])
      X[:, o] = A[i][:, j]
      o += 1
    end
  end
  return X
end

function UnionOfColumns(A::AbstractAlgebra.MatElem...)
  r = nrows(A[1])
  c = ncols(A[1])
  R = base_ring(A[1])
  for i=2:length(A)
    @assert ncols(A[i]) == c
    @assert base_ring(A[i]) == R
    r += nrows(A[i])
  end
  X = similar(A[1], r, c)
  o = 1
  for i=1:length(A)
    for j=1:nrows(A[i])
      X[o, :] = A[i][j, :]
      o += 1
    end
  end
  return X
end

function CertainRows(m::TypeOfMatrixForHomalg, list)::TypeOfMatrixForHomalg
    m[:, list]
end

function CertainColumns(m::TypeOfMatrixForHomalg, list)::TypeOfMatrixForHomalg
    m[list, :]
end

function ZeroRows(M::TypeOfMatrixForHomalg)
    l = filter(i->iszero(M[:, [i]]),1:ncols(M))
    if length(l) == 0
        println("[]")
    else
        println(l)
    end
end

function ZeroColumns(M::TypeOfMatrixForHomalg)
    l = filter(i->iszero(M[[i], :]),1:nrows(M))
    if length(l) == 0
        println("[]")
    else
        println(l)
    end
end
""";

else ## Singular matrices

OscarMacros.matrices := """

TypeOfMatrixForHomalg = Singular.smatrix

MatrixForHomalg = Singular.Matrix

ZeroMatrixForHomalg = Singular.zero_matrix

IdentityMatrixForHomalg = Singular.identity_matrix

#function Singular.Matrix(R::Singular.PolyRing{T}, a::Array{Singular.spoly{T}, 2})::Singular.smatrix{Singular.spoly{T}} where T <:AbstractAlgebra.RingElem
#    Singular.Matrix(R::Singular.PolyRing{T}, size(a)[1], size(a)[2], reshape(a,:))
#end

function isone(r::Singular.spoly{T})::Bool where T r == one(r) end
function isone(M::Singular.smatrix)::Bool nrows(M) == ncols(M) && iszero(M - IdentityMatrixForHomalg(base_ring(M), nrows(M))) end

Determinant = Singular.det

function UnionOfRows(Ms::Singular.smatrix...)::Singular.smatrix
    list = [[M[i] for i in 1:ngens(M)] for M in [Singular.Module(M) for M in Ms]]
    list = vcat(list...)
    Singular.Matrix(Singular.Module(base_ring(Ms[1]), list))
end

function UnionOfColumns(Ms::Singular.smatrix...)::Singular.smatrix
    list = [[M[i] for i in 1:ngens(M)] for M in [Singular.Module(Singular.transpose(M)) for M in Ms]]
    list = vcat(list...)
    Singular.transpose(Singular.Matrix(Singular.Module(base_ring(Ms[1]), list)))
end

function CertainRows(m::TypeOfMatrixForHomalg, list)::TypeOfMatrixForHomalg
    M = Singular.Module(m)
    MatrixForHomalg(Singular.Module(base_ring(M), [M[i] for i in list]))
end

function CertainColumns(m::TypeOfMatrixForHomalg, list)::TypeOfMatrixForHomalg
    Singular.transpose(CertainRows(Singular.transpose(m), list))
end

function ZeroRows(m::TypeOfMatrixForHomalg)
    M = Singular.Module(m)
    l = filter(i->iszero(M[i]),1:ngens(M))
    if length(l) == 0
        println("[]")
    else
        println(l)
    end
end

function ZeroColumns(m::TypeOfMatrixForHomalg)
    ZeroRows(Singular.transpose(m))
end
""";

fi;
    

##
InstallGlobalFunction( InitializeOscarMacros,
  function( stream )
    
    return InitializeMacros( OscarMacros, stream );
    
end );

####################################
#
# constructor functions and methods:
#
####################################

##
InstallGlobalFunction( RingForHomalgInOscar,
  function( arg )
    local finalizers, nargs, ar, R, RP;
    
    finalizers := PositionProperty( arg, i -> IsList( i ) and ForAll( i, IsFunction ) );
    
    if not finalizers = fail then
        finalizers := Remove( arg, finalizers );
    fi;
    
    nargs := Length( arg );
    
    ar := [ arg[1] ];
    
    Add( ar, TheTypeHomalgExternalRingObjectInOscar );
    
    if nargs > 1 then
        Append( ar, arg{[ 2 .. nargs ]} );
    fi;
    
    ar := [ ar, TheTypeHomalgExternalRingInOscar ];
    
    Add( ar, "HOMALG_IO_Oscar" );
    
    if not finalizers = fail then
        Add( ar, finalizers );
    fi;
    
    R := CallFuncList( CreateHomalgExternalRing, ar );
    
    if not IsBound( homalgStream( R ).start_time ) then
        homalgStream( R ).start_time := homalgTime( R );
    fi;
    
    _Oscar_SetRing( R );
    
    RP := homalgTable( R );
    
    RP!.SetInvolution :=
      function( R )
        homalgSendBlocking( "\nfunction Involution(m) return transpose(m) end\n\n", "need_command", R, "define" );
    end;
    
    RP!.NumeratorAndDenominatorOfPolynomial := RP!.NumeratorAndDenominatorOfRational;
    
    homalgStream( R ).setinvol( R );
    
    LetWeakPointerListOnExternalObjectsContainRingCreationNumbers( R );
    
    return R;
    
end );

##
InstallGlobalFunction( HomalgRingOfIntegersInOscar,
  function( arg )
    local ZZ, nargs, c, d, param, minimal_polynomial, r, R, RP;
    
    ZZ := "Singular.ZZ";
    
    nargs := Length( arg );
    
    if nargs > 0 and IsInt( arg[1] ) and arg[1] <> 0 then
        ## characteristic:
        c := AbsInt( arg[1] );
        arg := arg{[ 2 .. nargs ]};
        if nargs > 1 and IsPosInt( arg[1] ) then
            d := arg[1];
            if d > 1 then
                param := Concatenation( "Z", String( c ), "_", String( d ) );
                arg := Concatenation( [ c, param, d ], arg{[ 2 .. nargs - 1 ]} );
                R := CallFuncList( HomalgRingOfIntegersInOscar, arg );
                SetRingProperties( R, c, d );
                R!.NameOfPrimitiveElement := param;
                SetName( R, Concatenation( "GF(", String( c ), "^", String( d ), ")" ) );
                return R;
            fi;
            arg := arg{[ 2 .. Length( arg ) ]};
        fi;
    else
        ## characteristic:
        c := 0;
        if nargs > 0 and arg[1] = 0 then
            arg := arg{[ 2 .. nargs ]};
        fi;
    fi;
    
    if not ( IsZero( c ) or IsPrime( c ) ) then
        return HomalgRingOfIntegersInOscar( ) / c;
    fi;
    
    ## we create GF(p)[dummy_variable] and feed only expressions without
    ## "dummy_variable" to Oscar. Since GAP does not know about
    ## the dummy_variable it will vanish during the next ring extension
    
    nargs := Length( arg );
    
    if nargs > 0 and IsString( arg[1] ) then
        
        param := ParseListOfIndeterminates( SplitString( arg[1], "," ) );
        
        arg := arg{[ 2 .. nargs ]};
        
        if nargs > 1 and IsString( arg[1] ) then
            minimal_polynomial := arg[1];
            arg := arg{[ 2 .. nargs - 1 ]};
        fi;
        
        r := CallFuncList( HomalgRingOfIntegersInOscar, arg );
        
        R := [ "Hecke.PolynomialRing(Hecke.ZZ, ", String( param ), ")" ];
        R := Concatenation( [ R ], [ [ "" ] ], [ [ ", (", JoinStringsWithSeparator( param ), ")" ] ], [ IsPrincipalIdealRing ], arg );
        
    else
        
        if not IsZero( c ) then
            ZZ := Concatenation( "Singular.FiniteField(", String( c ), ", 1, \"Zc_1\")[1]" );
        fi;
        
        R := Concatenation( "Singular.PolynomialRing(", ZZ, ", [\"dummy_variable\"])" );
        R := Concatenation( [ R ], [ [ "" ] ], [ [ ", dummy_variable" ] ], [ IsPrincipalIdealRing ], arg );
    
    fi;
    
    if IsBound( r ) then
        ## R will be defined in the same instance of Oscar as r
        Add( R, r );
    fi;
    
    if IsBound( minimal_polynomial ) then
        ## FIXME: we assume the polynomial is irreducible of degree > 1
        Add( R,
             [ function( R )
                 local name;
                 
                 name := homalgSendBlocking( [ minimal_polynomial ], "need_output", R, "homalgSetName" );
                 if name[1] = '(' and name[Length( name )] = ')' then
                     name := name{[ 2 .. Length( name ) - 1 ]};
                 fi;
                 R!.MinimalPolynomialOfPrimitiveElement := name;
                 homalgSendBlocking( [ "minpoly=", minimal_polynomial ], "need_command", R, "define" );
               end ] );
    fi;
    
    R := CallFuncList( RingForHomalgInOscar, R );
    
    R!.RingWithoutDummyVariable := ZZ;
    
    if IsBound( param ) then
        
        param := List( param, function( a ) local r; r := HomalgExternalRingElement( a, R ); SetName( r, a ); return r; end );
        
        SetRationalParameters( R, param );
        
        SetIsResidueClassRingOfTheIntegers( R, false );
        
        if IsPrime( c ) then
            SetIsFieldForHomalg( R, true );
            ## FIXME: we assume the polynomial is irreducible of degree > 1
            if not IsBound( minimal_polynomial ) then
                SetCoefficientsRing( R, r );
            fi;
        else
            SetCoefficientsRing( R, r );
            SetIsFieldForHomalg( R, false );
            SetIsPrincipalIdealRing( R, true );
            SetIsCommutative( R, true );
        fi;
        
    else
        
        SetIsResidueClassRingOfTheIntegers( R, true );
        
    fi;
    
    SetRingProperties( R, c );

    RP := homalgTable( R );
    Unbind( RP!.ReducedRowEchelonForm );
    Unbind( RP!.ReducedColumnEchelonForm );
    
    if HasIsIntegersForHomalg( R ) and IsIntegersForHomalg( R ) then
        RP!.PrimaryDecomposition := RP!.PrimaryDecomposition_Z;
        RP!.RadicalSubobject := RP!.RadicalSubobject_Z;
        RP!.RadicalDecomposition := RP!.RadicalDecomposition_Z;
        Unbind( RP!.CoefficientsOfUnreducedNumeratorOfWeightedHilbertPoincareSeries );
        Unbind( RP!.MaximalDegreePart );
    fi;
    
    return R;
    
end );

##
InstallMethod( HomalgRingOfIntegersInUnderlyingCAS,
        "for an integer and homalg ring in Oscar",
        [ IsInt, IsHomalgExternalRingInOscarRep ],
        
  HomalgRingOfIntegersInOscar );

##
InstallGlobalFunction( HomalgFieldOfRationalsInOscar,
  function( arg )
    local QQ, nargs, param, minimal_polynomial, Q, R;
    
    QQ := "Singular.QQ";
    
    nargs := Length( arg );
    
    if nargs > 0 and IsString( arg[1] ) then
        
        param := ParseListOfIndeterminates( SplitString( arg[1], "," ) );
        
        arg := arg{[ 2 .. nargs ]};
        
        if nargs > 1 and IsString( arg[1] ) then
            minimal_polynomial := arg[1];
            arg := arg{[ 2 .. nargs - 1 ]};
        fi;
        
        Q := CallFuncList( HomalgFieldOfRationalsInOscar, arg );
        
        if param = [ ] then
            R := [ "Singular.PolynomialRing(", QQ, ", [\"dummy_variable\"])" ];
            R := Concatenation( [ R ], [ [ "" ] ], [ [ ", dummy_variable" ] ], [ IsPrincipalIdealRing ], arg );
        else
            R := [ "Hecke.PolynomialRing(Hecke.QQ, ", String( param ), ")" ];
            R := Concatenation( [ R ], [ [ "" ] ], [ [ ", (", JoinStringsWithSeparator( param ), ")" ] ], [ IsPrincipalIdealRing ], arg );
        fi;
        
    else
        
        R := [ "Singular.PolynomialRing(", QQ, ", [\"dummy_variable\"])" ];
        R := Concatenation( [ R ], [ [ "" ] ], [ [ ", dummy_variable" ] ], [ IsPrincipalIdealRing ], arg );
        
    fi;
    
    if IsBound( Q ) then
        ## R will be defined in the same instance of Oscar as Q
        Add( R, Q );
    fi;
    
    if IsBound( minimal_polynomial ) then
        ## FIXME: we assume the polynomial is irreducible of degree > 1
        Add( R,
             [ function( R )
                 local name;
                 
                 name := homalgSendBlocking( [ minimal_polynomial ], "need_output", R, "homalgSetName" );
                 if name[1] = '(' and name[Length( name )] = ')' then
                     name := name{[ 2 .. Length( name ) - 1 ]};
                 fi;
                 R!.MinimalPolynomialOfPrimitiveElement := name;
                 homalgSendBlocking( [ "minpoly=", minimal_polynomial ], "need_command", R, "define" );
               end ] );
    fi;
    
    R := CallFuncList( RingForHomalgInOscar, R );
    
    R!.RingWithoutDummyVariable := QQ;
    
    if IsBound( param ) and not IsEmpty( param ) then
        
        param := List( param, function( a ) local r; r := HomalgExternalRingElement( a, R ); SetName( r, a ); return r; end );
        
        SetRationalParameters( R, param );
        
        SetIsFieldForHomalg( R, true );
        
        SetCoefficientsRing( R, Q );
        
    else
        
        SetIsRationalsForHomalg( R, true );
        
    fi;
    
    SetRingProperties( R, 0 );
    
    return R;
    
end );

##
InstallMethod( HomalgFieldOfRationalsInUnderlyingCAS,
        "for a homalg ring in Oscar",
        [ IsHomalgExternalRingInOscarRep ],
        
  HomalgFieldOfRationalsInOscar );

##
InstallMethod( FieldOfFractions,
        "for homalg rings in Oscar",
        [ IsHomalgExternalRingInOscarRep and IsIntegersForHomalg ],
        
  function( ZZ )
    
    return HomalgFieldOfRationalsInOscar( ZZ );
    
end );

##
InstallGlobalFunction( HomalgRingOfCyclotomicIntegersInOscar,
  function( arg )
    local degree, var, v, R, RP;
    
    if Length( arg ) < 2 then
        
        Error( "too few arguments" );
        
    fi;
    
    degree := arg[ 1 ];
    
    var := arg[ 2 ];
    
    arg := arg{ [ 3 .. Length( arg )] };
    
    if degree = 1 then
        
        return CallFuncList( HomalgRingOfIntegersInOscar, arg );
        
    elif not IsInt( degree ) or not IsString( var ) then
        
        Error( "input must be an integer > 1 and a string\n" );
        
    fi;
    
    R := [ [ "RingOfCyclotomicIntegers(", String( degree ), ")" ], [ "" ], [ ", ", var ] ];
    
    R := CallFuncList( RingForHomalgInOscar, R );

    SetName( R, Concatenation( "Z[", var, "]" ) );
    
    SetIsRationalsForHomalg( R, false );
    
    SetIsFieldForHomalg( R, false );
    
    SetBaseRing( R, R );

    RP := homalgTable( R );
    
    Unbind( RP!.BasisOfRowModule );
    Unbind( RP!.BasisOfColumnModule );
    Unbind( RP!.BasisOfRowsCoeff );
    Unbind( RP!.BasisOfColumnsCoeff );
    Unbind( RP!.DecideZeroRows );
    Unbind( RP!.DecideZeroColumns );
    Unbind( RP!.DecideZeroRowsEffectively );
    Unbind( RP!.DecideZeroColumnsEffectively );
    Unbind( RP!.SyzygiesGeneratorsOfRows );
    Unbind( RP!.SyzygiesGeneratorsOfColumns );
    Unbind( RP!.RelativeSyzygiesGeneratorsOfRows );
    Unbind( RP!.RelativeSyzygiesGeneratorsOfColumns );
    
    return R;
    
end );

##
InstallGlobalFunction( HomalgRingOfGoldenRatioIntegersInOscar,
  function( arg )
    local var, v, R, RP;
    
    if Length( arg ) < 1 then
        
        Error( "too few arguments" );
        
    fi;
    
    var := arg[ 1 ];
    
    arg := arg{ [ 2 .. Length( arg )] };
    
    R := [ [ "RingOfGoldenRatioIntegers()" ], [ "" ], [ ", ", var ] ];
    
    R := CallFuncList( RingForHomalgInOscar, R );

    SetName( R, Concatenation( "Z[", var, "]" ) );
    
    SetIsRationalsForHomalg( R, false );
    
    SetIsFieldForHomalg( R, false );
    
    SetBaseRing( R, R );

    RP := homalgTable( R );
    
    Unbind( RP!.BasisOfRowModule );
    Unbind( RP!.BasisOfColumnModule );
    Unbind( RP!.BasisOfRowsCoeff );
    Unbind( RP!.BasisOfColumnsCoeff );
    Unbind( RP!.DecideZeroRows );
    Unbind( RP!.DecideZeroColumns );
    Unbind( RP!.DecideZeroRowsEffectively );
    Unbind( RP!.DecideZeroColumnsEffectively );
    Unbind( RP!.SyzygiesGeneratorsOfRows );
    Unbind( RP!.SyzygiesGeneratorsOfColumns );
    Unbind( RP!.RelativeSyzygiesGeneratorsOfRows );
    Unbind( RP!.RelativeSyzygiesGeneratorsOfColumns );
    
    return R;
    
end );

##
InstallMethod( PolynomialRing,
        "for homalg rings in Oscar",
        [ IsHomalgExternalRingInOscarRep, IsList ],
        
  function( R, indets )
    local order, ar, r, var, nr_var, properties, param, l, var_base, var_fibr, a, ext_obj, S, weights, P, L, W, RP;
    
    order := ValueOption( "order" );
    
    ar := _PrepareInputForPolynomialRing( R, indets );
    
    r := ar[1];
    var := ar[2];	## all indeterminates, relative and base
    nr_var := ar[3];	## the number of relative indeterminates
    properties := ar[4];
    param := ar[5];
    
    l := Length( var );
    
    ## create the new ring
    if IsString( order ) and Length( order ) >= 3 and order{[ 1 .. 3 ]} = "lex" then
        
        var_base := var{[ 1 .. l - nr_var ]};
        var_fibr := var{[ l - nr_var + 1 .. l ]};
        
        ## lex order
        if HasIsIntegersForHomalg( r ) and IsIntegersForHomalg( r ) then
            ext_obj := homalgSendBlocking( [ "(integer", param, "),(", Concatenation( var_fibr, var_base ), "),(lp,c)" ], TheTypeHomalgExternalRingObjectInOscar, properties, R, "CreateHomalgRing" );
        else
            ext_obj := homalgSendBlocking( [ "(", Characteristic( R ), param, "),(", Concatenation( var_fibr, var_base ), "),(lp,c)" ], TheTypeHomalgExternalRingObjectInOscar, properties, R, "CreateHomalgRing" );
        fi;
        
    elif IsRecord( order ) and IsBound( order.weights ) then
        
        ## weighted degrevlex order
        if HasIsIntegersForHomalg( r ) and IsIntegersForHomalg( r ) then
            ext_obj := homalgSendBlocking( [ "(integer", param, "),(", var, "),(wp(", order.weights, "),c)" ], TheTypeHomalgExternalRingObjectInOscar, properties, R, "CreateHomalgRing" );
        else
            ext_obj := homalgSendBlocking( [ "(", Characteristic( R ), param, "),(", var, "),(wp(", order.weights, "),c)" ], TheTypeHomalgExternalRingObjectInOscar, properties, R, "CreateHomalgRing" );
        fi;
        
    elif order = "product" or order = "block" then
        
        var_base := var{[ 1 .. l - nr_var ]};
        var_fibr := var{[ l - nr_var + 1 .. l ]};
        
        ## block order
        weights := Concatenation( Concatenation( List( [ 1 .. Length( var_base ) ], a -> "0," ) ), Concatenation( List( [ 1 .. Length( var_fibr ) ], a -> "1," ) ) );
        weights := weights{[ 1 .. Length( weights ) - 1 ]}; # remove trailing comma
        if HasIsIntegersForHomalg( r ) and IsIntegersForHomalg( r ) then
            ext_obj := homalgSendBlocking( [ "(integer", param, "),(", var_base, var_fibr, "),(a(", weights, "),dp,C)" ], TheTypeHomalgExternalRingObjectInOscar, properties, R, "CreateHomalgRing" );
        else
            ext_obj := homalgSendBlocking( [ "(", Characteristic( R ), param, "),(", var_base, var_fibr, "),(a(", weights, "),dp,C)" ], TheTypeHomalgExternalRingObjectInOscar, properties, R, "CreateHomalgRing" );
        fi;
        
    else

        if IsBound( R!.RingWithoutDummyVariable ) then
            a := R!.RingWithoutDummyVariable;
        else
            a := CoefficientsRing( R )!.RingWithoutDummyVariable;
        fi;
        
        ## degrevlex order
        if Length( var ) = 1 then
            ext_obj := homalgSendBlocking( [ "Singular.PolynomialRing(", a, ", ", var, ")" ], [ "" ], [ Concatenation( ", (", JoinStringsWithSeparator( var ), ",)" ) ], TheTypeHomalgExternalRingObjectInOscar, properties, R, "CreateHomalgRing" );
        else
            ext_obj := homalgSendBlocking( [ "Singular.PolynomialRing(", a, ", ", var, ")" ], [ "" ], [ Concatenation( ", (", JoinStringsWithSeparator( var ), ")" ) ], TheTypeHomalgExternalRingObjectInOscar, properties, R, "CreateHomalgRing" );
        fi;
        
    fi;
    
    ## this must precede CreateHomalgExternalRing as otherwise
    ## the definition of 0,1,-1 would precede "minpoly=";
    ## causing an error in the new Oscar
    if IsBound( r!.MinimalPolynomialOfPrimitiveElement ) then
        homalgSendBlocking( [ "minpoly=", r!.MinimalPolynomialOfPrimitiveElement ], "need_command", ext_obj, "define" );
    fi;
    
    S := CreateHomalgExternalRing( ext_obj, TheTypeHomalgExternalRingInOscar );
    
    S!.order := order;
    
    var := List( var, a -> HomalgExternalRingElement( a, S ) );
    
    Perform( var, Name );
    
    SetIsFreePolynomialRing( S, true );
    
    if HasIndeterminatesOfPolynomialRing( R ) and IndeterminatesOfPolynomialRing( R ) <> [ ] then
        
        SetBaseRing( S, R );
        SetRelativeIndeterminatesOfPolynomialRing( S, var{[ l - nr_var + 1 .. l ]} );
        
        if false then # order = fail then
            
            P := PolynomialRingWithProductOrdering( R, indets );
            
            weights := Concatenation( ListWithIdenticalEntries( l - nr_var, 0 ), ListWithIdenticalEntries( nr_var, 1 ) );
            W := PolynomialRing( R, indets : order := rec( weights := weights ) );
            
            SetPolynomialRingWithDegRevLexOrdering( S, S );
            SetPolynomialRingWithDegRevLexOrdering( P, S );
            SetPolynomialRingWithDegRevLexOrdering( W, S );
            
            SetPolynomialRingWithProductOrdering( S, P );
            SetPolynomialRingWithProductOrdering( P, P );
            SetPolynomialRingWithProductOrdering( W, P );
            
            SetPolynomialRingWithWeightedOrdering( S, W );
            SetPolynomialRingWithWeightedOrdering( P, W );
            SetPolynomialRingWithWeightedOrdering( W, W );
            
        fi;
        
    else
        
        if order = fail then
            
            SetPolynomialRingWithDegRevLexOrdering( S, S );
            
        fi;
        
    fi;
    
    SetRingProperties( S, r, var );
    
    RP := homalgTable( S );
    
    homalgStream( S ).setinvol( S );
    
    if not ( HasIsFieldForHomalg( r ) and IsFieldForHomalg( r ) ) then
        Unbind( RP!.IsUnit );
        Unbind( RP!.GetColumnIndependentUnitPositions );
        Unbind( RP!.GetRowIndependentUnitPositions );
        Unbind( RP!.GetUnitPosition );
    fi;
    
    if HasIsIntegersForHomalg( r ) and IsIntegersForHomalg( r ) then
        RP!.PrimaryDecomposition := RP!.PrimaryDecomposition_Z;
        RP!.RadicalSubobject := RP!.RadicalSubobject_Z;
        RP!.RadicalDecomposition := RP!.RadicalDecomposition_Z;
        Unbind( RP!.CoefficientsOfUnreducedNumeratorOfWeightedHilbertPoincareSeries );
        Unbind( RP!.MaximalDegreePart );
    fi;
    
    Unbind( RP!.ReducedRowEchelonForm );
    Unbind( RP!.ReducedColumnEchelonForm );
    
    return S;
    
end );

##
InstallMethod( PolynomialRingWithProductOrdering,
        "for homalg rings in Oscar",
        [ IsHomalgExternalRingInOscarRep, IsList ],
        
  function( R, indets )
    
    return PolynomialRing( R, indets : order := "product" );
    
end );

##
InstallMethod( PolynomialRingWithLexicographicOrdering,
        "for homalg rings in Oscar",
        [ IsHomalgExternalRingInOscarRep, IsList ],
        
  function( R, indets )
    
    return PolynomialRing( R, indets : order := "lex" );
    
end );

##
InstallMethod( RingOfDerivations,
        "for homalg rings in Oscar",
        [ IsHomalgExternalRingInOscarRep, IsList ],
        
  function( R, indets )
    local ar, r, var, der, param, base, stream, display_color, ext_obj, b, n, S, RP;
    
    ar := _PrepareInputForRingOfDerivations( R, indets );
    
    r := ar[1];
    var := ar[2];
    der := ar[3];
    param := ar[4];
    base := ar[5];
    
    stream := homalgStream( R );
    
    if ( not ( IsBound( HOMALG_IO.show_banners ) and HOMALG_IO.show_banners = false )
         and not ( IsBound( stream.show_banner ) and stream.show_banner = false )
         and not ( IsBound( stream.show_banner_PLURAL ) and stream.show_banner_PLURAL = false ) ) then
        
        if IsBound( stream.color_display ) then
            display_color := stream.color_display;
        else
            display_color := "";
        fi;
        
        Print( "================================================================\n" );
        
        ## leave the below indentation untouched!
        Print( display_color, "\
                     SINGULAR::PLURAL\n\
The SINGULAR Subsystem for Non-commutative Polynomial Computations\n\
     by: G.-M. Greuel, V. Levandovskyy, H. Schoenemann\n\
FB Mathematik der Universitaet, D-67653 Kaiserslautern\033[0m\n\
================================================================\n" );
        
        stream.show_banner_PLURAL := false;
        
    fi;
    
    ## create the new ring in 2 steps: expand polynomial ring with derivatives and then
    ## add the Weyl-structure
    ## todo: this creates a block ordering with a new "dp"-block
    if HasIsIntegersForHomalg( r ) and IsIntegersForHomalg( r ) then
        if base <> "" then
            ext_obj := homalgSendBlocking( [ "(integer", param,  "),(", base, var, der, "),(dp(", Length( base ), "),dp,C)" ], R, "initialize" );
        else
            ext_obj := homalgSendBlocking( [ "(integer", param,  "),(", var, der, "),(dp,C)" ], R, "initialize" );
        fi;
    else
        if base <> "" then
            ext_obj := homalgSendBlocking( [ "(", Characteristic( R ), param, "),(", base, var, der, "),(dp(", Length( base ), "),dp,C)" ], R, "initialize" );
        else
            ext_obj := homalgSendBlocking( [ "(", Characteristic( R ), param, "),(", var, der, "),(dp,C)" ], R, "initialize" );
        fi;
    fi;
    
    ## as we are not yet done we cannot call CreateHomalgExternalRing
    ## to create a HomalgRing, and only then would homalgSendBlocking call stream.setring,
    ## so till then we have to prevent the garbage collector from stepping in
    stream.DeletePeriod_save := stream.DeletePeriod;
    stream.DeletePeriod := false;
    
    if base <> "" then
        b := Length( base );
        n := b + Length( var ) + Length( der );
        homalgSendBlocking( [ "matrix @M[", n, "][", n, "]" ], "need_command", ext_obj, "initialize" );
        n := Length( der );
        b := List( [ 1 .. Length( der ) ], i -> Concatenation( "@M[", String( b + i ), ",", String( b + n + i ), "] = 1;" ) );
        homalgSendBlocking( Concatenation( b ), "need_command", ext_obj, "initialize" );
        ext_obj := homalgSendBlocking( [ "nc_algebra(1,@M)" ], TheTypeHomalgExternalRingObjectInOscar, ext_obj, "CreateHomalgRing" );
    else
        ext_obj := homalgSendBlocking( [ "Weyl()" ], TheTypeHomalgExternalRingObjectInOscar, ext_obj, "CreateHomalgRing" );
    fi;
    
    ## this must precede CreateHomalgExternalRing as otherwise
    ## the definition of 0,1,-1 would precede "minpoly=";
    ## causing an error in the new Oscar
    if IsBound( r!.MinimalPolynomialOfPrimitiveElement ) then
        homalgSendBlocking( [ "minpoly=", r!.MinimalPolynomialOfPrimitiveElement ], "need_command", ext_obj, "define" );
    fi;
    
    S := CreateHomalgExternalRing( ext_obj, TheTypeHomalgExternalRingInOscar );
    
    ## now it is safe to call the garbage collector
    stream.DeletePeriod := stream.DeletePeriod_save;
    Unbind( stream.DeletePeriod_save );
    
    der := List( der , a -> HomalgExternalRingElement( a, S ) );
    
    Perform( der, Name );
    
    SetIsWeylRing( S, true );
    
    SetBaseRing( S, R );
    
    SetRingProperties( S, R, der );
    
    RP := homalgTable( S );
    
    RP!.SetInvolution :=
      function( R )
        homalgSendBlocking( Concatenation(
                [ "\nproc Involution (matrix M)\n{\n" ],
                [ "  map F = ", R, ", " ],
                [ JoinStringsWithSeparator( List( IndeterminateCoordinatesOfRingOfDerivations( R ), String ) ) ],
                Concatenation( List( IndeterminateDerivationsOfRingOfDerivations( R ), a -> [ ", -" , String( a ) ] ) ),
                [ ";\n  return( transpose( involution( M, F ) ) );\n}\n\n" ]
                ), "need_command", "define" );
    end;
    
    homalgStream( S ).setinvol( S );
    
    RP!.Compose :=
      function( A, B )
        
        # fix the broken design of Plural
        return homalgSendBlocking( [ "transpose( transpose(", A, ") * transpose(", B, ") )" ], [ "matrix" ], "Compose" );
        
    end;
    
    ## there exists a bug in Plural (3-0-4,3-1-0) that occurs with nres(M,2)[2];
    if homalgSendBlocking( "\n\
// start: check the nres-isHomog-bug in Plural:\n\
ring homalg_Weyl_1 = 0,(x,y,z,Dx,Dy,Dz),dp;\n\
def homalg_Weyl_2 = Weyl();\n\
setring homalg_Weyl_2;\n\
option(redTail);short=0;\n\
matrix homalg_Weyl_3[1][3] = 3*Dy-Dz,2*x,3*Dx+3*Dz;\n\
matrix homalg_Weyl_4 = nres(homalg_Weyl_3,2)[2];\n\
ncols(homalg_Weyl_4) == 2; kill homalg_Weyl_4; kill homalg_Weyl_3; kill homalg_Weyl_2; kill homalg_Weyl_1;\n\
// end: check the nres-isHomog-bug in Plural."
    , "need_output", S, "initialize" ) = "1" then;
    
        Unbind( RP!.ReducedSyzygiesGeneratorsOfRows );
        Unbind( RP!.ReducedSyzygiesGeneratorsOfColumns );
    fi;
    
    _Oscar_SetRing( S );
    
    ## there seems to exists a bug in Plural that occurs with mres(M,1)[1];
    Unbind( RP!.ReducedBasisOfRowModule );
    Unbind( RP!.ReducedBasisOfColumnModule );
    
    if not ( HasIsFieldForHomalg( r ) and IsFieldForHomalg( r ) ) then
        Unbind( RP!.IsUnit );
        Unbind( RP!.GetColumnIndependentUnitPositions );
        Unbind( RP!.GetRowIndependentUnitPositions );
        Unbind( RP!.GetUnitPosition );
    fi;
    
    if HasIsIntegersForHomalg( r ) and IsIntegersForHomalg( r ) then
        RP!.PrimaryDecomposition := RP!.PrimaryDecomposition_Z;
        RP!.RadicalSubobject := RP!.RadicalSubobject_Z;
        RP!.RadicalDecomposition := RP!.RadicalDecomposition_Z;
        Unbind( RP!.CoefficientsOfUnreducedNumeratorOfWeightedHilbertPoincareSeries );
        Unbind( RP!.MaximalDegreePart );
    fi;
    
    return S;
    
end );

##
InstallMethod( RingOfDerivations,
        "for homalg rings in Oscar",
        [ IsHomalgExternalRingInOscarRep, IsList, IsList ],
        
  function( R, indets, weights )
    local ar, r, var, der, param, stream, display_color, ext_obj, S, RP;
    
    ar := _PrepareInputForRingOfDerivations( R, indets );
    
    r := ar[1];
    var := ar[2];
    der := ar[3];
    param := ar[4];
    
    stream := homalgStream( R );
    
    if ( not ( IsBound( HOMALG_IO.show_banners ) and HOMALG_IO.show_banners = false )
         and not ( IsBound( stream.show_banner ) and stream.show_banner = false )
         and not ( IsBound( stream.show_banner_PLURAL ) and stream.show_banner_PLURAL = false ) ) then
        
        if IsBound( stream.color_display ) then
            display_color := stream.color_display;
        else
            display_color := "";
        fi;
        
        Print( "================================================================\n" );
        
        ## leave the below indentation untouched!
        Print( display_color, "\
                     SINGULAR::PLURAL\n\
The SINGULAR Subsystem for Non-commutative Polynomial Computations\n\
     by: G.-M. Greuel, V. Levandovskyy, H. Schoenemann\n\
FB Mathematik der Universitaet, D-67653 Kaiserslautern\033[0m\n\
================================================================\n" );
        
        stream.show_banner_PLURAL := false;
        
    fi;
    
    ## create the new ring in 2 steps: expand polynomial ring with derivatives and then
    ## add the Weyl-structure
    ## todo: this creates a block ordering with a new "dp"-block
    if HasIsIntegersForHomalg( r ) and IsIntegersForHomalg( r ) then
        ext_obj := homalgSendBlocking( [ "(integer", param,  "),(", var, der, "),(wp(", weights, "),c)" ], R, "initialize" );
    else
        ext_obj := homalgSendBlocking( [ "(", Characteristic( R ), param, "),(", var, der, "),(wp(", weights, "),c)" ], R, "initialize" );
    fi;
    
    ## as we are not yet done we cannot call CreateHomalgExternalRing
    ## to create a HomalgRing, and only then would homalgSendBlocking call stream.setring,
    ## so till then we have to prevent the garbage collector from stepping in
    stream.DeletePeriod_save := stream.DeletePeriod;
    stream.DeletePeriod := false;
    
    ext_obj := homalgSendBlocking( [ "Weyl();" ], TheTypeHomalgExternalRingObjectInOscar, ext_obj, "CreateHomalgRing" );
    
    ## this must precede CreateHomalgExternalRing as otherwise
    ## the definition of 0,1,-1 would precede "minpoly=";
    ## causing an error in the new Oscar
    if IsBound( r!.MinimalPolynomialOfPrimitiveElement ) then
        homalgSendBlocking( [ "minpoly=", r!.MinimalPolynomialOfPrimitiveElement ], "need_command", ext_obj, "define" );
    fi;
    
    S := CreateHomalgExternalRing( ext_obj, TheTypeHomalgExternalRingInOscar );
    
    ## now it is safe to call the garbage collector
    stream.DeletePeriod := stream.DeletePeriod_save;
    Unbind( stream.DeletePeriod_save );
    
    der := List( der , a -> HomalgExternalRingElement( a, S ) );
    
    Perform( der, Name );
    
    SetIsWeylRing( S, true );
    
    SetBaseRing( S, R );
    
    SetRingProperties( S, R, der );
    
    RP := homalgTable( S );
    
    RP!.SetInvolution :=
      function( R )
        homalgSendBlocking( Concatenation(
                [ "\nproc Involution (matrix M)\n{\n" ],
                [ "  map F = ", R, ", " ],
                [ JoinStringsWithSeparator( List( IndeterminateCoordinatesOfRingOfDerivations( R ), String ) ) ],
                Concatenation( List( IndeterminateDerivationsOfRingOfDerivations( R ), a -> [ ", -" , String( a ) ] ) ),
                [ ";\n  return( transpose( involution( M, F ) ) );\n}\n\n" ]
                ), "need_command", "define" );
    end;
    
    homalgStream( S ).setinvol( S );
    
    RP!.Compose :=
      function( A, B )
        
        # fix the broken design of Plural
        return homalgSendBlocking( [ "transpose( transpose(", A, ") * transpose(", B, ") )" ], [ "matrix" ], "Compose" );
        
    end;
    
    ## there exists a bug in Plural (3-0-4,3-1-0) that occurs with nres(M,2)[2];
    if homalgSendBlocking( "\n\
// start: check the nres-isHomog-bug in Plural:\n\
ring homalg_Weyl_1 = 0,(x,y,z,Dx,Dy,Dz),dp;\n\
def homalg_Weyl_2 = Weyl();\n\
setring homalg_Weyl_2;\n\
option(redTail);short=0;\n\
matrix homalg_Weyl_3[1][3] = 3*Dy-Dz,2*x,3*Dx+3*Dz;\n\
matrix homalg_Weyl_4 = nres(homalg_Weyl_3,2)[2];\n\
ncols(homalg_Weyl_4) == 2; kill homalg_Weyl_4; kill homalg_Weyl_3; kill homalg_Weyl_2; kill homalg_Weyl_1;\n\
// end: check the nres-isHomog-bug in Plural."
    , "need_output", S, "initialize" ) = "1" then;
    
        Unbind( RP!.ReducedSyzygiesGeneratorsOfRows );
        Unbind( RP!.ReducedSyzygiesGeneratorsOfColumns );
    fi;
    
    _Oscar_SetRing( S );
    
    ## there seems to exists a bug in Plural that occurs with mres(M,1)[1];
    Unbind( RP!.ReducedBasisOfRowModule );
    Unbind( RP!.ReducedBasisOfColumnModule );
    
    if not ( HasIsFieldForHomalg( r ) and IsFieldForHomalg( r ) ) then
        Unbind( RP!.IsUnit );
        Unbind( RP!.GetColumnIndependentUnitPositions );
        Unbind( RP!.GetRowIndependentUnitPositions );
        Unbind( RP!.GetUnitPosition );
    fi;
    
    if HasIsIntegersForHomalg( r ) and IsIntegersForHomalg( r ) then
        RP!.PrimaryDecomposition := RP!.PrimaryDecomposition_Z;
        RP!.RadicalSubobject := RP!.RadicalSubobject_Z;
        RP!.RadicalDecomposition := RP!.RadicalDecomposition_Z;
        Unbind( RP!.CoefficientsOfUnreducedNumeratorOfWeightedHilbertPoincareSeries );
        Unbind( RP!.MaximalDegreePart );
    fi;
    
    if 0 in weights then
        Unbind( RP!.IsUnit );
        Unbind( RP!.GetColumnIndependentUnitPositions );
        Unbind( RP!.GetRowIndependentUnitPositions );
        Unbind( RP!.GetUnitPosition );
    fi;
    
    RP!.MatrixOfSymbols := RP!.MatrixOfSymbols_workaround;
    
    return S;
    
end );

##
InstallMethod( ExteriorRing,
        "for homalg rings in Oscar",
        [ IsHomalgExternalRingInOscarRep, IsHomalgExternalRingInOscarRep, IsHomalgExternalRingInOscarRep, IsList ],
        
  function( R, Coeff, Base, indets )
    local ar, r, param, var, anti, comm, stream, display_color, ext_obj, S, RP;
    
    ar := _PrepareInputForExteriorRing( R, Base, indets );
    
    r := ar[1];
    param := ar[2];
    var := ar[3];
    anti := ar[4];
    comm := ar[5];
    
    stream := homalgStream( R );
    
    if ( not ( IsBound( HOMALG_IO.show_banners ) and HOMALG_IO.show_banners = false )
         and not ( IsBound( stream.show_banner ) and stream.show_banner = false )
         and not ( IsBound( stream.show_banner_SCA ) and stream.show_banner_SCA = false ) ) then
        
        if IsBound( stream.color_display ) then
            display_color := stream.color_display;
        else
            display_color := "";
        fi;
        
        Print( "================================================================\n" );
        
        ## leave the below indentation untouched!
        Print( display_color, "\
                     SINGULAR::SCA\n\
The SINGULAR Subsystem for Super-Commutative Algebras\n\
     by: G.-M. Greuel, O. Motsak, H. Schoenemann\n\
FB Mathematik der Universitaet, D-67653 Kaiserslautern\033[0m\n\
================================================================\n" );
        
        stream.show_banner_SCA := false;
        
    fi;
    
    ## create the new ring in 2 steps: create a polynomial ring with anti commuting and commuting variables and then
    ## add the exterior structure
    ext_obj := homalgSendBlocking( [ "(", Characteristic( R ), param, "),(", Concatenation( comm, anti ), "),(dp,C)" ], R, "initialize" );
    
    ## as we are not yet done we cannot call CreateHomalgExternalRing
    ## to create a HomalgRing, and only then would homalgSendBlocking call stream.setring,
    ## so till then we have to prevent the garbage collector from stepping in
    stream.DeletePeriod_save := stream.DeletePeriod;
    stream.DeletePeriod := false;
    
    ext_obj := homalgSendBlocking( [ "superCommutative_ForHomalg(", Length( comm ) + 1, ");" ], TheTypeHomalgExternalRingObjectInOscar, ext_obj, "CreateHomalgRing" );
    
    ## this must precede CreateHomalgExternalRing as otherwise
    ## the definition of 0,1,-1 would precede "minpoly=";
    ## causing an error in the new Oscar
    if IsBound( r!.MinimalPolynomialOfPrimitiveElement ) then
        homalgSendBlocking( [ "minpoly=", r!.MinimalPolynomialOfPrimitiveElement ], "need_command", ext_obj, "define" );
    fi;
    
    S := CreateHomalgExternalRing( ext_obj, TheTypeHomalgExternalRingInOscar );
    
    ## now it is safe to call the garbage collector
    stream.DeletePeriod := stream.DeletePeriod_save;
    Unbind( stream.DeletePeriod_save );
    
    anti := List( anti , a -> HomalgExternalRingElement( a, S ) );
    
    Perform( anti, Name );
    
    comm := List( comm , a -> HomalgExternalRingElement( a, S ) );
    
    Perform( comm, Name );
    
    SetIsExteriorRing( S, true );
    
    SetBaseRing( S, Base );
    
    SetRingProperties( S, R, anti );
    
    homalgSendBlocking( "option(redTail);option(redSB);", "need_command", stream, "initialize" );
    
    RP := homalgTable( S );
    
    RP!.SetInvolution :=
      function( R )
        homalgSendBlocking( Concatenation(
                [ "\nproc Involution (matrix M)\n{\n" ],
                [ "  map F = ", R ],
                Concatenation( List( IndeterminatesOfExteriorRing( R ), a -> [ ", ", String( a ) ] ) ),
                [ ";\n  return( transpose( involution( M, F ) ) );\n}\n\n" ]
                ), "need_command", "define" );
    end;
    
    homalgStream( S ).setinvol( S );
    
    RP!.Compose :=
      function( A, B )
        
        # fix the broken design of SCA
        return homalgSendBlocking( [ "transpose( transpose(", A, ") * transpose(", B, ") )" ], [ "matrix" ], "Compose" );
        
    end;
    
    if not ( HasIsFieldForHomalg( r ) and IsFieldForHomalg( r ) ) then
        Unbind( RP!.IsUnit );
        Unbind( RP!.GetColumnIndependentUnitPositions );
        Unbind( RP!.GetRowIndependentUnitPositions );
        Unbind( RP!.GetUnitPosition );
    fi;
    
    if HasIsIntegersForHomalg( r ) and IsIntegersForHomalg( r ) then
        RP!.PrimaryDecomposition := RP!.PrimaryDecomposition_Z;
        RP!.RadicalSubobject := RP!.RadicalSubobject_Z;
        RP!.RadicalDecomposition := RP!.RadicalDecomposition_Z;
        Unbind( RP!.CoefficientsOfUnreducedNumeratorOfWeightedHilbertPoincareSeries );
        Unbind( RP!.MaximalDegreePart );
    fi;
    
    return S;
    
end );

##
InstallMethod( PseudoDoubleShiftAlgebra,
        "for homalg rings in Oscar",
        [ IsHomalgExternalRingInOscarRep, IsList ],
        
  function( R, indets )
    local ar, r, var, shift, param, base, stream, display_color, switch, ext_obj,
          b, n, steps, pairs, d, P, RP, Ds, D_s, S, B, T, Y;
    
    ar := _PrepareInputForPseudoDoubleShiftAlgebra( R, indets );
    
    r := ar[1];
    var := ar[2];
    shift := ar[3];
    param := ar[4];
    base := ar[5];
    
    stream := homalgStream( R );
    
    if ( not ( IsBound( HOMALG_IO.show_banners ) and HOMALG_IO.show_banners = false )
         and not ( IsBound( stream.show_banner ) and stream.show_banner = false )
         and not ( IsBound( stream.show_banner_PLURAL ) and stream.show_banner_PLURAL = false ) ) then
        
        if IsBound( stream.color_display ) then
            display_color := stream.color_display;
        else
            display_color := "";
        fi;
        
        Print( "================================================================\n" );
        
        ## leave the below indentation untouched!
        Print( display_color, "\
                     SINGULAR::PLURAL\n\
The SINGULAR Subsystem for Non-commutative Polynomial Computations\n\
     by: G.-M. Greuel, V. Levandovskyy, H. Schoenemann\n\
FB Mathematik der Universitaet, D-67653 Kaiserslautern\033[0m\n\
================================================================\n" );
        
        stream.show_banner_PLURAL := false;
        
    fi;
    
    switch := ValueOption( "switch" );
    
    ## create the new ring in 2 steps: expand polynomial ring with shifts and then
    ## add the shift-structure
    ## todo: this creates a block ordering with a new "dp"-block
    
    if IsIdenticalObj( switch, true ) then
        
        if HasIsIntegersForHomalg( r ) and IsIntegersForHomalg( r ) then
            if base <> "" then
                #ext_obj := homalgSendBlocking( [ "(integer", param,  "),(", base, shift, var, "),(dp(", Length( base ), "),dp,C)" ], R, "initialize" );
                ext_obj := homalgSendBlocking( [ "(integer", param,  "),(", base, shift, var, "),(dp,C)" ], R, "initialize" );
            else
                ext_obj := homalgSendBlocking( [ "(integer", param,  "),(", shift, var, "),(dp,C)" ], R, "initialize" );
            fi;
        else
            if base <> "" then
                #ext_obj := homalgSendBlocking( [ "(", Characteristic( R ), param, "),(", base, shift, var, "),(dp(", Length( base ), "),dp,C)" ], R, "initialize" );
                ext_obj := homalgSendBlocking( [ "(", Characteristic( R ), param, "),(", base, shift, var, "),(dp,C)" ], R, "initialize" );
            else
                ext_obj := homalgSendBlocking( [ "(", Characteristic( R ), param, "),(", shift, var, "),(dp,C)" ], R, "initialize" );
            fi;
        fi;
        
    else
        
        if HasIsIntegersForHomalg( r ) and IsIntegersForHomalg( r ) then
            if base <> "" then
                #ext_obj := homalgSendBlocking( [ "(integer", param,  "),(", base, var, shift, "),(dp(", Length( base ), "),dp,C)" ], R, "initialize" );
                ext_obj := homalgSendBlocking( [ "(integer", param,  "),(", base, var, shift, "),(dp,C)" ], R, "initialize" );
            else
                ext_obj := homalgSendBlocking( [ "(integer", param,  "),(", var, shift, "),(dp,C)" ], R, "initialize" );
            fi;
        else
            if base <> "" then
                #ext_obj := homalgSendBlocking( [ "(", Characteristic( R ), param, "),(", base, var, shift, "),(dp(", Length( base ), "),dp,C)" ], R, "initialize" );
                ext_obj := homalgSendBlocking( [ "(", Characteristic( R ), param, "),(", base, var, shift, "),(dp,C)" ], R, "initialize" );
            else
                ext_obj := homalgSendBlocking( [ "(", Characteristic( R ), param, "),(", var, shift, "),(dp,C)" ], R, "initialize" );
            fi;
        fi;
        
    fi;
    
    ## as we are not yet done we cannot call CreateHomalgExternalRing
    ## to create a HomalgRing, and only then would homalgSendBlocking call stream.setring,
    ## so till then we have to prevent the garbage collector from stepping in
    stream.DeletePeriod_save := stream.DeletePeriod;
    stream.DeletePeriod := false;
    
    b := Length( base );
    n := b + Length( var ) + Length( shift );
    
    homalgSendBlocking( [ "matrix @d[", n, "][", n, "]" ], "need_command", ext_obj, "initialize" );
    
    n := Length( shift ) / 2;
    
    steps := ValueOption( "steps" );
    
    if IsRat( steps ) then
        steps := ListWithIdenticalEntries( n, steps );
    elif not ( IsList( steps ) and Length( steps ) = n and ForAll( steps, IsRat ) ) then
        steps := ListWithIdenticalEntries( n, 1 );
    fi;
    
    pairs := ValueOption( "pairs" );
    
    if IsIdenticalObj( switch, true ) then
        
        if IsIdenticalObj( pairs, true ) then
            d := Concatenation(
                         List( [ 1 .. n ],
                               i -> Concatenation( "@d[", String( b + ( 2 * i - 1 ) ), ",", String( b + 2 * n + i ), "] = -(", String( steps[i] ), ") * ", shift[2 * i - 1] ) ),
                         List( [ 1 .. n ],
                               i -> Concatenation( "@d[", String( b + ( 2 * i ) ), ",", String( b + 2 * n + i ), "] = (", String( steps[i] ), ") * ", shift[2 * i] ) ) );
        else
            d := Concatenation(
                         List( [ 1 .. n ],
                               i -> Concatenation( "@d[", String( b + ( i ) ), ",", String( b + 2 * n + i ), "] = -(", String( steps[i] ), ") * ", shift[i] ) ),
                         List( [ 1 .. n ],
                               i -> Concatenation( "@d[", String( b + ( n + i ) ), ",", String( b + 2 * n + i ), "] = (", String( steps[i] ), ") * ", shift[n + i] ) ) );
        fi;
        
    else
        
        if IsIdenticalObj( pairs, true ) then
            d := Concatenation(
                         List( [ 1 .. n ],
                               i -> Concatenation( "@d[", String( b + i ), ",", String( b + n + ( 2 * i - 1 ) ), "] = (", String( steps[i] ), ") * ", shift[2 * i - 1] ) ),
                         List( [ 1 .. n ],
                               i -> Concatenation( "@d[", String( b + i ), ",", String( b + n + ( 2 * i ) ), "] = -(", String( steps[i] ), ") * ", shift[2 * i] ) ) );
        else
            d := Concatenation(
                         List( [ 1 .. n ],
                               i -> Concatenation( "@d[", String( b + i ), ",", String( b + n + ( i ) ), "] = (", String( steps[i] ), ") * ", shift[i] ) ),
                         List( [ 1 .. n ],
                               i -> Concatenation( "@d[", String( b + i ), ",", String( b + n + ( n + i ) ), "] = -(", String( steps[i] ), ") * ", shift[n + i] ) ) );
        fi;
        
    fi;
    
    homalgSendBlocking( JoinStringsWithSeparator( d, "; " ), "need_command", ext_obj, "initialize" );
    
    ext_obj := homalgSendBlocking( [ "nc_algebra(1,@d)" ], TheTypeHomalgExternalRingObjectInOscar, ext_obj, "CreateHomalgRing" );
    
    ## this must precede CreateHomalgExternalRing as otherwise
    ## the definition of 0,1,-1 would precede "minpoly=";
    ## causing an error in the new Oscar
    if IsBound( r!.MinimalPolynomialOfPrimitiveElement ) then
        homalgSendBlocking( [ "minpoly=", r!.MinimalPolynomialOfPrimitiveElement ], "need_command", ext_obj, "define" );
    fi;
    
    P := CreateHomalgExternalRing( ext_obj, TheTypeHomalgExternalRingInOscar );
    
    ## now it is safe to call the garbage collector
    stream.DeletePeriod := stream.DeletePeriod_save;
    Unbind( stream.DeletePeriod_save );
    
    var := List( var , a -> HomalgExternalRingElement( a, P ) );
    
    Perform( var, Name );
    
    shift := List( shift , a -> HomalgExternalRingElement( a, P ) );
    
    Perform( shift, Name );
    
    SetIsPseudoDoubleShiftAlgebra( P, true );
    
    SetBaseRing( P, R );
    
    SetRingProperties( P, R, shift );
    
    RP := homalgTable( P );
    
    RP!.SetInvolution :=
      function( R )
        homalgSendBlocking( Concatenation(
                [ "\nproc Involution (matrix M)\n{\n" ],
                [ "  map F = ", R, ", " ],
                Concatenation( List( IndeterminateCoordinatesOfPseudoDoubleShiftAlgebra( R ), a -> [ "-" , String( a ), ", " ] ) ),
                [ JoinStringsWithSeparator( List( IndeterminateShiftsOfPseudoDoubleShiftAlgebra( R ), String ), ", " ) ],
                [ ";\n  return( transpose( involution( M, F ) ) );\n}\n\n" ]
                ), "need_command", "define" );
    end;
    
    homalgStream( P ).setinvol( P );
    
    RP!.Compose :=
      function( A, B )
        
        # fix the broken design of Plural
        return homalgSendBlocking( [ "transpose( transpose(", A, ") * transpose(", B, ") )" ], [ "matrix" ], "Compose" );
        
    end;
    
    ## there exists a bug in Plural (3-0-4,3-1-0) that occurs with nres(M,2)[2];
    if homalgSendBlocking( "\n\
// start: check the nres-isHomog-bug in Plural:\n\
ring homalg_Weyl_1 = 0,(x,y,z,Dx,Dy,Dz),dp;\n\
def homalg_Weyl_2 = Weyl();\n\
setring homalg_Weyl_2;\n\
option(redTail);short=0;\n\
matrix homalg_Weyl_3[1][3] = 3*Dy-Dz,2*x,3*Dx+3*Dz;\n\
matrix homalg_Weyl_4 = nres(homalg_Weyl_3,2)[2];\n\
ncols(homalg_Weyl_4) == 2; kill homalg_Weyl_4; kill homalg_Weyl_3; kill homalg_Weyl_2; kill homalg_Weyl_1;\n\
// end: check the nres-isHomog-bug in Plural."
    , "need_output", P, "initialize" ) = "1" then;
    
        Unbind( RP!.ReducedSyzygiesGeneratorsOfRows );
        Unbind( RP!.ReducedSyzygiesGeneratorsOfColumns );
    fi;
    
    _Oscar_SetRing( P );
    
    ## there seems to exists a bug in Plural that occurs with mres(M,1)[1];
    Unbind( RP!.ReducedBasisOfRowModule );
    Unbind( RP!.ReducedBasisOfColumnModule );
    
    if not ( HasIsFieldForHomalg( r ) and IsFieldForHomalg( r ) ) then
        Unbind( RP!.IsUnit );
        Unbind( RP!.GetColumnIndependentUnitPositions );
        Unbind( RP!.GetRowIndependentUnitPositions );
        Unbind( RP!.GetUnitPosition );
    fi;
    
    if HasIsIntegersForHomalg( r ) and IsIntegersForHomalg( r ) then
        RP!.PrimaryDecomposition := RP!.PrimaryDecomposition_Z;
        RP!.RadicalSubobject := RP!.RadicalSubobject_Z;
        RP!.RadicalDecomposition := RP!.RadicalDecomposition_Z;
        Unbind( RP!.CoefficientsOfUnreducedNumeratorOfWeightedHilbertPoincareSeries );
        Unbind( RP!.MaximalDegreePart );
    fi;
    
    shift := List( shift, String );
    
    if IsIdenticalObj( pairs, true ) then
        Ds := shift{List( [ 1 .. n ], i -> 2 * i - 1 )};
        D_s := shift{List( [ 1 .. n ], i -> 2 * i )};
    else
        Ds := shift{[ 1 .. n ]};
        D_s := shift{[ n + 1 .. 2 * n ]};
    fi;
    
    ## the "commutative" double-shift algebra
    S := R * shift;
    
    ## does not reduce elements instantaneously
    ## S := HomalgQRingInOscar( AmbientRing( S ), RingRelations( S ) );
    
    P!.CommutativeDoubleShiftAlgebra := S / ListN( Ds, D_s, {d, d_} -> ( d / S ) * ( d_ / S ) - 1 );

    ## the Laurent algebra
    B := BaseRing( R );
    
    T := B * shift;
    
    P!.LaurentAlgebra := T / ListN( Ds, D_s, {d, d_} -> ( d / T ) * ( d_ / T ) - 1 );
    
    ## the double-shift algebra
    Y := P / ListN( Ds, D_s, {d, d_} -> ( d / P ) * ( d_ / P ) - 1 );
    
    Y!.CommutativeDoubleShiftAlgebra := P!.CommutativeDoubleShiftAlgebra;
    Y!.LaurentAlgebra := P!.LaurentAlgebra;
    
    SetBaseRing( Y, BaseRing( P ) );
    
    SetIndeterminateCoordinatesOfDoubleShiftAlgebra( Y,
            List( IndeterminateCoordinatesOfPseudoDoubleShiftAlgebra( P ), d -> d / Y ) );

    if HasRelativeIndeterminateCoordinatesOfPseudoDoubleShiftAlgebra( P ) then
        
        SetRelativeIndeterminateCoordinatesOfDoubleShiftAlgebra( Y,
                List( RelativeIndeterminateCoordinatesOfPseudoDoubleShiftAlgebra( P ), d -> d / Y ) );
    fi;
    
    SetIndeterminateShiftsOfDoubleShiftAlgebra( Y,
            List( IndeterminateShiftsOfPseudoDoubleShiftAlgebra( P ), d -> d / Y ) );
    
    P!.DoubleShiftAlgebra := Y;
    
    if not IsIdenticalObj( switch, true ) then
        P!.SwitchedPseudoDoubleShiftAlgebra := PseudoDoubleShiftAlgebra( R, indets : switch := true );
    fi;
    
    return P;
    
end );

##
InstallMethod( DoubleShiftAlgebra,
        "for homalg rings in Oscar",
        [ IsHomalgExternalRingInOscarRep, IsList ],
        
  function( R, indets )
    local P;
    
    P := PseudoDoubleShiftAlgebra( R, indets );
    
    return P!.DoubleShiftAlgebra;
    
end );

##
InstallMethod( HomalgQRingInOscar,
        "for a homalg ring in Oscar and ring relations",
        [ IsHomalgExternalRingInOscarRep and IsFreePolynomialRing, IsHomalgRingRelations ],
        
  function( R, ring_rel )
    local r, stream, ideal, ext_obj, S, RP;
    
    r := CoefficientsRing( R );
    
    if not ( HasIsFieldForHomalg( r ) and IsFieldForHomalg( r ) ) then
        Error( "Oscar qrings are currently only supported over fields" );
    fi;
    
    stream := homalgStream( R );
    
    ideal := EntriesOfHomalgMatrix( EvaluatedMatrixOfRingRelations( ring_rel ) );
    
    ext_obj := homalgSendBlocking( [ "std(ideal(", ideal, "))" ], [ "qring" ], TheTypeHomalgExternalRingObjectInOscar, R, "CreateHomalgRing" );
    
    ## this must precede CreateHomalgExternalRing as otherwise
    ## the definition of 0,1,-1 would precede "minpoly=";
    ## causing an error in the new Oscar
    if IsBound( r!.MinimalPolynomialOfPrimitiveElement ) then
        homalgSendBlocking( [ "minpoly=", r!.MinimalPolynomialOfPrimitiveElement ], "need_command", ext_obj, "define" );
    fi;
    
    S := CreateHomalgExternalRing( ext_obj, TheTypeHomalgExternalRingInOscar );
    
    ## for the view methods:
    ## <A Oscar q ring>
    ## <A matrix over an Oscar q ring>
    S!.description := " Oscar q";
    
    SetAmbientRing( S, R );
    
    SetRingRelations( S, ring_rel );
    
    homalgSendBlocking( "option(redTail);option(redSB);", "need_command", stream, "initialize" );
    
    RP := homalgTable( S );
    
    # taken from ResidueClassRingForHomalg.gi
    RP!.RingName :=
      function( R )
        local ring_rel, entries, name;
        
        ring_rel := MatrixOfRelations( R );
        
        if IsBound( ring_rel!.BasisOfRowModule ) then
            ring_rel := ring_rel!.BasisOfRowModule;
        elif IsBound( ring_rel!.BasisOfColumnModule ) then
            ring_rel := ring_rel!.BasisOfColumnModule;
        fi;
        
        if not IsBound( ring_rel!.StringOfEntriesForRingName ) then
            
            entries := EntriesOfHomalgMatrix( ring_rel );
            
            if entries = [ ] then
                entries := "0";
            elif IsHomalgInternalRingRep( AmbientRing( R ) ) then
                entries := JoinStringsWithSeparator( List( entries, String ), ", " );
            else
                entries := JoinStringsWithSeparator( List( entries, Name ), ", " );
            fi;
            
            name := RingName( AmbientRing( R ) );
            
            ring_rel!.StringOfEntries := String( Concatenation( "[ ", entries, " ]" ) );
            ring_rel!.StringOfEntriesForRingName := String( Concatenation( name, "/( ", entries, " )" ) );
            
        fi;
        
        return ring_rel!.StringOfEntriesForRingName;
        
    end;

    RP!.SetInvolution :=
      function( R )
        homalgSendBlocking( "\nproc Involution (matrix m)\n{\n  return(transpose(m));\n}\n\n", "need_command", R, "define" );
    end;
    
    homalgStream( S ).setinvol( S );
    
    RP!.IsZero := r -> homalgSendBlocking( [ "reduce(", r, ",std(0))==0" ] , "need_output", "IsZero" ) = "1";
    
    RP!.IsOne := r -> homalgSendBlocking( [ "reduce(", r, ",std(0))==1" ] , "need_output", "IsOne" ) = "1";
    
    RP!.AreEqualMatrices :=
      function( A, B )
        
        return homalgSendBlocking( [ "matrix(reduce(", A, ",std(0))) == matrix(reduce(", B, ",std(0)))" ] , "need_output", "AreEqualMatrices" ) = "1";
        
    end;
    
    # taken from ResidueClassRingForHomalg.gi
    SetIndeterminatesOfPolynomialRing( S, List( IndeterminatesOfPolynomialRing( R ), r -> r / S ) );
    
    return S;
    
end );

##
InstallMethod( HomalgQRingInOscar,
        [ IsHomalgExternalRingInOscarRep and IsFreePolynomialRing, IsHomalgMatrix ],
        
  function( R, ring_rel )
    
    if NrRows( ring_rel ) = 0 or NrColumns( ring_rel ) = 0  then
        return R;
    elif NrColumns( ring_rel ) = 1 then
        return HomalgQRingInOscar( R, HomalgRingRelationsAsGeneratorsOfLeftIdeal( ring_rel ) );
    elif NrRows( ring_rel ) = 1 then
        return HomalgQRingInOscar( R, HomalgRingRelationsAsGeneratorsOfRightIdeal( ring_rel ) );
    fi;
    
    TryNextMethod( );
    
end );

##
InstallMethod( HomalgQRingInOscar,
        [ IsHomalgExternalRingInOscarRep and IsFreePolynomialRing, IsList ],
        
  function( R, ring_rel )
    
    if ForAll( ring_rel, IsString ) then
        return HomalgQRingInOscar( R, List( ring_rel, s -> HomalgRingElement( s, R ) ) );
    elif not ForAll( ring_rel, IsRingElement ) then
        TryNextMethod( );
    fi;
    
    return HomalgQRingInOscar( R, HomalgMatrix( ring_rel, Length( ring_rel ), 1, R ) );
    
end );

##
InstallMethod( HomalgQRingInOscar,
        [ IsHomalgExternalRingInOscarRep and IsFreePolynomialRing, IsRingElement ],
        
  function( R, ring_rel )
    
    return HomalgQRingInOscar( R, [ ring_rel ] );
    
end );

##
InstallMethod( HomalgQRingInOscar,
        [ IsHomalgExternalRingInOscarRep and IsFreePolynomialRing, IsString ],
        
  function( R, ring_rel )
    
    return HomalgQRingInOscar( R, HomalgRingElement( ring_rel, R ) );
    
end );

##
InstallMethod( AddRationalParameters,
        "for Oscar rings",
        [ IsHomalgExternalRingInOscarRep and IsFieldForHomalg, IsList ],
        
  function( R, param )
    local c, par;
    
    if IsString( param ) then
        param := [ param ];
    fi;
    
    param := List( param, String );
    
    c := Characteristic( R );
    
    if HasRationalParameters( R ) then
        par := RationalParameters( R );
        par := List( par, String );
    else
        par := [ ];
    fi;
    
    par := Concatenation( par, param );
    par := JoinStringsWithSeparator( par );
    
    ## TODO: take care of the rest
    if c = 0 then
        return HomalgFieldOfRationalsInOscar( par, R );
    fi;
    
    return HomalgRingOfIntegersInOscar( c, par, R );
    
end );

##
InstallMethod( AddRationalParameters,
        "for Oscar rings",
        [ IsHomalgExternalRingInOscarRep and IsFreePolynomialRing, IsList ],
        
  function( R, param )
    local c, par, indets, r;
    
    if IsString( param ) then
        param := [ param ];
    fi;
    
    param := List( param, String );
    
    c := Characteristic( R );
    
    if HasRationalParameters( R ) then
        par := RationalParameters( R );
        par := List( par, String );
    else
        par := [ ];
    fi;
    
    par := Concatenation( par, param );
    par := JoinStringsWithSeparator( par );
    
    indets := Indeterminates( R );
    indets := List( indets, String );
    
    r := CoefficientsRing( R );
    
    if not IsFieldForHomalg( r ) then
        Error( "the coefficients ring is not a field\n" );
    fi;
    
    ## TODO: take care of the rest
    if c = 0 then
        return HomalgFieldOfRationalsInOscar( par, r ) * indets;
    fi;
    
    return HomalgRingOfIntegersInOscar( c, par, r ) * indets;
    
end );

##
InstallMethod( SetMatElm,
        "for homalg external matrices in Oscar",
        [ IsHomalgExternalMatrixRep and IsMutable, IsPosInt, IsPosInt, IsString, IsHomalgExternalRingInOscarRep ],
        
  function( M, r, c, s, R )
    
    homalgSendBlocking( [ M, "[", c, r, "]=", s ], "need_command", "SetMatElm" );
    
end );

##
InstallMethod( AddToMatElm,
        "for homalg external matrices in Oscar",
        [ IsHomalgExternalMatrixRep and IsMutable, IsPosInt, IsPosInt, IsHomalgExternalRingElementRep, IsHomalgExternalRingInOscarRep ],
        
  function( M, r, c, a, R )
    
    homalgSendBlocking( [ M, "[", c, r, "]=", a, "+", M, "[", c, r, "]" ], "need_command", "AddToMatElm" );
    
end );

##
InstallMethod( CreateHomalgMatrixFromString,
        "constructor for homalg external matrices in Oscar",
        [ IsString, IsHomalgExternalRingInOscarRep ],
        
  function( s, R )
    local r, c;
    
    r := Length( Positions( s, '[' ) ) - 1;
    
    c := ( Length( Positions( s, ',' ) ) + 1 ) / r;
    
    return CreateHomalgMatrixFromString( s, r, c, R );
    
end );

##
InstallMethod( CreateHomalgMatrixFromString,
        "constructor for homalg external matrices in Oscar",
        [ IsString, IsInt, IsInt, IsHomalgExternalRingInOscarRep ],
        
  function( s, r, c, R )
    local str, ext_obj;
    
    str := ShallowCopy( s );
    
    RemoveCharacters( str, "[]" );
    
    ext_obj := homalgSendBlocking( [ "MatrixForHomalg(", R, r, c, ", [", str, "])" ], "HomalgMatrix" );
    
    if not ( r = 1 and c = 1 ) then
        homalgSendBlocking( [ ext_obj, " = transpose(", ext_obj, ")" ], "need_command", "TransposedMatrix" );
    fi;
    
    return HomalgMatrix( ext_obj, r, c, R );
    
end );

##
InstallMethod( MatElmAsString,
        "for homalg external matrices in Oscar",
        [ IsHomalgExternalMatrixRep, IsPosInt, IsPosInt, IsHomalgExternalRingInOscarRep ],
        
  function( M, r, c, R )
    
    return homalgSendBlocking( [ M, "[", c, r, "]" ], "need_output", "MatElm" );
    
end );

##
InstallMethod( MatElm,
        "for homalg external matrices in Oscar",
        [ IsHomalgExternalMatrixRep, IsPosInt, IsPosInt, IsHomalgExternalRingInOscarRep ],
        
  function( M, r, c, R )
    local Mrc;
    
    Mrc := homalgSendBlocking( [ M, "[", c, r, "]" ], "MatElm" );
    
    return HomalgExternalRingElement( Mrc, R );
    
end );

####################################
#
# transfer methods:
#
####################################

##
InstallMethod( GetListOfHomalgMatrixAsString,
        "for homalg external matrices in Oscar",
        [ IsHomalgExternalMatrixRep, IsHomalgExternalRingInOscarRep ],
        
  function( M, R )
    
    return homalgSendBlocking( [ "\"[\"+string(transpose(", M, "))+\"]\"" ], "need_output", "GetListOfHomalgMatrixAsString" );
    #remark: matrices are saved transposed in singular
    
end );

##
InstallMethod( GetListListOfHomalgMatrixAsString,
        "for homalg external matrices in Oscar",
        [ IsHomalgExternalMatrixRep, IsHomalgExternalRingInOscarRep ],
        
  function( M, R )
    local v, command;
    
    v := homalgStream( R ).variable_name;
    
    command := [
                "matrix ", v, "m[", NrColumns( M ),"][1]; ",
                v, "s=\"[\"; ",
                "for(int i=1;i<=", NrRows( M ), ";i++){",
                v, "m=", M, "[1..", NrColumns( M ), ",i]; ",	## matrices are saved transposed in Oscar
                "if(i!=1){", v, "s=", v, "s+\",\";}; ",
                v, "s=", v, "s+\"[\"+string(", v, "m)+\"]\";}; ",
                v, "s=", v, "s+\"]\"; kill ", v, "m"
                ];
    
    homalgSendBlocking( command, "need_command", "GetListListOfHomalgMatrixAsString" );
    
    return homalgSendBlocking( [ v, "s; ", v, "s=\"\"" ], "need_output", R, "GetListListOfHomalgMatrixAsString" );
    
end );

##
InstallMethod( GetSparseListOfHomalgMatrixAsString,
        "for homalg external matrices in Oscar",
        [ IsHomalgExternalMatrixRep, IsHomalgExternalRingInOscarRep ],
        
  function( M, R )
    local s;
    
    s := homalgSendBlocking( [ "GetSparseListOfHomalgMatrixAsString(", M, ")" ], "need_output", "GetSparseListOfHomalgMatrixAsString" );
    
    s := SplitString( s, "," );
    
    s := ListToListList( s, Length( s ) / 3, 3 );
    
    s := JoinStringsWithSeparator( List( s, JoinStringsWithSeparator ), "],[" );
    
    return Concatenation( "[[", s, "]]" );
    
end );

##
InstallMethod( SaveHomalgMatrixToFile,
        "for homalg external matrices in Oscar",
        [ IsString, IsHomalgMatrix, IsHomalgExternalRingInOscarRep ],
        
  function( filename, M, R )
    local mode, v, command;
    
    if not IsBound( M!.SaveAs ) then
        mode := "ListList";
    else
        mode := M!.SaveAs; #not yet supported
    fi;
    
    if mode = "ListList" then
        
        command := [ "write(\"", filename, "\", \"", String( EntriesOfHomalgMatrixAsListList( M ) ), "\")" ]; ## matrices are saved transposed in Oscar
        
        homalgSendBlocking( command, HomalgRing( M ), "need_command", "SaveHomalgMatrixToFile" );
        
    fi;
    
    return true;
    
end );

##
InstallMethod( LoadHomalgMatrixFromFile,
        "for homalg external rings in Oscar",
        [ IsString, IsInt, IsInt, IsHomalgExternalRingInOscarRep ],
        
  function( filename, r, c, R )
    local mode, v, command, M;
    
    if not IsBound( R!.LoadAs ) then
        mode := "ListList";
    else
        mode := R!.LoadAs; #not yet supported
    fi;
    
    M := HomalgVoidMatrix( R );
    
    if mode = "ListList" then
        
        v := homalgStream( R ).variable_name;
        
        command := [
                    v, "s=read(\"", filename, "\", String); ",
                    v, "r=[]; for i = split(", v, "s, r\"[\\[,\\]\\n\\r\]+\"); if length(i)>0; push!(", v, "r, eval(Meta.parse(replace(i, \"\/\" => \"\/\/\")))); end; end; ",
                    M, "=Involution(MatrixForHomalg(", R, r, c, ", ", v, "r)); ",	## matrices are saved transposed in Oscar
                    v, "s=\"\"; ", v, "r=\"\"",
                    ];
        
        homalgSendBlocking( command, "need_command", "LoadHomalgMatrixFromFile" );
        
    fi;
    
    SetNrRows( M, r );
    SetNrColumns( M, c );
    
    return M;
    
end );

####################################
#
# View, Print, and Display methods:
#
####################################

## TODO: Workaround. Delete once https://github.com/oscar-system/Singular.jl/pull/323 is merged
InstallMethod( homalgSetName,
        "for homalg external ring elements",
        [ IsHomalgExternalRingElementRep, IsString, IsHomalgExternalRingInOscarRep ],

  function( r, name, R )
    
    name := homalgSendBlocking( [ r ], "need_output", "homalgSetName" );

    if Length( name ) > 1 and name{[ 1, 2 ]} = "1*" then
        name := name{[ 3 .. Length( name ) ]};
    fi;
    
    SetName( r, name );
    
end );

##
InstallMethod( Display,
        "for homalg external matrices in Oscar",
        [ IsHomalgExternalMatrixRep ], 1,
        
  function( o )
    
    if IsHomalgExternalRingInOscarRep( HomalgRing( o ) ) then
        
        Print( homalgSendBlocking( [ "transpose(", o, ")" ], "need_display", "Display" ) );
        
    else
        
        TryNextMethod( );
        
    fi;
    
end );

##
InstallMethod( DisplayRing,
        "for homalg rings in Oscar",
        [ IsHomalgExternalRingInOscarRep ], 1,
        
  function( o )
    
    homalgDisplay( [ o ] );
    
end );
back to top