Failing to serialize Rational
tueda opened this issue · 4 comments
Though Rational
is Serializable
, when I try to serialize a Rational
object with Rings v2.5.2, it fails:
import java.io.*
import cc.redberry.rings.*
import cc.redberry.rings.poly.multivar.*
var ring = Rings.MultivariateRing(3, Rings.Z)
var field = Rings.Frac(ring)
var p = MultivariatePolynomial.parse("1+x+y", "x", "y")
var q = MultivariatePolynomial.parse("1+x-y", "x", "y")
var r = field.mk(p, q)
var bstream = new ByteArrayOutputStream()
var ostream = new ObjectOutputStream(bstream)
ostream.writeObject(r)
jshell> ostream.writeObject(r)
| Exception java.io.NotSerializableException: cc.redberry.rings.Rational$$Lambda$18/0x000000084007f440
| at ObjectOutputStream.writeObject0 (ObjectOutputStream.java:1185)
| at ObjectOutputStream.defaultWriteFields (ObjectOutputStream.java:1553)
| at ObjectOutputStream.writeSerialData (ObjectOutputStream.java:1510)
| at ObjectOutputStream.writeOrdinaryObject (ObjectOutputStream.java:1433)
| at ObjectOutputStream.writeObject0 (ObjectOutputStream.java:1179)
| at ObjectOutputStream.writeObject (ObjectOutputStream.java:349)
| at (#11:1)
I guess simplicityCriteria
would be not Serializable
and could be transient
...?
@tueda Hi Takahiro! Thanks for reporting this. The bug was already fixed in the develop branch, so now I just made a release (2.5.3) with the fix.
Nevertheless I won't recommend using Java's serialization in Rings: it is much slower than e.g. encoding/decoding expressions from strings. So, for serialization I would recommend using Rings's Coder
(see this):
import java.io.*
import cc.redberry.rings.*
import cc.redberry.rings.poly.multivar.*
var ring = Rings.MultivariateRing(3, Rings.Z)
var field = Rings.Frac(ring)
var p = MultivariatePolynomial.parse("1+x+y", "x", "y")
var q = MultivariatePolynomial.parse("1+x-y", "x", "y")
var r = field.mk(p, q)
var mCoder = Coder.mkMultivariateCoder(ring, "x", "y")
Coder<Rational<MultivariatePolynomial<BigInteger>>, ?, ?> coder = Coder.mkRationalsCoder(field, mCoder)
coder.encode(r) // to string
assert r.equals(coder.decode(coder.encode(r)))
Thanks for the prompt response!
It seems that Rings.Z
must be a singleton (or all instances of Integers
should be "equal") and the serialization breaks it, so if I try to, for example, add an object obtained by deserialization and a newly created object, then easily get
import cc.redberry.rings.*
import cc.redberry.rings.poly.multivar.*
var ring = Rings.MultivariateRing(2, Rings.Z)
var field = Rings.Frac(ring)
var p = MultivariatePolynomial.parse("1+x+y", "x", "y")
var q = MultivariatePolynomial.parse("1+x-y", "x", "y")
var r = field.mk(p, q)
var bstream1 = new ByteArrayOutputStream()
var ostream1 = new ObjectOutputStream(bstream1)
ostream1.writeObject(r)
ostream1.close()
var data = bstream1.toByteArray()
var bstream2 = new ByteArrayInputStream(data)
var ostream2 = new ObjectInputStream(bstream2)
var t = (Rational<MultivariatePolynomial<cc.redberry.rings.bigint.BigInteger>>) ostream2.readObject()
t.ring.equals(r.ring) // gives false
t.add(r)
jshell> t.add(r)
| Exception java.lang.IllegalArgumentException: Mixing polynomials over different coefficient rings: Z and Z
| at IPolynomial.assertSameCoefficientRingWith (IPolynomial.java:36)
| at AMultivariatePolynomial.add (AMultivariatePolynomial.java:1190)
| at AMultivariatePolynomial.add (AMultivariatePolynomial.java:76)
| at APolynomialRing.add (APolynomialRing.java:38)
| at APolynomialRing.add (APolynomialRing.java:12)
| at Rational.add (Rational.java:588)
| at (#17:1)
But if encoding/decoding expressions via string is faster than Java's serialization, then I can use it. I haven't tried for such performance comparison, it's worth information.
(Though encoding/decoding via string is better, should I keep this issue open for the Rings.Z
serialization problem?)
Yes, you are right, it was a problem with Rings.Z
--- I just fixed it in develop
. In any case I recommend you to use Coder
. Please, let me know if I can help!
The Corder
works very well, regardless of the Rings.Z
problem. Just for information, in jshell:
import cc.redberry.rings.*
import cc.redberry.rings.io.*
import cc.redberry.rings.poly.multivar.*
var ring = Rings.MultivariateRing(2, Rings.Z)
var field = Rings.Frac(ring)
var p = MultivariatePolynomial.parse("1+x+y", "x", "y")
var q = MultivariatePolynomial.parse("1+x-y", "x", "y")
var r = field.mk(p, q)
var mCoder = Coder.mkMultivariateCoder(ring, "x", "y")
var coder = Coder.mkRationalsCoder(field, mCoder)
var s = coder.encode(r)
var t = coder.decode(s)
r.equals(t) // gives true
r.add(t) // works well
I have checked the develop
branch, and confirmed the Rings.Z
problem was fixed: the code in the previous post now works. Thanks again!