SWI-Prolog / packages-jpl

JPL: The Prolog <-> Java interface
BSD 2-Clause "Simplified" License
54 stars 33 forks source link

Add JPL support for rational type #39

Closed ssardina closed 4 years ago

ssardina commented 4 years ago

SWI-Prolog can not report terms of type rational, which are not (yet) supported by JPL.

ssardina commented 4 years ago

Some progress on the Java side in 9ea1a114bd5c3a92238ac05ec7dd5d0c67034d94

JanWielemaker commented 4 years ago

Hi Sebastian! You know I know little about Java and JPL, but if I can help a little on the C side close to Prolog, I'm happy to.

ssardina commented 4 years ago

Hi Jan! Very timing indeed, thanks for offering to help.

In fact, I have almost finished the Java side of JPL for accommodating rationals, but the C side is my strong weak side. I have been trying to understand but it's challenging to say the least :-) And I don't want to make any bad mistake.

What I need is to build a Prolog term to represent a rational, basically a corresponding PL_put_*() C function. While we have for integers, floats, etc there seems to be none for rational:

https://www.swi-prolog.org/pldoc/man?section=foreign-term-construct

I would imagine we need the following C function:

int PL_put_rational(term_t -t, long n, long d)

in file src/pl-fli.c but there is none. Am I missing something why it is not there? Can we add it?

I am confused because there are some stuff about rationals there, for example:

int
PL_is_rational(term_t t)
{ GET_LD
  word w = valHandle(t);

  return isRational(w);
}

Interesingly though isRational(w) compares with an integer tag code (src/pl-data.h):

#define isRational(w)   (tag(w)   == TAG_INTEGER)

So, I suspect I am missing the point here. To me it seems rationals are partially supported in all this , but this cannot be right and I am not understanding it correctly.

Again, I think what I need is the PL_put_rational(term_t -t, long n, long d) function

JanWielemaker commented 4 years ago

The relevant documentation is here. Some remarks:

ssardina commented 4 years ago

Are you suggesting that I treat a rational in Java as a String, similarly as we do with BigInteger (arbitrary precision)?

Yes when we put a BigInteger into a term, we treat the number as a String and then use PL_chars_to_term as follows:

JNIEXPORT jboolean JNICALL
Java_org_jpl7_fli_Prolog_put_1integer_1big(JNIEnv *env, jclass jProlog,
                                           jobject jterm, jstring jvalue)
{ term_t term;

  if ( jpl_ensure_pvm_init(env) &&
       getTermValue(env, jterm, &term))
  { return PL_chars_to_term((char *)(*env)->GetStringUTFChars(env, jvalue, 0),
                            term);
  } else
  { return FALSE;
  }
}

See all this code is in the JNI interface jpl.c so requires nothing from code SWI code in the FLI.

mmm would this work if I just represent the rational number a String with two numbers separated with an r? Like 2r3 for 2/3? Is that easy?

I guess chars_to_term will take the chars 2r3 and covert it to a Prolog 2 rdiv 3.. Is that true?

Sorry I am pretty basic (actually null) at the C side of SWI so most of it is "guessing" rather than true knowledge.. ;-)

ssardina commented 4 years ago

BTW, shouldn't TAG_INTEGER be renamed TAG_RATIONAL as integers are rational, not the other way around?

JanWielemaker commented 4 years ago

Like 2r3

That would surely work. I wonder how bad it is from a performance perspective. We could consider hexadecimal notation as well, e.g., 0x2r3. This isn't yet supported (it is for big integers, but not for rational) but it does require significantly less work to read.

What about the other direction (Prolog --> Java)?

TAG_INTEGER be renamed TAG_RATIONAL

That makes sense. The constants are not known externally though, so it is not really an issue.