Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion Packages/MIES/MIES_SweepFormula_Executor.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,15 @@ static Function/WAVE SFE_FormulaExecutorStringOrVariable(STRUCT SF_ExecutionData
return SFH_GetOutputForExecutorSingle(outT, exd.graph, "ExecutorStringReturn")
End

static Function/WAVE SFE_ConvertNonFiniteElements(WAVE/T subArray)
/// @brief Convert a text wave that consists solely of the non-finite literals inf/-inf/NaN into a numeric wave
///
/// @return numeric wave with the converted values or a null wave reference if at least one element is not a
/// non-finite literal
Function/WAVE SFE_ConvertNonFiniteElements(WAVE/T subArray)

if(numpnts(subArray) == 0)
return $""
endif

Make/FREE/D/N=(DimSize(subArray, ROWS), DimSize(subArray, COLS), DimSize(subArray, LAYERS), DimSize(subArray, CHUNKS)) convert
MultiThread convert[][][][] = SFE_ConvertNonFiniteElementsImpl(subArray[p][q][r][s])
Expand Down
32 changes: 31 additions & 1 deletion Packages/MIES/MIES_SweepFormula_Operations.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -2567,9 +2567,31 @@ static Function/WAVE SFO_OperationXValuesImpl(WAVE/Z input)
return output
End

/// @brief Convert a dataset that consists solely of the non-finite literals inf/-inf/NaN into a numeric wave
///
/// This allows primitive operations like `1 - NaN` or `1 - inf` where a non-finite value is entered as bare
/// literal and is therefore kept as string by the parser. Returns the input unchanged if it is not textual or if
/// it contains at least one element that is not a non-finite literal.
Comment thread
Copilot marked this conversation as resolved.
Outdated
static Function/WAVE SFO_ConvertNonFiniteText(WAVE/Z data)

if(!WaveExists(data) || !IsTextWave(data))
return data
endif

WAVE/T dataText = data
WAVE/Z converted = SFE_ConvertNonFiniteElements(dataText)
if(!WaveExists(converted))
return data
endif

CopyScales dataText, converted

return converted
End

static Function/WAVE SFO_IndexOverDataSetsForPrimitiveOperation(STRUCT SF_ExecutionData &exd, string opShort)

variable dataSetNum0, dataSetNum1
variable dataSetNum0, dataSetNum1, i
string errMsg, type1, type2, resultType

SFH_CheckArgumentCount(exd, opShort, 2, maxArgs = 2)
Expand All @@ -2578,6 +2600,14 @@ static Function/WAVE SFO_IndexOverDataSetsForPrimitiveOperation(STRUCT SF_Execut
WAVE/WAVE arg1 = SF_ResolveDatasetFromJSON(exd, 1)
dataSetNum0 = DimSize(arg0, ROWS)
dataSetNum1 = DimSize(arg1, ROWS)

// treat the non-finite literals inf/-inf/NaN as numeric operands, see #1863
for(i = 0; i < dataSetNum0; i += 1)
arg0[i] = SFO_ConvertNonFiniteText(arg0[i])
endfor
for(i = 0; i < dataSetNum1; i += 1)
arg1[i] = SFO_ConvertNonFiniteText(arg1[i])
endfor
if(dataSetNum0 == 0 && dataSetNum1 == 0)
WAVE/WAVE output = SFH_CreateSFRefWave(exd.graph, opShort, 0)
return output
Expand Down
3 changes: 3 additions & 0 deletions Packages/doc/SweepFormula.rst
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ The array evaluation supports numeric and text data. The interpretation of the J
text data is preferred. This means that `["NaN"]` returns a one element text wave `{"NaN"}`,
whereas `[1, "NaN"]` returns a two element numeric wave `{1, NaN}`. If one element can not be
parsed as string then it is assumed that the array contains numeric data.
The non-finite literals `inf`, `-inf` and `NaN` are also accepted as operands of the primitive
operations `+`, `-`, `*` and `/`, so that e.g. `1 - NaN` and `1 - inf` are valid and evaluate them
as numeric values.
The JSON null element is only allowed for the topmost array as the parser inserts it for
operation with no argument like e.g. `select()`. For sub arrays null elements `[null]`
are invalid and result in an error.
Expand Down
47 changes: 33 additions & 14 deletions Packages/tests/Basic/UTF_SweepFormula.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -110,20 +110,39 @@ static Function TestNonFiniteValues()
TestOperationMinMaxHelper(win, "\"NaN\"", "NaN", NaN)
End

// Fails with Abort
// UTF_TD_GENERATOR DataGenerators#NonFiniteValues
//static Function TestNonFiniteValuesPrimitiveOperations([variable var])
//
// string win, device, str
//
// [win, device] = CreateEmptyUnlockedDataBrowserWindow()
//
// str = "\"" + num2str(var) + "\""
// TestOperationMinMaxHelper(win, "{\"+\":[1," + str + "]}", "1+" + str, 1 + var)
// TestOperationMinMaxHelper(win, "{\"*\":[1," + str + "]}", "1*" + str, 1 * var)
// TestOperationMinMaxHelper(win, "{\"-\":[1," + str + "]}", "1-" + str, 1 - var)
// TestOperationMinMaxHelper(win, "{\"/\":[1," + str + "]}", "1/" + str, 1 / var)
//End
static Function TestNonFiniteValuesPrimitiveOperations()

string win

win = GetDataBrowserWithData()

// non-finite values entered as bare literals are kept as string by the parser (see #1863)
CheckEqualFormulas("{\"+\":[1,\"NaN\"]}", "1+NaN")
CheckEqualFormulas("{\"-\":[1,\"NaN\"]}", "1-NaN")
CheckEqualFormulas("{\"*\":[1,\"NaN\"]}", "1*NaN")
CheckEqualFormulas("{\"/\":[1,\"NaN\"]}", "1/NaN")

// and are converted to numeric values when used in primitive operations
WAVE data = SFE_ExecuteFormula("1+NaN", win, singleResult = 1, useVariables = 0)
CHECK_EQUAL_WAVES(data, {NaN}, mode = WAVE_DATA)
WAVE data = SFE_ExecuteFormula("1-NaN", win, singleResult = 1, useVariables = 0)
CHECK_EQUAL_WAVES(data, {NaN}, mode = WAVE_DATA)
WAVE data = SFE_ExecuteFormula("1*NaN", win, singleResult = 1, useVariables = 0)
CHECK_EQUAL_WAVES(data, {NaN}, mode = WAVE_DATA)
WAVE data = SFE_ExecuteFormula("1/NaN", win, singleResult = 1, useVariables = 0)
CHECK_EQUAL_WAVES(data, {NaN}, mode = WAVE_DATA)

WAVE data = SFE_ExecuteFormula("1-inf", win, singleResult = 1, useVariables = 0)
CHECK_EQUAL_WAVES(data, {-Inf}, mode = WAVE_DATA)
WAVE data = SFE_ExecuteFormula("1+inf", win, singleResult = 1, useVariables = 0)
CHECK_EQUAL_WAVES(data, {+Inf}, mode = WAVE_DATA)
WAVE data = SFE_ExecuteFormula("1--inf", win, singleResult = 1, useVariables = 0)
CHECK_EQUAL_WAVES(data, {+Inf}, mode = WAVE_DATA)
WAVE data = SFE_ExecuteFormula("1*inf", win, singleResult = 1, useVariables = 0)
CHECK_EQUAL_WAVES(data, {+Inf}, mode = WAVE_DATA)
WAVE data = SFE_ExecuteFormula("1/inf", win, singleResult = 1, useVariables = 0)
CHECK_EQUAL_WAVES(data, {0}, mode = WAVE_DATA)
End

static Function TestScientificNotation()

Expand Down