Skip to content
This repository has been archived by the owner on Jul 17, 2024. It is now read-only.

Commit

Permalink
feat: add support for Decimal and Decimal score types
Browse files Browse the repository at this point in the history
- Decimal maps mostly to BigDecimal, although its floating
  point concepts are ignored (Python does not have an infinite
  precision MathContext, so it acts more like a dynamic range
  floating point with an adjustable precision.
  The precision used is shared in
  a thread local object that can be changed using
  decimal.setcontext.

- Added `str` constructors to `float` and `int`

- Added sanity tests for all variants of penalize/reward/impact
  and score types
  • Loading branch information
Christopher-Chianelli committed Jul 12, 2024
1 parent e1dac95 commit 8ffe5b2
Show file tree
Hide file tree
Showing 31 changed files with 4,090 additions and 90 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ public class PythonClassTranslator {
// $ is illegal in variables/methods in Python
public static final String TYPE_FIELD_NAME = "$TYPE";
public static final String CPYTHON_TYPE_FIELD_NAME = "$CPYTHON_TYPE";
private static final String JAVA_METHOD_PREFIX = "$method$";
private static final String PYTHON_JAVA_TYPE_MAPPING_PREFIX = "$pythonJavaTypeMapping";
public static final String JAVA_METHOD_PREFIX = "$method$";
public static final String PYTHON_JAVA_TYPE_MAPPING_PREFIX = "$pythonJavaTypeMapping";

public record PreparedClassInfo(PythonLikeType type, String className, String classInternalName) {
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ai.timefold.jpyinterpreter.implementors;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.IdentityHashMap;
import java.util.Iterator;
Expand Down Expand Up @@ -31,6 +32,7 @@
import ai.timefold.jpyinterpreter.types.collections.PythonLikeTuple;
import ai.timefold.jpyinterpreter.types.errors.TypeError;
import ai.timefold.jpyinterpreter.types.numeric.PythonBoolean;
import ai.timefold.jpyinterpreter.types.numeric.PythonDecimal;
import ai.timefold.jpyinterpreter.types.numeric.PythonFloat;
import ai.timefold.jpyinterpreter.types.numeric.PythonInteger;
import ai.timefold.jpyinterpreter.types.numeric.PythonNumber;
Expand Down Expand Up @@ -65,76 +67,79 @@ public static PythonLikeObject wrapJavaObject(Object object, Map<Object, PythonL
return existingObject;
}

if (object instanceof OpaqueJavaReference) {
return ((OpaqueJavaReference) object).proxy();
if (object instanceof OpaqueJavaReference opaqueJavaReference) {
return opaqueJavaReference.proxy();
}

if (object instanceof PythonLikeObject) {
if (object instanceof PythonLikeObject instance) {
// Object already a PythonLikeObject; need to do nothing
return (PythonLikeObject) object;
return instance;
}

if (object instanceof Byte || object instanceof Short || object instanceof Integer || object instanceof Long) {
return PythonInteger.valueOf(((Number) object).longValue());
}

if (object instanceof BigInteger) {
return PythonInteger.valueOf((BigInteger) object);
if (object instanceof BigInteger integer) {
return PythonInteger.valueOf(integer);
}

if (object instanceof BigDecimal decimal) {
return new PythonDecimal(decimal);
}

if (object instanceof Float || object instanceof Double) {
return PythonFloat.valueOf(((Number) object).doubleValue());
}

if (object instanceof Boolean) {
return PythonBoolean.valueOf((Boolean) object);
if (object instanceof Boolean booleanValue) {
return PythonBoolean.valueOf(booleanValue);
}

if (object instanceof String) {
return PythonString.valueOf((String) object);
if (object instanceof String string) {
return PythonString.valueOf(string);
}

if (object instanceof Iterator) {
return new DelegatePythonIterator<>((Iterator) object);
if (object instanceof Iterator iterator) {
return new DelegatePythonIterator<>(iterator);
}

if (object instanceof List) {
if (object instanceof List list) {
PythonLikeList out = new PythonLikeList();
createdObjectMap.put(object, out);
for (Object item : (List) object) {
for (Object item : list) {
out.add(wrapJavaObject(item));
}
return out;
}

if (object instanceof Set) {
if (object instanceof Set set) {
PythonLikeSet out = new PythonLikeSet();
createdObjectMap.put(object, out);
for (Object item : (Set) object) {
for (Object item : set) {
out.add(wrapJavaObject(item));
}
return out;
}

if (object instanceof Map) {
if (object instanceof Map map) {
PythonLikeDict out = new PythonLikeDict();
createdObjectMap.put(object, out);
Set<Map.Entry<?, ?>> entrySet = ((Map) object).entrySet();
Set<Map.Entry<?, ?>> entrySet = map.entrySet();
for (Map.Entry<?, ?> entry : entrySet) {
out.put(wrapJavaObject(entry.getKey()), wrapJavaObject(entry.getValue()));
}
return out;
}

if (object instanceof Class) {
Class<?> maybeFunctionClass = (Class<?>) object;
if (object instanceof Class maybeFunctionClass) {
if (Set.of(maybeFunctionClass.getInterfaces()).contains(PythonLikeFunction.class)) {
return new PythonCode((Class<? extends PythonLikeFunction>) maybeFunctionClass);
}
}

if (object instanceof OpaquePythonReference) {
return new PythonObjectWrapper((OpaquePythonReference) object);
if (object instanceof OpaquePythonReference opaquePythonReference) {
return new PythonObjectWrapper(opaquePythonReference);
}

// Default: return a JavaObjectWrapper
Expand All @@ -161,6 +166,10 @@ public static PythonLikeType getPythonLikeType(Class<?> javaClass) {
return BuiltinTypes.INT_TYPE;
}

if (BigDecimal.class.equals(javaClass) || PythonDecimal.class.equals(javaClass)) {
return BuiltinTypes.DECIMAL_TYPE;
}

if (float.class.equals(javaClass) || double.class.equals(javaClass) ||
Float.class.equals(javaClass) || Double.class.equals(javaClass) ||
PythonFloat.class.equals(javaClass)) {
Expand Down Expand Up @@ -273,7 +282,7 @@ public static <T> T convertPythonObjectToJavaType(Class<? extends T> type, Pytho
PythonNumber pythonNumber = (PythonNumber) object;
Number value = pythonNumber.getValue();

if (type.equals(BigInteger.class)) {
if (type.equals(BigInteger.class) || type.equals(BigDecimal.class)) {
return (T) value;
}

Expand Down Expand Up @@ -355,13 +364,23 @@ public static void returnValue(MethodVisitor methodVisitor, MethodDescriptor met
Type.INT_TYPE.equals(returnAsmType) ||
Type.LONG_TYPE.equals(returnAsmType) ||
Type.FLOAT_TYPE.equals(returnAsmType) ||
Type.DOUBLE_TYPE.equals(returnAsmType)) {
Type.DOUBLE_TYPE.equals(returnAsmType) ||
Type.getType(BigInteger.class).equals(returnAsmType) ||
Type.getType(BigDecimal.class).equals(returnAsmType)) {
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(PythonNumber.class));
methodVisitor.visitMethodInsn(Opcodes.INVOKEINTERFACE,
Type.getInternalName(PythonNumber.class),
"getValue",
Type.getMethodDescriptor(Type.getType(Number.class)),
true);

if (Type.getType(BigInteger.class).equals(returnAsmType) ||
Type.getType(BigDecimal.class).equals(returnAsmType)) {
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, returnAsmType.getInternalName());
methodVisitor.visitInsn(Opcodes.ARETURN);
return;
}

String wrapperClassName = null;
String methodName = null;
String methodDescriptor = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import ai.timefold.jpyinterpreter.types.collections.view.DictValueView;
import ai.timefold.jpyinterpreter.types.numeric.PythonBoolean;
import ai.timefold.jpyinterpreter.types.numeric.PythonComplex;
import ai.timefold.jpyinterpreter.types.numeric.PythonDecimal;
import ai.timefold.jpyinterpreter.types.numeric.PythonFloat;
import ai.timefold.jpyinterpreter.types.numeric.PythonInteger;
import ai.timefold.jpyinterpreter.types.numeric.PythonNumber;
Expand Down Expand Up @@ -60,6 +61,7 @@ public class BuiltinTypes {
public static final PythonLikeType BOOLEAN_TYPE = new PythonLikeType("bool", PythonBoolean.class, List.of(INT_TYPE));
public static final PythonLikeType FLOAT_TYPE = new PythonLikeType("float", PythonFloat.class, List.of(NUMBER_TYPE));
public final static PythonLikeType COMPLEX_TYPE = new PythonLikeType("complex", PythonComplex.class, List.of(NUMBER_TYPE));
public final static PythonLikeType DECIMAL_TYPE = new PythonLikeType("Decimal", PythonDecimal.class, List.of(NUMBER_TYPE));

public static final PythonLikeType STRING_TYPE = new PythonLikeType("str", PythonString.class, List.of(BASE_TYPE));
public static final PythonLikeType BYTES_TYPE = new PythonLikeType("bytes", PythonBytes.class, List.of(BASE_TYPE));
Expand Down
Loading

0 comments on commit 8ffe5b2

Please sign in to comment.