mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-09-13 17:25:54 +00:00
Split apart util.value_compare_diff to have better type annotation
This commit is contained in:
+62
-58
@@ -1,4 +1,4 @@
|
||||
import sys
|
||||
from __future__ import annotations
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
@@ -8,7 +8,7 @@ import platform
|
||||
import hashlib
|
||||
import zipfile
|
||||
import subprocess
|
||||
from typing import Tuple, List
|
||||
from typing import Tuple, List, Union
|
||||
from . import png
|
||||
from rdtest.remoteserver import RemoteServer, AndroidRemoteServer
|
||||
|
||||
@@ -290,74 +290,78 @@ def zip_compare(test_file: str, ref_file: str):
|
||||
# Use the 32-bit float epsilon, not sys.float_info.epsilon which is for double floats
|
||||
FLT_EPSILON = 2.0*1.19209290E-07
|
||||
|
||||
# Python 3.8 doesn't support | for complex types even with future
|
||||
VectorValue = Union[Tuple[int,...], List[int], Tuple[float,...], List[float]]
|
||||
ScalarValue = Union[int, float]
|
||||
ScalarOrVectorValue = Union[VectorValue, ScalarValue]
|
||||
|
||||
def value_compare_diff(ref, data, eps=FLT_EPSILON):
|
||||
# if we're comparing scalar to a 1-length tuple or list, compare against the first element. We only expect this for
|
||||
# data where it's possibly autogenerated
|
||||
try:
|
||||
from typing import TypeGuard
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
def is_scalar(x: object) -> TypeGuard[ScalarValue]:
|
||||
return isinstance(x, int) or isinstance(x, float)
|
||||
|
||||
def is_vector(x: object) -> TypeGuard[VectorValue]:
|
||||
return isinstance(x, list) or isinstance(x, tuple)
|
||||
|
||||
def _scalar_compare_diff(ref: int | float, data: int | float, eps=FLT_EPSILON) -> Tuple[bool, float]:
|
||||
# if the types are different this is probably 0.0 == 0 or something. Just compare straight by casting to floats
|
||||
if type(data) != type(data):
|
||||
return float(data) == float(ref), abs(float(data)-float(ref))
|
||||
|
||||
# Special handling for NaNs - NaNs are always equal to NaNs, but NaN is never equal to any other value
|
||||
if math.isnan(ref) and math.isnan(data):
|
||||
return True, 0.0
|
||||
elif math.isnan(ref) != math.isnan(data):
|
||||
return False, 0.0
|
||||
|
||||
# Same as above for infs, but check the sign
|
||||
if math.isinf(ref) and math.isinf(data):
|
||||
return math.copysign(1.0, ref) == math.copysign(1.0, data), 0.0
|
||||
elif math.isinf(ref) != math.isinf(data):
|
||||
return False, 0.0
|
||||
|
||||
# Floats are equal if the absolute difference is less than epsilon times the largest.
|
||||
largest = max(abs(ref), abs(data))
|
||||
eps = largest * eps if largest > 1.0 else eps
|
||||
return abs(ref-data) <= eps, abs(ref-data)
|
||||
|
||||
def value_compare_diff(ref: ScalarOrVectorValue, data: ScalarOrVectorValue, eps=FLT_EPSILON) -> Tuple[bool, float]:
|
||||
if (type(data) == list or type(data) == tuple) and len(data) == 1 and type(data[0]) == type(ref):
|
||||
return value_compare_diff(ref, data[0], eps)
|
||||
|
||||
if type(ref) == float or type(data) == float:
|
||||
# if the types are different this is probably 0.0 == 0 or something. Just compare straight by casting to floats
|
||||
if type(data) != type(data):
|
||||
return float(data) == float(ref), abs(float(data)-float(ref))
|
||||
if is_scalar(ref) and is_scalar(data):
|
||||
return _scalar_compare_diff(ref, data, eps)
|
||||
|
||||
# Special handling for NaNs - NaNs are always equal to NaNs, but NaN is never equal to any other value
|
||||
if math.isnan(ref) and math.isnan(data):
|
||||
return True, 0.0
|
||||
elif math.isnan(ref) != math.isnan(data):
|
||||
return False, 0.0
|
||||
# if we're comparing scalar to a 1-length tuple or list, compare against the first element. We only expect this for
|
||||
# data where it's possibly autogenerated
|
||||
if is_scalar(ref):
|
||||
assert is_vector(data) and len(data) == 1
|
||||
return value_compare_diff(ref, data[0], eps)
|
||||
|
||||
# Same as above for infs, but check the sign
|
||||
if math.isinf(ref) and math.isinf(data):
|
||||
return math.copysign(1.0, ref) == math.copysign(1.0, data), 0.0
|
||||
elif math.isinf(ref) != math.isinf(data):
|
||||
return False, 0.0
|
||||
assert is_vector(ref) and is_vector(data)
|
||||
|
||||
# Floats are equal if the absolute difference is less than epsilon times the largest.
|
||||
largest = max(abs(ref), abs(data))
|
||||
eps = largest * eps if largest > 1.0 else eps
|
||||
return abs(ref-data) <= eps, abs(ref-data)
|
||||
elif type(ref) == list or type(ref) == tuple:
|
||||
# tuples and lists can be treated interchangeably
|
||||
if type(data) != list and type(data) != tuple:
|
||||
return False, 0.0
|
||||
# Lists/tuples are not equal if they have different lengths
|
||||
if len(ref) != len(data):
|
||||
return False, 0.0
|
||||
|
||||
# Lists are equal if they have the same length and all members have value_compare(i, j) == True
|
||||
if len(ref) != len(data):
|
||||
return False, 0.0
|
||||
ret = (True, 0.0)
|
||||
|
||||
ret = (True, 0.0)
|
||||
for i in range(len(ref)):
|
||||
is_eq, diff_amt = value_compare_diff(ref[i], data[i], eps)
|
||||
if not is_eq:
|
||||
ret = (False, max(ret[1], diff_amt))
|
||||
|
||||
for i in range(len(ref)):
|
||||
is_eq, diff_amt = value_compare_diff(ref[i], data[i], eps)
|
||||
if not is_eq:
|
||||
ret = (False, max(ret[1], diff_amt))
|
||||
|
||||
return ret
|
||||
elif type(ref) == dict:
|
||||
if type(data) != dict:
|
||||
return False, 0.0
|
||||
|
||||
# Similarly, dicts are equal if both have the same set of keys and
|
||||
# corresponding values are value_compare(i, j) == True
|
||||
if ref.keys() != data.keys():
|
||||
return False, 0.0
|
||||
|
||||
ret = (True, 0.0)
|
||||
|
||||
for i in ref.keys():
|
||||
is_eq, diff_amt = value_compare_diff(ref[i], data[i], eps)
|
||||
if not is_eq:
|
||||
ret = (False, max(ret[1], diff_amt))
|
||||
|
||||
return ret
|
||||
else:
|
||||
# For other types, just use normal comparison
|
||||
return ref == data, 0.0
|
||||
return ret
|
||||
|
||||
|
||||
def value_compare(ref, data, eps=FLT_EPSILON):
|
||||
def value_compare(ref: ScalarOrVectorValue | str | None, data: ScalarOrVectorValue | str | None, eps=FLT_EPSILON):
|
||||
# some simple cases that don't need diff compares and we allow for uniformity
|
||||
if ref is None or data is None: return data is ref and data is None
|
||||
if isinstance(ref, str) or isinstance(data, str): return ref == data
|
||||
|
||||
is_eq, diff_amt = value_compare_diff(ref, data, eps)
|
||||
return is_eq
|
||||
|
||||
|
||||
Reference in New Issue
Block a user