Skip to content

Accessing Singular from Julia

malex984 edited this page Dec 19, 2014 · 26 revisions
using Cxx

const singdir = joinpath( ENV["HOME"], "singular-4/T/home/wbhart/singular-4/") # const singdir = joinpath( ENV["HOME"], "S" )

addHeaderDir(joinpath(singdir, "include"), kind = C_System)
addHeaderDir(joinpath(singdir, "include", "singular"), kind = C_System)
cxxinclude("Singular/libsingular.h", isAngled=false)

libSingular = dlopen(joinpath(singdir, "lib", "libSingular.so"), RTLD_GLOBAL)

@cxx siInit(pointer(joinpath(singdir, "bin", "Singular")))

@cxx StringSetS(pointer("Hello World!"))

@cxx feStringAppendResources(0)

s = @cxx StringEndS()
# @cxx PrintS(s)  # BUG: PrintS is a C function
# icxx" PrintS($s); "   # quick and dirty shortcut

PrintS(m) =  ccall( dlsym (libSingular, :PrintS), Void, (Ptr{Uint8},), m) # another workaround
PrintS(s)

icxx" char* n [] = { (char*)\"t\"}; ring r = rDefault( 13, 1, n); rWrite(r); PrintLn(); rDelete(r); "

function jlInit(cf::Ptr{Void}, ::Ptr{Void})
  println("jlInit: new coeffs: $cf"); return convert( Cint, 1);
end
const cjlInit = cfunction(jlInit, Cint, (Ptr{Void},Ptr{Void}))

new_typ = icxx" return nRegister( n_unknown, (cfInitCharProc)$cjlInit); " 
# CppEnum{:n_coeffType}(14)

new_coeff = icxx" return nInitChar( $new_typ, 0 ); "
# jlInit: new coeffs: Ptr{Void} @0x00007fcc9b0a7358 ### !!!! see jlInit!
# CppPtr{:n_Procs_s,()}(Ptr{Void} @0x0000000000000000)


const n_Q = icxx" return n_Q; "
const n_Z = icxx" return n_Z; "
const n_Zp =icxx" return n_Zp; "


nInitChar(n, p)  = icxx" return nInitChar( $n, (void*)($p) ); "
n_CoeffWrite(cf, details::Bool = true) = icxx" n_CoeffWrite($cf, ($details? 1 : 0)); "
n_Init(i, cf) = icxx" return n_Init ($i, $cf ); "
n_Delete(n, cf) = icxx" n_Delete(& $n, $cf); $n = 0; "

function n_Print(n, cf) 
  icxx" n_Print( $n, $cf); "
  println();
  return nothing
end


# q = 66 in QQ
Q = nInitChar( n_Q, 0 )
n_CoeffWrite(Q)
q = n_Init (66, Q )
n_Print( q, Q)
print(q)
n_Delete(q, Q)
print(q)

## z = 666 in ZZ
Z = nInitChar( n_Z, 0 )
n_CoeffWrite(Z)
z = n_Init (666, Z )
n_Print( z, Z)
print(z)
n_Delete(z, Z)
print(z)

## zz = 6 in Zp{11}
Z11 = nInitChar( n_Zp, 11 )
n_CoeffWrite(Z11)
zz = n_Init (11*3 + 6, Z11 )
n_Print( zz, Z11)
print(zz)
n_Delete(zz, Z11)
print(zz)

Here is my idea for Julia wrappers for Singular "pointer" types (all of low level element types: number, poly, ideal) which are to be treated in conjunction with corresponding management objects (coeffs, ring):

abstract SingularCoeffs

# possible concrete coeff types:
type SingularQQ <: SingularCoeffs end
immutable SingularZZ <: SingularCoeffs end
bitstype WORD_SIZE GenericSingularCoeffs  <: SingularCoeffs

abstract SingularNumber <: Number

bitstype WORD_SIZE GenericSingularNumber{Coeffs <: SingularCoeffs}  <: SingularNumber
immutable RRSingularNumber <: SingularNumber end

InitSingularNumber{Coeffs <: SingularCoeffs}( ::Type{Coeffs}, i) = reinterpret(GenericSingularNumber{Coeffs}, i)

InitSingularNumber( SingularQQ, 2 ) # GenericSingularNumber{SingularQQ}(0x0000000000000002)
isbits(ans) # true


function myop{C}( a::GenericSingularNumber{C}, b::GenericSingularNumber{C} )
  println( "myop ($a, $b) over $C")
end

myop( InitSingularNumber( SingularQQ, 22 ), InitSingularNumber( SingularQQ, 66 ) )
myop (GenericSingularNumber{SingularQQ}(0x0000000000000016), GenericSingularNumber{SingularQQ}(0x0000000000000042)) over SingularQQ

myop( InitSingularNumber( SingularZZ, 22 ), InitSingularNumber( SingularZZ, 66 ) )
myop (GenericSingularNumber{SingularZZ}(0x0000000000000016), GenericSingularNumber{SingularZZ}(0x0000000000000042)) over SingularZZ

myop( InitSingularNumber( SingularQQ, 22 ), InitSingularNumber( SingularZZ, 66 ) ) 
# ERROR: `myop` has no method matching myop(::GenericSingularNumber{SingularQQ}, ::GenericSingularNumber{SingularZZ})

myop( InitSingularNumber( SingularZZ, 22 ), InitSingularNumber( SingularQQ, 66 ) ) 
# ERROR: `myop` has no method matching myop(::GenericSingularNumber{SingularZZ}, ::GenericSingularNumber{SingularQQ})

Further experiments:

# real enum constants will come from Singular: "coeffs/coeffs.h"
const n_QQ = 444
const n_ZZ = 555
const n_Zp = 666

abstract SingularCoeffs

# possible concrete coeff types:
abstract SingularQQ <: SingularCoeffs
abstract SingularZZ <: SingularCoeffs

bitstype WORD_SIZE GenericSingularCoeffs{TYP, PAR}  <: SingularCoeffs

typ{TYP, PAR}( ::Type{GenericSingularCoeffs{TYP, PAR}} ) = TYP
par{TYP, PAR}( ::Type{GenericSingularCoeffs{TYP, PAR}} ) = PAR

typ( ::Type{SingularQQ} ) = n_QQ
par( ::Type{SingularQQ} ) = :NULL

typ( ::Type{SingularZZ} ) = n_ZZ
par( ::Type{SingularZZ} ) = :NULL

Pros:

  • we avoid one extra level of indirection (types in Julia are pointers to heap allocated things)
  • we can specialize conversions to/from Julia Number types to specific Singular Numbers

Cons:

  • we need to do "proper" construction/destruction for all such handles "by hand"

Proof of concept:

using Cxx
cxx"""
typedef void* SingularCoeffs;
typedef void* SingularNumber;
SingularNumber InitSingularNumber( SingularCoeffs cf, unsigned long i )
{ i += (unsigned long)(cf); return (SingularNumber)(i); } 
"""

@cxx InitSingularNumber( Ptr{Void}(1), 2) # Ptr{Void} @0x0000000000000003
Clone this wiki locally