You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jira@jena.apache.org by "Andy Seaborne (Jira)" <ji...@apache.org> on 2023/09/06 07:35:00 UTC

[jira] [Comment Edited] (JENA-2355) Rule Math Builtins do not support xsd:decimal

    [ https://issues.apache.org/jira/browse/JENA-2355?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17762217#comment-17762217 ] 

Andy Seaborne edited comment on JENA-2355 at 9/6/23 7:34 AM:
-------------------------------------------------------------

The code in Product.java is: 

{code:java}
                if (v1 instanceof Float || v1 instanceof Double 
                ||  v2 instanceof Float || v2 instanceof Double) {
                    sum = Util.makeDoubleNode(nv1.doubleValue() * nv2.doubleValue());
                } else {
                    sum = Util.makeLongNode(nv1.longValue() * nv2.longValue());
                }
                return env.bind(args[2], sum);
{code}

so only Double/Float or Long is supported and then only weakly (as it stands, double+long is long which is wrong).

xsd:decimal could be added. it is  type supported by the {{TypeMapper}}.

There are rules (from XQuery/Xpath Functions and Operators) for the output datatype given different combinations of the 4 inputs types (XSD types integer, decimal, double and float).

The pattern is repeated across jena-core/src/main/java/org/apache/jena/reasoner/rulesys/builtins

Difference.java, Max.java, Min.java, Product.java, Quotient.java, Sum.java




was (Author: andy.seaborne):
Probably because xsd:decimal isn't specifically in the model API.

The code in Product.java is: 

{code:java}
                if (v1 instanceof Float || v1 instanceof Double 
                ||  v2 instanceof Float || v2 instanceof Double) {
                    sum = Util.makeDoubleNode(nv1.doubleValue() * nv2.doubleValue());
                } else {
                    sum = Util.makeLongNode(nv1.longValue() * nv2.longValue());
                }
                return env.bind(args[2], sum);
{code}

so only Double/Float or Long is supported and then only weakly.

xsd:decimal could be added.

The pattern is repeated across jena-core/src/main/java/org/apache/jena/reasoner/rulesys/builtins

Difference.java, Max.java, Min.java, Product.java, Quotient.java, Sum.java



> Rule Math Builtins do not support xsd:decimal
> ---------------------------------------------
>
>                 Key: JENA-2355
>                 URL: https://issues.apache.org/jira/browse/JENA-2355
>             Project: Apache Jena
>          Issue Type: Bug
>          Components: Reasoners
>    Affects Versions: Jena 4.9.0
>            Reporter: Jan Martin Keil
>            Priority: Major
>
> The [builtin|https://jena.apache.org/documentation/inference/#RULEbuiltins] math functions of the rule reasoners do not properly support xsd:decimal. For example, sum(1.1, 1.1) = 2.0 (returned as integer) and quotient(0.1, 0.1) throws "ArithmeticException: / by zero". Here some detailed tests:
> {code:java}
> import org.apache.jena.rdf.model.*;
> import org.apache.jena.reasoner.rulesys.GenericRuleReasoner;
> import org.apache.jena.reasoner.rulesys.Rule;
> import org.apache.jena.riot.Lang;
> import org.apache.jena.riot.RDFParser;
> import org.junit.jupiter.api.Assertions;
> import org.junit.jupiter.api.Test;
> public class ApacheJenaRuleDecimalTest {
>     Property a = ResourceFactory.createProperty("http://example/a");
>     Property b = ResourceFactory.createProperty("http://example/b");
>     Property sum = ResourceFactory.createProperty("http://example/sum");
>     Property difference = ResourceFactory.createProperty("http://example/difference");
>     Property product = ResourceFactory.createProperty("http://example/product");
>     Property quotient = ResourceFactory.createProperty("http://example/quotient");
>     String rules =
>             "(?r <http://example/a> ?a) (?r <http://example/b> ?b) sum(?a, ?b, ?c) -> (?r <http://example/sum> ?c) ." +
>                     "(?r <http://example/a> ?a) (?r <http://example/b> ?b) difference(?a, ?b, ?c) -> (?r <http://example/difference> ?c) ." +
>                     "(?r <http://example/a> ?a) (?r <http://example/b> ?b) product(?a, ?b, ?c) -> (?r <http://example/product> ?c) ." +
>                     "(?r <http://example/a> ?a) (?r <http://example/b> ?b) quotient(?a, ?b, ?c) -> (?r <http://example/quotient> ?c) .";
>     GenericRuleReasoner reasoner = new GenericRuleReasoner(Rule.parseRules(rules));
>     @Test
>     public void test1k0() {
>         Model model = ModelFactory.createDefaultModel();
>         RDFParser.fromString(
>                         "<http://example/decimal-decimal> <http://example/a> 1.0 ; <http://example/b> 1.0 ." +
>                                 "<http://example/double-decimal> <http://example/a> 1.0e0 ; <http://example/b> 1.0 ." +
>                                 "<http://example/decimal-double> <http://example/a> 1.0 ; <http://example/b> 1.0e0 ." +
>                                 "<http://example/double-double> <http://example/a> 1.0e0 ; <http://example/b> 1.0e0 .")
>                 .lang(Lang.TTL).parse(model);
>         System.out.println("Original Statement:");
>         model.listStatements().forEach(s -> System.out.println(s));
>         System.out.println("Deducted Statement:");
>         InfModel infModel = ModelFactory.createInfModel(reasoner, model);
>         infModel.getDeductionsModel().listStatements().forEach(s -> System.out.println(s));
>         infModel.getDeductionsModel().listStatements(null, sum, (RDFNode) null)
>                 .forEach(s -> Assertions.assertEquals(s.getDouble(), 2.0, s.getSubject().getLocalName()));
>         infModel.getDeductionsModel().listStatements(null, difference, (RDFNode) null)
>                 .forEach(s -> Assertions.assertEquals(s.getDouble(), 0.0, s.getSubject().getLocalName()));
>         infModel.getDeductionsModel().listStatements(null, product, (RDFNode) null)
>                 .forEach(s -> Assertions.assertEquals(s.getDouble(), 1.0, s.getSubject().getLocalName()));
>         infModel.getDeductionsModel().listStatements(null, quotient, (RDFNode) null)
>                 .forEach(s -> Assertions.assertEquals(s.getDouble(), 1.0, s.getSubject().getLocalName()));
>     }
>     @Test
>     public void test1k1() {
>         Model model = ModelFactory.createDefaultModel();
>         RDFParser.fromString(
>                         "<http://example/decimal-decimal> <http://example/a> 1.1 ; <http://example/b> 1.1 ." +
>                                 "<http://example/double-decimal> <http://example/a> 1.1e0 ; <http://example/b> 1.1 ." +
>                                 "<http://example/decimal-double> <http://example/a> 1.1 ; <http://example/b> 1.1e0 ." +
>                                 "<http://example/double-double> <http://example/a> 1.1e0 ; <http://example/b> 1.1e0 .")
>                 .lang(Lang.TTL).parse(model);
>         System.out.println("Original Statement:");
>         model.listStatements().forEach(s -> System.out.println(s));
>         System.out.println("Deducted Statement:");
>         InfModel infModel = ModelFactory.createInfModel(reasoner, model);
>         infModel.getDeductionsModel().listStatements().forEach(s -> System.out.println(s));
>         infModel.getDeductionsModel().listStatements(null, sum, (RDFNode) null)
>                 .forEach(s -> Assertions.assertEquals(s.getDouble(), 2.2, s.getSubject().getLocalName()));
>         infModel.getDeductionsModel().listStatements(null, difference, (RDFNode) null)
>                 .forEach(s -> Assertions.assertEquals(s.getDouble(), 0.0, s.getSubject().getLocalName()));
>         infModel.getDeductionsModel().listStatements(null, product, (RDFNode) null)
>                 .forEach(s -> Assertions.assertEquals(s.getDouble(), 1.21, s.getSubject().getLocalName()));
>         infModel.getDeductionsModel().listStatements(null, quotient, (RDFNode) null)
>                 .forEach(s -> Assertions.assertEquals(s.getDouble(), 1.0, s.getSubject().getLocalName()));
>     }
>     @Test
>     public void test0k1() {
>         Model model = ModelFactory.createDefaultModel();
>         RDFParser.fromString(
>                         "<http://example/decimal-decimal> <http://example/a> 0.1 ; <http://example/b> 0.1 ." +
>                                 "<http://example/double-decimal> <http://example/a> 0.1e0 ; <http://example/b> 0.1 ." +
>                                 "<http://example/decimal-double> <http://example/a> 0.1 ; <http://example/b> 0.1e0 ." +
>                                 "<http://example/double-double> <http://example/a> 0.1e0 ; <http://example/b> 0.1e0 .")
>                 .lang(Lang.TTL).parse(model);
>         System.out.println("Original Statement:");
>         model.listStatements().forEach(s -> System.out.println(s));
>         System.out.println("Deducted Statement:");
>         InfModel infModel = ModelFactory.createInfModel(reasoner, model);
>         infModel.getDeductionsModel().listStatements().forEach(s -> System.out.println(s));
>         infModel.getDeductionsModel().listStatements(null, sum, (RDFNode) null)
>                 .forEach(s -> Assertions.assertEquals(s.getDouble(), 0.2, s.getSubject().getLocalName()));
>         infModel.getDeductionsModel().listStatements(null, difference, (RDFNode) null)
>                 .forEach(s -> Assertions.assertEquals(s.getDouble(), 0.0, s.getSubject().getLocalName()));
>         infModel.getDeductionsModel().listStatements(null, product, (RDFNode) null)
>                 .forEach(s -> Assertions.assertEquals(s.getDouble(), 0.01, s.getSubject().getLocalName()));
>         infModel.getDeductionsModel().listStatements(null, quotient, (RDFNode) null)
>                 .forEach(s -> Assertions.assertEquals(s.getDouble(), 1.0, s.getSubject().getLocalName()));
>     }
> }
>  {code}
>  



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: jira-unsubscribe@jena.apache.org
For additional commands, e-mail: jira-help@jena.apache.org