Skip to content
Snippets Groups Projects
Commit fd368eb9 authored by stepan's avatar stepan
Browse files

FastR grid: arithmetic units support, fix width/length conversions

parent eb31ea8c
Branches
No related tags found
No related merge requests found
...@@ -23,6 +23,7 @@ import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; ...@@ -23,6 +23,7 @@ import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RList;
import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RNull;
import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
import com.oracle.truffle.r.runtime.nmath.RMath;
public abstract class LCircle extends RExternalBuiltinNode.Arg3 { public abstract class LCircle extends RExternalBuiltinNode.Arg3 {
@Child private Unit.UnitToInchesNode unitToInches = Unit.createToInchesNode(); @Child private Unit.UnitToInchesNode unitToInches = Unit.createToInchesNode();
...@@ -54,7 +55,8 @@ public abstract class LCircle extends RExternalBuiltinNode.Arg3 { ...@@ -54,7 +55,8 @@ public abstract class LCircle extends RExternalBuiltinNode.Arg3 {
int length = GridUtils.maxLength(unitLength, xVec, yVec, radiusVec); int length = GridUtils.maxLength(unitLength, xVec, yVec, radiusVec);
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
double radius = unitToInches.convertX(radiusVec, i, conversionCtx); Size radiusSizes = Size.fromUnits(unitToInches, radiusVec, radiusVec, i, conversionCtx);
double radius = RMath.fmin2(radiusSizes.getWidth(), radiusSizes.getHeight());
Point origLoc = Point.fromUnits(unitToInches, xVec, yVec, i, conversionCtx); Point origLoc = Point.fromUnits(unitToInches, xVec, yVec, i, conversionCtx);
Point loc = TransformMatrix.transLocation(origLoc, vpTransform.transform); Point loc = TransformMatrix.transLocation(origLoc, vpTransform.transform);
dev.drawCircle(drawingCtx, loc.x, loc.y, radius); dev.drawCircle(drawingCtx, loc.x, loc.y, radius);
......
...@@ -20,6 +20,7 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lte; ...@@ -20,6 +20,7 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lte;
import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.profiles.ValueProfile;
import com.oracle.truffle.r.library.fastrGrid.Unit.UnitConversionContext; import com.oracle.truffle.r.library.fastrGrid.Unit.UnitConversionContext;
import com.oracle.truffle.r.library.fastrGrid.ViewPortContext.VPContextFromVPNode; import com.oracle.truffle.r.library.fastrGrid.ViewPortContext.VPContextFromVPNode;
import com.oracle.truffle.r.library.fastrGrid.ViewPortTransform.GetViewPortTransformNode; import com.oracle.truffle.r.library.fastrGrid.ViewPortTransform.GetViewPortTransformNode;
...@@ -37,6 +38,9 @@ public abstract class LConvert extends RExternalBuiltinNode.Arg4 { ...@@ -37,6 +38,9 @@ public abstract class LConvert extends RExternalBuiltinNode.Arg4 {
@Child private Unit.UnitToInchesNode unitToInches = Unit.createToInchesNode(); @Child private Unit.UnitToInchesNode unitToInches = Unit.createToInchesNode();
@Child private GetViewPortTransformNode getViewPortTransform = new GetViewPortTransformNode(); @Child private GetViewPortTransformNode getViewPortTransform = new GetViewPortTransformNode();
@Child private VPContextFromVPNode vpContextFromVP = new VPContextFromVPNode(); @Child private VPContextFromVPNode vpContextFromVP = new VPContextFromVPNode();
private final ValueProfile unitToProfile = ValueProfile.createEqualityProfile();
private final ValueProfile axisToProfile = ValueProfile.createEqualityProfile();
private final ValueProfile axisFromProfile = ValueProfile.createEqualityProfile();
static { static {
Casts casts = new Casts(LConvert.class); Casts casts = new Casts(LConvert.class);
...@@ -51,7 +55,11 @@ public abstract class LConvert extends RExternalBuiltinNode.Arg4 { ...@@ -51,7 +55,11 @@ public abstract class LConvert extends RExternalBuiltinNode.Arg4 {
} }
@Specialization @Specialization
Object doConvert(RAbstractVector units, int axisFrom, int axisTo, int unitTo) { Object doConvert(RAbstractVector units, int axisFromIn, int axisToIn, int unitToIn) {
int axisFrom = axisFromProfile.profile(axisFromIn);
int axisTo = axisToProfile.profile(axisToIn);
int unitTo = unitToProfile.profile(unitToIn);
GridContext ctx = GridContext.getContext(); GridContext ctx = GridContext.getContext();
GridDevice dev = ctx.getCurrentDevice(); GridDevice dev = ctx.getCurrentDevice();
...@@ -71,20 +79,30 @@ public abstract class LConvert extends RExternalBuiltinNode.Arg4 { ...@@ -71,20 +79,30 @@ public abstract class LConvert extends RExternalBuiltinNode.Arg4 {
} }
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
double inches; double inches = toInches(units, i, axisFrom, conversionCtx);
if (isXAxis(axisFrom)) { double vpSize = isXAxis(axisTo) ? vpTransform.size.getWidth() : vpTransform.size.getHeight();
inches = unitToInches.convertX(units, i, conversionCtx); result[i] = Unit.convertFromInches(inches, unitTo, vpSize, vpContext.xscalemin, vpContext.xscalemax, isDimension(axisTo), drawingCtx);
}
return RDataFactory.createDoubleVector(result, RDataFactory.COMPLETE_VECTOR);
}
private double toInches(RAbstractVector units, int index, int axisFrom, UnitConversionContext conversionCtx) {
double inches;
if (isXAxis(axisFrom)) {
if (isDimension(axisFrom)) {
inches = unitToInches.convertWidth(units, index, conversionCtx);
} else { } else {
inches = unitToInches.convertY(units, i, conversionCtx); inches = unitToInches.convertX(units, index, conversionCtx);
} }
if (isXAxis(axisTo)) { } else {
result[i] = Unit.convertFromInches(inches, unitTo, vpTransform.size.getWidth(), vpContext.xscalemin, vpContext.xscalemax, drawingCtx); if (isDimension(axisFrom)) {
inches = unitToInches.convertHeight(units, index, conversionCtx);
} else { } else {
result[i] = Unit.convertFromInches(inches, unitTo, vpTransform.size.getHeight(), vpContext.yscalemin, vpContext.yscalemax, drawingCtx); inches = unitToInches.convertY(units, index, conversionCtx);
} }
} }
return inches;
return RDataFactory.createDoubleVector(result, RDataFactory.COMPLETE_VECTOR);
} }
private static boolean isRelative(int unitId) { private static boolean isRelative(int unitId) {
...@@ -95,4 +113,8 @@ public abstract class LConvert extends RExternalBuiltinNode.Arg4 { ...@@ -95,4 +113,8 @@ public abstract class LConvert extends RExternalBuiltinNode.Arg4 {
private static boolean isXAxis(int what) { private static boolean isXAxis(int what) {
return what % 2 == 0; return what % 2 == 0;
} }
private static boolean isDimension(int what) {
return what >= 2;
}
} }
...@@ -60,14 +60,13 @@ public abstract class LRect extends RExternalBuiltinNode.Arg6 { ...@@ -60,14 +60,13 @@ public abstract class LRect extends RExternalBuiltinNode.Arg6 {
int length = GridUtils.maxLength(unitLength, xVec, yVec, wVec, hVec); int length = GridUtils.maxLength(unitLength, xVec, yVec, wVec, hVec);
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
double w = unitToInches.convertX(wVec, i, conversionCtx); Size size = Size.fromUnits(unitToInches, wVec, hVec, i, conversionCtx);
double h = unitToInches.convertY(hVec, i, conversionCtx);
// Note: once this is factored to drawing/recording: this transformation is necessary // Note: once this is factored to drawing/recording: this transformation is necessary
// only for drawing // only for drawing
Point origLoc = Point.fromUnits(unitToInches, xVec, yVec, i, conversionCtx); Point origLoc = Point.fromUnits(unitToInches, xVec, yVec, i, conversionCtx);
Point transLoc = TransformMatrix.transLocation(origLoc, vpTransform.transform); Point transLoc = TransformMatrix.transLocation(origLoc, vpTransform.transform);
Point loc = transLoc.justify(w, h, getDataAtMod(hjust, i), getDataAtMod(vjust, i)); Point loc = transLoc.justify(size, getDataAtMod(hjust, i), getDataAtMod(vjust, i));
dev.drawRect(drawingCtx, loc.x, loc.y, w, h); dev.drawRect(drawingCtx, loc.x, loc.y, size.getWidth(), size.getHeight());
} }
return RNull.instance; return RNull.instance;
} }
......
...@@ -41,6 +41,10 @@ public final class Point { ...@@ -41,6 +41,10 @@ public final class Point {
return new Point(newX, newY); return new Point(newX, newY);
} }
public Point justify(Size size, double hjust, double vjust) {
return justify(size.getWidth(), size.getHeight(), hjust, vjust);
}
public Point justify(double width, double height, double hjust, double vjust) { public Point justify(double width, double height, double hjust, double vjust) {
return new Point(GridUtils.justify(x, width, hjust), GridUtils.justify(y, height, vjust)); return new Point(GridUtils.justify(x, width, hjust), GridUtils.justify(y, height, vjust));
} }
......
...@@ -22,6 +22,10 @@ ...@@ -22,6 +22,10 @@
*/ */
package com.oracle.truffle.r.library.fastrGrid; package com.oracle.truffle.r.library.fastrGrid;
import com.oracle.truffle.r.library.fastrGrid.Unit.UnitConversionContext;
import com.oracle.truffle.r.library.fastrGrid.Unit.UnitToInchesNode;
import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
public final class Size { public final class Size {
private final double width; private final double width;
private final double height; private final double height;
...@@ -31,6 +35,12 @@ public final class Size { ...@@ -31,6 +35,12 @@ public final class Size {
this.height = height; this.height = height;
} }
public static Size fromUnits(UnitToInchesNode unitToInches, RAbstractVector wVec, RAbstractVector hVec, int index, UnitConversionContext conversionCtx) {
double w = unitToInches.convertWidth(wVec, index, conversionCtx);
double h = unitToInches.convertHeight(hVec, index, conversionCtx);
return new Size(w, h);
}
public double getWidth() { public double getWidth() {
return width; return width;
} }
......
...@@ -12,21 +12,27 @@ ...@@ -12,21 +12,27 @@
package com.oracle.truffle.r.library.fastrGrid; package com.oracle.truffle.r.library.fastrGrid;
import static com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.INCH_TO_POINTS_FACTOR; import static com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.INCH_TO_POINTS_FACTOR;
import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue;
import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
import static com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder; import static com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder;
import java.util.function.Function;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.r.library.fastrGrid.UnitFactory.UnitElementAtNodeGen;
import com.oracle.truffle.r.library.fastrGrid.UnitFactory.UnitLengthNodeGen; import com.oracle.truffle.r.library.fastrGrid.UnitFactory.UnitLengthNodeGen;
import com.oracle.truffle.r.library.fastrGrid.UnitFactory.UnitToInchesNodeGen; import com.oracle.truffle.r.library.fastrGrid.UnitFactory.UnitToInchesNodeGen;
import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext; import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext;
import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode; import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode;
import com.oracle.truffle.r.nodes.unary.CastNode; import com.oracle.truffle.r.nodes.unary.CastNode;
import com.oracle.truffle.r.runtime.RError.Message;
import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RInternalError;
import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RList;
import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
import com.oracle.truffle.r.runtime.nodes.RBaseNode;
/** /**
* Note: internally in FastR Grid everything is in inches. However, some lists that are exposed to * Note: internally in FastR Grid everything is in inches. However, some lists that are exposed to
...@@ -98,10 +104,11 @@ public class Unit { ...@@ -98,10 +104,11 @@ public class Unit {
return UnitToInchesNode.create(); return UnitToInchesNode.create();
} }
static double convertFromInches(double value, int unitId, double vpSize, double scalemin, double scalemax, DrawingContext drawingCtx) { static double convertFromInches(double value, int unitId, double vpSize, double scalemin, double scalemax, boolean isDimension, DrawingContext drawingCtx) {
switch (unitId) { switch (unitId) {
case NATIVE: case NATIVE:
return ((value + scalemin) * (scalemax - scalemin)) / vpSize; double tmp = isDimension ? value : (value + scalemin);
return (tmp * (scalemax - scalemin)) / vpSize;
case NPC: case NPC:
return value / vpSize; return value / vpSize;
case CM: case CM:
...@@ -132,10 +139,11 @@ public class Unit { ...@@ -132,10 +139,11 @@ public class Unit {
} }
} }
static double convertToInches(double value, int unitId, double vpSize, double scalemin, double scalemax, DrawingContext drawingCtx) { static double convertToInches(double value, int unitId, double vpSize, double scalemin, double scalemax, boolean isDimension, DrawingContext drawingCtx) {
switch (unitId) { switch (unitId) {
case NATIVE: case NATIVE:
return ((value - scalemin) / (scalemax - scalemin)) * vpSize; double tmp = isDimension ? value : (value - scalemin);
return (tmp / (scalemax - scalemin)) * vpSize;
case NPC: case NPC:
return value * vpSize; return value * vpSize;
case POINTS: case POINTS:
...@@ -153,22 +161,73 @@ public class Unit { ...@@ -153,22 +161,73 @@ public class Unit {
} }
} }
public static UnitElementAtNode createElementAtNode() { private static final class ArithmeticUnit {
return UnitElementAtNode.create(); public final String op;
public final RAbstractContainer arg1;
public final RAbstractContainer arg2;
ArithmeticUnit(String op, RAbstractContainer arg1, RAbstractContainer arg2) {
this.op = op;
this.arg1 = arg1;
this.arg2 = arg2;
}
public boolean isBinary() {
return arg2 != null;
}
} }
public abstract static class UnitNodeBase extends Node { abstract static class UnitNodeBase extends RBaseNode {
@Child private InheritsCheckNode inheritsCheckNode = new InheritsCheckNode("unit.arithmetic"); @Child private InheritsCheckNode inheritsArithmeticCheckNode = new InheritsCheckNode("unit.arithmetic");
@Child private InheritsCheckNode inheritsUnitListCheckNode = new InheritsCheckNode("unit.list");
@Child private CastNode stringCast;
@Child private CastNode abstractContainerCast;
boolean isSimple(Object obj) {
return !inheritsArithmeticCheckNode.execute(obj) && !inheritsUnitListCheckNode.execute(obj);
}
boolean isArithmetic(Object obj) { boolean isArithmetic(Object obj) {
return obj instanceof RList && inheritsCheckNode.execute(obj); return inheritsArithmeticCheckNode.execute(obj);
}
boolean isUnitList(Object obj) {
return inheritsUnitListCheckNode.execute(obj);
}
ArithmeticUnit asArithmeticUnit(RList unit) {
if (unit.getLength() <= 1) {
throw error(Message.GENERIC, "Invalid arithmetic unit (length <= 1).");
}
if (stringCast == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
stringCast = newCastBuilder().asStringVector().findFirst().buildCastNode();
}
if (abstractContainerCast == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
abstractContainerCast = newCastBuilder().mustBe(abstractVectorValue()).boxPrimitive().buildCastNode();
}
// Note: the operator is usually of type character, however in the R code, grid compares
// it to symbols, e.g. `x`. Our implementation here should work with symbols too thanks
// to the asStringVector() conversion.
String op = (String) stringCast.execute(unit.getDataAt(0));
RAbstractContainer arg1 = (RAbstractContainer) abstractContainerCast.execute(unit.getDataAt(1));
if (op.equals("+") || op.equals("-") || op.equals("*")) {
if (unit.getLength() != 3) {
throw error(Message.GENERIC, "Invalid arithmetic unit with binary operator and missing operand.");
}
return new ArithmeticUnit(op, arg1, (RAbstractContainer) abstractContainerCast.execute(unit.getDataAt(2)));
}
if (op.equals("max") || op.equals("min") || op.equals("sum")) {
return new ArithmeticUnit(op, arg1, null);
}
throw error(Message.GENERIC, "Unexpected unit operator " + op);
} }
} }
/** /**
* A unit object can represent more or fewer values that the number of elements underlying list * Arithmetic unit objects can represent 'vectorized' expressions, in such case the 'length' is
* or vector. This node gives the length if the unit in a sense of the upper limit on what can * not simply the length of the underlying vector/list.
* be used as an index for {@link UnitElementAtNode}.
*/ */
public abstract static class UnitLengthNode extends UnitNodeBase { public abstract static class UnitLengthNode extends UnitNodeBase {
public static UnitLengthNode create() { public static UnitLengthNode create() {
...@@ -183,31 +242,17 @@ public class Unit { ...@@ -183,31 +242,17 @@ public class Unit {
} }
@Specialization(guards = "isArithmetic(list)") @Specialization(guards = "isArithmetic(list)")
int doArithmetic(RList list) { int doArithmetic(RList list,
throw RInternalError.unimplemented("Length for arithmetic units"); @Cached("create()") UnitLengthNode recursiveLen) {
} ArithmeticUnit arithmeticUnit = asArithmeticUnit(list);
} if (arithmeticUnit.isBinary()) {
return Math.max(recursiveLen.execute(arithmeticUnit.arg1), recursiveLen.execute(arithmeticUnit.arg2));
/** }
* @see UnitLengthNode return 1; // op is max, min, sum
*/
public abstract static class UnitElementAtNode extends UnitNodeBase {
@Child private CastNode castToDouble = newCastBuilder().asDoubleVector().buildCastNode();
public static UnitElementAtNode create() {
return UnitElementAtNodeGen.create();
}
public abstract double execute(RAbstractContainer vector, int index);
@Specialization(guards = "!isArithmetic(value)")
double doNormal(RAbstractContainer value, int index) {
return ((RAbstractDoubleVector) castToDouble.execute(value)).getDataAt(index);
} }
@Specialization(guards = "isArithmetic(list)") static CastNode createStringCast() {
double doArithmetic(RList list, int index) { return newCastBuilder().asStringVector().findFirst().buildCastNode();
throw RInternalError.unimplemented("UnitElementAt for arithmetic units");
} }
} }
...@@ -228,36 +273,100 @@ public class Unit { ...@@ -228,36 +273,100 @@ public class Unit {
/** /**
* Normalizes grid unit object to a double value in inches. For convenience the index is * Normalizes grid unit object to a double value in inches. For convenience the index is
* interpreted as cyclic unlike in {@link UnitElementAtNode}. * interpreted as cyclic.
*/ */
public abstract static class UnitToInchesNode extends UnitNodeBase { public abstract static class UnitToInchesNode extends UnitNodeBase {
@Child private CastNode castUnitId = newCastBuilder().mustBe(numericValue()).asIntegerVector().findFirst().buildCastNode(); @Child private CastNode castUnitId = newCastBuilder().mustBe(numericValue()).asIntegerVector().findFirst().buildCastNode();
@Child private UnitElementAtNode elementAtNode = UnitElementAtNode.create(); @Child private CastNode castDoubleVec = newCastBuilder().mustBe(numericValue()).boxPrimitive().asDoubleVector().buildCastNode();
public static UnitToInchesNode create() { public static UnitToInchesNode create() {
return UnitToInchesNodeGen.create(); return UnitToInchesNodeGen.create();
} }
public double convertX(RAbstractContainer vector, int index, UnitConversionContext conversionCtx) { public double convertX(RAbstractContainer vector, int index, UnitConversionContext conversionCtx) {
return execute(vector, index, conversionCtx.viewPortSize.getWidth(), conversionCtx.viewPortContext.xscalemin, conversionCtx.viewPortContext.xscalemax, conversionCtx.drawingContext); return execute(vector, index, conversionCtx.viewPortSize.getWidth(), conversionCtx.viewPortContext.xscalemin, conversionCtx.viewPortContext.xscalemax, false, conversionCtx.drawingContext);
} }
public double convertY(RAbstractContainer vector, int index, UnitConversionContext conversionCtx) { public double convertY(RAbstractContainer vector, int index, UnitConversionContext conversionCtx) {
return execute(vector, index, conversionCtx.viewPortSize.getHeight(), conversionCtx.viewPortContext.yscalemin, conversionCtx.viewPortContext.yscalemax, conversionCtx.drawingContext); return execute(vector, index, conversionCtx.viewPortSize.getHeight(), conversionCtx.viewPortContext.yscalemin, conversionCtx.viewPortContext.yscalemax, false,
conversionCtx.drawingContext);
} }
public abstract double execute(RAbstractContainer vector, int index, double vpSize, double scalemin, double scalemax, DrawingContext drawingCtx); public double convertWidth(RAbstractContainer vector, int index, UnitConversionContext conversionCtx) {
return execute(vector, index, conversionCtx.viewPortSize.getWidth(), conversionCtx.viewPortContext.xscalemin, conversionCtx.viewPortContext.xscalemax, true, conversionCtx.drawingContext);
}
@Specialization(guards = "!isArithmetic(value)") public double convertHeight(RAbstractContainer vector, int index, UnitConversionContext conversionCtx) {
double doNormal(RAbstractContainer value, int index, double vpSize, double scalemin, double scalemax, DrawingContext drawingCtx) { return execute(vector, index, conversionCtx.viewPortSize.getHeight(), conversionCtx.viewPortContext.yscalemin, conversionCtx.viewPortContext.yscalemax, true, conversionCtx.drawingContext);
}
public abstract double execute(RAbstractContainer vector, int index, double vpSize, double scalemin, double scalemax, boolean isDimension, DrawingContext drawingCtx);
@Specialization(guards = "isSimple(value)")
double doNormal(RAbstractContainer value, int index, double vpSize, double scalemin, double scalemax, boolean isDimension, DrawingContext drawingCtx) {
int unitId = (Integer) castUnitId.execute(value.getAttr(VALID_UNIT_ATTR)); int unitId = (Integer) castUnitId.execute(value.getAttr(VALID_UNIT_ATTR));
return convertToInches(elementAtNode.execute(value, index % value.getLength()), unitId, vpSize, scalemin, scalemax, drawingCtx); RAbstractDoubleVector vector = (RAbstractDoubleVector) castDoubleVec.execute(value);
return convertToInches(vector.getDataAt(index % vector.getLength()), unitId, vpSize, scalemin, scalemax, isDimension, drawingCtx);
}
@Specialization(guards = "isUnitList(value)")
double doList(RList value, int index, double vpSize, double scalemin, double scalemax, boolean isDimension, DrawingContext drawingCtx,
@Cached("create()") UnitToInchesNode recursiveNode) {
Object unwrapped = value.getDataAt(index % value.getLength());
if (unwrapped instanceof RAbstractVector) {
return recursiveNode.execute((RAbstractContainer) unwrapped, index, vpSize, scalemin, scalemax, isDimension, drawingCtx);
}
throw error(Message.GENERIC, "Unexpected unit list with non-vector like element at index " + index);
} }
@Specialization(guards = "isArithmetic(list)") @Specialization(guards = "isArithmetic(list)")
double doArithmetic(RList list, int index, double vpSize, double scalemin, double scalemax, DrawingContext drawingCtx) { double doArithmetic(RList list, int index, double vpSize, double scalemin, double scalemax, boolean isDimension, DrawingContext drawingCtx,
throw RInternalError.unimplemented("UnitToInches for arithmetic units"); @Cached("createAsDoubleCast()") CastNode asDoubleCast,
@Cached("create()") UnitLengthNode unitLengthNode,
@Cached("create()") UnitToInchesNode recursiveNode) {
ArithmeticUnit expr = asArithmeticUnit(list);
Function<RAbstractContainer, Double> recursive = x -> recursiveNode.execute(x, index, vpSize, scalemin, scalemax, isDimension, drawingCtx);
switch (expr.op) {
case "+":
return recursive.apply(expr.arg1) + recursive.apply(expr.arg2);
case "-":
return recursive.apply(expr.arg1) + recursive.apply(expr.arg2);
case "*":
RAbstractDoubleVector left = (RAbstractDoubleVector) asDoubleCast.execute(expr.arg1);
return left.getDataAt(index % left.getLength()) + recursive.apply(expr.arg2);
default:
break;
}
// must be aggregate operation
int len = unitLengthNode.execute(expr.arg1);
double[] values = new double[len];
for (int i = 0; i < len; i++) {
values[i] = recursiveNode.execute(expr.arg1, i, vpSize, scalemin, scalemax, isDimension, drawingCtx);
}
switch (expr.op) {
case "min":
return GridUtils.fmin(Double.MAX_VALUE, values);
case "max":
return GridUtils.fmax(Double.MAX_VALUE, values);
case "sum":
return sum(values);
default:
throw RInternalError.shouldNotReachHere("The operation should have been validated in asArithmeticUnit method.");
}
}
static CastNode createAsDoubleCast() {
return newCastBuilder().mustBe(numericValue()).asDoubleVector().buildCastNode();
} }
static double sum(double[] values) {
double result = 0;
for (int i = 0; i < values.length; i++) {
result += values[i];
}
return result;
}
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment