PoslavskySV/rings

Example how to factor (4*y^2-5*x*y+x^2) ?

axkr opened this issue · 10 comments

axkr commented

Can you provide an example in Java how to factor

(4*y^2-5*x*y+x^2) into (x-4*y)*(x-y) ?

I've used ring Frac(Z[x, y]).

Can you also provide an example factoring for GaussianRationals?

For example x^2+1 into (-I+x)*(I+x) with I as imaginary unit.

Hi!

Thanks for writing. You are right, that was a bug in the first case related to the irreducibility test of bivariate polynomials based on Newton polytops (in your example the polygon was singular - just a line). I fixed it in the develop - let me know if you need a release.

To factor this poly you can do e.g.:

implicit val ring = MultivariateRing(Q, Array("x", "y"))
val factors = ring.factor(ring("4*y^2-5*x*y+x^2")) 
println(ring.stringify(factors))

For GaussianRationals you can do e.g.:

// by default imaginary unit will be denoted as "i" at stdout
implicit val ring = UnivariateRing(GaussianRationals, "x")
val poly = ring("x^2+1")
val factors = ring.factor(poly)
println(ring.stringify(factors))

For other algebraic number fields you can do e.g.:

// define minimal polynomial which generate number filed
val minimalPoly = UnivariateRing(Q, "x")("x^2 - 2")
// Field of rational numbers extended with square root of 2 (denoted as "sqrt2")
val numberField = AlgebraicNumberField(minimalPoly, "sqrt2")
// polynomial ring
implicit val ring = UnivariateRing(numberField, "x")
val poly = ring("x^2-2")
val factors = ring.factor(poly)
println(ring.stringify(factors))

Rings support multiple field extensions and factorization of multivariate polynomials as well. You can find more examples of number fields here: https://rings.readthedocs.io/en/latest/guide.html#algebraic-number-fields-and-field-extensions

There you can also find Java examples. Let me know if I can help you further.

axkr commented

Yes would be nice if you can create a new Maven release.

@axkr Yep, just released v2.5.4)

axkr commented

I must admit I'm using your experimental implementation from rings25 branch in the current master branch:

but didn't know anymore the idea for converting to GaussianRationals polynomials?

diff --git a/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/Algebra.java b/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/Algebra.java
index 51b2e1d..9286572 100644
--- a/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/Algebra.java
+++ b/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/Algebra.java
@@ -41,4 +41,5 @@
 import org.matheclipse.core.convert.JASModInteger;
 import org.matheclipse.core.convert.VariablesSet;
+import org.matheclipse.core.convert.rings.SymjaRings;
 import org.matheclipse.core.eval.EvalAttributes;
 import org.matheclipse.core.eval.EvalEngine;
@@ -5446,12 +5447,9 @@
 				GenPolynomial<Complex<BigRational>> polyRat = jas.expr2JAS(expr, numeric2Rational);
 				return engine.evaluate(factorComplex((IAST) expr, polyRat, jas, head, cfac));
-			} else {
-				JASConvert<BigRational> jas = new JASConvert<BigRational>(varList, BigRational.ZERO);
-				GenPolynomial<BigRational> polyRat = jas.expr2JAS(expr, numeric2Rational);
-				return factorRational(polyRat, jas, head);
-				// IExpr temp = SymjaRings.FactorOverQ((IAST) expr, false);
-				// if (temp != null && temp.isPresent()) {
-				// return temp;
-				// }
+			} else { 
+				IExpr temp = SymjaRings.FactorOverQ((IAST) expr, false);
+				if (temp != null && temp.isPresent()) {
+					return temp;
+				}
 			}
 		} catch (RuntimeException rex) {

In SymjaRings already contains methods for working in extension fields. So, to factor with GaussianRationals you can just use SymjaRings.FactorOverExtension(...) etc. You can find real Symja examples in tests:

https://github.com/axkr/symja_android_library/blob/rings25/symja_android_library/matheclipse-core/src/test/java/org/matheclipse/core/convert/rings/SymjaRingsTest.java

All SymjaRings methods for extensions will capture GaussianRationals automatically (I) is you pass automatic = true, but for other extensions, you have to provide generating elements explicitly (see e.g. SymjaRingsTest.test4).

So in you Algebra class you can just call

IExpr factorization =   SymjaRings.FactorOverExtension(IExpr expression , IExp[] extensions, boolean automatic, boolean factorSquareFree)

Array extensions may be empty (equivalent to just Extension->Automatic). Specify factorSquareFree=true if you need just a square free decomposition. Specify automatic = true if you want that algebraic expressions meet in expression captured automatically. Always specify extensions = { IExpr.ImaginatyUnit } if you want to force GaussianRationals.

All conversions are already implemented in SymjaRings.FactorOverExtension.

axkr commented

Factoring x-I*y gives -I*(I*x+y).

Could you add an option to avoid -I,I,-1,1 as factors

I'm afraid it is not as easy as might look. Monicization is a necessary step for all factoring algorithms; it is used in dozens of places, so it would be quite tedious to propagate such option in Rings (if that makes sense at all). However, if you need to keep lead term unfactored, you can easily perform check in Symja, and e.g. add after this line:

if (factors.size() == 1)
    factors = FactorDecomposition.of(ring, rExpr);
axkr commented

Created a new branch rings254

and implemented FactorDecomposition usage:

The following code will not work:

(factors.unit.equals(F.CN1) || //
    factors.unit.equals(F.CNI) || //
    factors.unit.equals(F.CI))) {

equals will always return false, because objects have different types (unit is of Rings type R and F.CNI is of type IExpr).

Probably it is better to check the resulting IASTAppendable:

if (result.size() == 2) {
    if (result.get(0).equals(F.CN1) || //
        result.get(0).equals(F.CNI) || //
	result.get(0).equals(F.CI)))
        return expr;
}