Closed crowlogic closed 3 months ago
The issue appears to be in how the expression "1/2-x/2" is being parsed and compiled into a RationalNullaryFunction. The current implementation is treating the entire expression as a Real number operation rather than a RationalFunction operation. Let's modify the code generation to correctly handle rational functions.
Here's how we can fix this:
First, we need to ensure that the expression parser recognizes "x" as the indeterminate variable for a RationalFunction.
We need to modify the code generation to use RationalFunction operations instead of Real operations.
We should use Integer operations where possible to maintain exact rational arithmetic.
That's an insightful approach. Your idea of modifying the literal constant handling to emit a fraction by default for decimal inputs is indeed more elegant and flexible. This strategy would provide several advantages:
Precision preservation: By representing decimals as fractions from the start, you maintain exact precision throughout your computations until explicitly converted.
Flexibility: Different parts of your system can then decide how to interpret or convert this fraction based on their specific needs.
Consistency: It provides a uniform representation for decimal inputs across your system.
Performance: It potentially reduces the need for repeated conversions in different parts of your code.
Here's a conceptual outline of how this might work:
arb_t
, fmpz_poly_q_t
, etc.) is requested:
This approach aligns well with the principle of keeping data in its most precise form until a specific representation is required. It also allows for more efficient handling in parts of your system that can work directly with fractions.
For implementation, you might consider using a structure like this:
typedef struct {
fmpz_t num;
fmpz_t den;
} fraction_t;
typedef struct {
enum { INT, FRACTION, ... } type;
union {
fmpz_t int_value;
fraction_t frac_value;
// other types...
} value;
} constant_t;
Then, your parsing function would populate this structure appropriately, and your node interface would work with this constant_t
type, converting as needed when a specific type is requested.
Does this align with what you had in mind? Would you like to discuss any specific aspects of implementing this approach?
Node: Default to RationalFunction instead of RationalPolynomial when the node is not the result node.
Node by generating IntegerPolynomials, if possible. Whenever we encounter a polynomial that's all integers, let's submit an IntegerPolynomial instead of a RealPolynomial.
And then specialize the division of IntegerPolynomials to the default output type of RationalFunction, just in the same way that divisions of pairs of integers specialize to the output of Fractions.
purge the complex quasi polynomial thing too
==== pFq({Minus2,3_5,1},{2,4},1Over2MinusxOver2).java ==== import arb.ComplexQuasiPolynomial; import arb.Fraction; import arb.Initializable; import arb.Integer; import arb.RationalFunction; import arb.RationalNullaryFunction; import arb.Real; import arb.Typesettable;
public class pFq({Minus2,3_5,1},{2,4},1Over2MinusxOver2) implements RationalNullaryFunction, Typesettable, AutoCloseable, Initializable { public boolean isInitialized; Integer cℤ1 = new Integer("2"); Integer cℤ4 = new Integer("4"); Integer cℤ3 = new Integer("1"); Real cℝ2 = new Real("3.5", 128); public Fraction vf1 = new Fraction(); public Fraction vf2 = new Fraction(); public Fraction f1 = new Fraction(); public Fraction f2 = new Fraction(); public Fraction f3 = new Fraction(); public Fraction f4 = new Fraction(); public Fraction f5 = new Fraction();
@Override
public Class
@Override public RationalFunction evaluate(Object in, int order, int bits, RationalFunction result) { if (!this.isInitialized) { this.initialize(); }
return new Object(
this.vf1.set(new Fraction[]{this.cℤ1.neg(this.f1), this.f2.set(this.cℝ2), this.f3.set(this.cℤ3)}),
this.vf2.set(new Fraction[]{this.f4.set(this.cℤ1), this.f5.set(this.cℤ4)}),
ComplexQuasiPolynomial.parse("(1/2)-(x/2)")
)
.evaluate(null, 1, bits, result);
}
@Override public void initialize() { if (this.isInitialized) { throw new AssertionError("Already initialized"); } else { this.isInitialized = true; } }
@Override public void close() { this.cℤ1.close(); this.cℤ4.close(); this.cℤ3.close(); this.cℝ2.close(); this.vf1.close(); this.vf2.close(); this.f1.close(); this.f2.close(); this.f3.close(); this.f4.close(); this.f5.close(); }
@Override public String toString() { return "pFq([-2,3.5,1],[2,4],1/2-x/2)"; }
@Override public String typeset() { return "${_3F_2}\left(\left[-2,3.5,1\right], \left[2,4\right] ; \left(\frac{1}{2}-\frac{x}{2}\right)\right)"; } }
To modify the code so that it generates a Fraction instead of a Real for expressions like "1/2", we need to make changes in a few key areas of the Expression compiler. Here's an approach to achieve this:
In the
LiteralConstant
class:In the
Expression
class:evaluateNumber()
method to handle fraction literals.In the
Division
class:Here are the specific changes:
LiteralConstant.java
:Expression.java
:Division.java
:These changes will:
You'll need to ensure that your
Fraction
class is properly implemented and that the rest of your code can handle Fraction objects where it previously expected Real objects.Also, you might need to adjust other parts of your code to handle Fractions in arithmetic operations, comparisons, and conversions to ensure consistency throughout your expression evaluation system.