phylanx icon indicating copy to clipboard operation
phylanx copied to clipboard

The direction of fold in `fold_left` and `fold_right` having a specified dtype

Open taless474 opened this issue 6 years ago • 1 comments

The following test aims to make sure that we walk the array from right to left and checks it in the following way: multiplying left to right 1e-40 cannot be held into a float32 so it causes an underflow while from right to left we have no such problem and the result is larger.

import numpy as np
from phylanx import Phylanx, PhylanxSession, execution_tree

PhylanxSession.init(1)

def variable(value, dtype=None, name=None, constraint=None):
	if dtype is None:
		dtype = "float32"
	if constraint is not None:
		raise TypeError("Constraint is the projection function to be "
						"applied to the variable after an "
                                                "optimizer update")
	from phylanx.ast.physl import PhySL
	if isinstance(value, PhySL.eval_wrapper):
		return execution_tree.variable(value.code(), dtype)
	if isinstance(value, execution_tree.variable):
		return value
	return execution_tree.variable(value, dtype=dtype, name=name)
	
def eval(func):
    return func.eval()
	
def dtype(x):
	from phylanx.ast.physl import PhySL
	if isinstance(x, PhySL.eval_wrapper):
		return execution_tree.variable(x.code(), dtype).dtype
	if isinstance(x, execution_tree.variable):
		return x.dtype
	return execution_tree.variable(x, dtype).dtype
	
@Phylanx
def foldl_eager(fn, elems, initializer, name):
	return fold_left(fn, initializer, elems)

def foldl(fn, elems, initializer=None, name=None):
	return foldl_eager.lazy(fn, elems, initializer, name)
	
@Phylanx
def foldr_eager(fn, elems, initializer, name):
	return fold_right(fn, initializer, elems)

def foldr(fn, elems, initializer=None, name=None):
	return foldr_eager.lazy(fn, elems, initializer, name)


def test_fold():
	x = np.array([1e-20, 1e-20, 10, 10, 10], dtype=np.float32)
	vx = variable(x)
	print(dtype(vx)) # prints float32
	p1 = eval(foldl(lambda a, b: a * b, vx))
	p2 = eval(foldr(lambda a, b: a * b, vx))

	assert p1 < p2
	assert 9e-38 < p2 <= 1e-37
	
test_fold()

It raises an assertion error. Here, we get the same value for p1 and p2.

taless474 avatar Apr 16 '19 02:04 taless474

@taless474 we see this as our computations are always done in float64. I have no solution to this except to really support float32 in the backend.

hkaiser avatar Apr 16 '19 12:04 hkaiser