sepuri sai krishna created SPARK-58897:
------------------------------------------

             Summary: vector_norm with degree infinity silently ignores NaN 
elements
                 Key: SPARK-58897
                 URL: https://issues.apache.org/jira/browse/SPARK-58897
             Project: Spark
          Issue Type: Bug
          Components: SQL
    Affects Versions: 4.2.0
            Reporter: sepuri sai krishna


h3. Summary

The infinity-norm branch of {{vector_norm}} silently drops {{NaN}} elements 
instead of
propagating them. Every other degree of {{vector_norm}} propagates {{NaN}}, and 
every other
max-like function in Spark treats {{NaN}} as the largest value, so the infinity 
norm is the
lone outlier.

The single-element case is the damaging one: a vector consisting of {{NaN}} is 
reported as
having infinity norm {{0.0}}, making it indistinguishable from the zero vector. 
That in turn
makes {{vector_normalize}} return {{NULL}} (its zero-norm path) rather than a 
vector of
{{NaN}}.

h3. Reproduction

{code:sql}
-- Wrong: NaN is ignored
SELECT vector_norm(array(float('nan')), float('inf'));                 -- 0.0   
     expected NaN
SELECT vector_norm(array(float('nan'), 5.0F), float('inf'));           -- 5.0   
     expected NaN
SELECT vector_norm(array(5.0F, float('nan')), float('inf'));           -- 5.0   
     expected NaN
SELECT vector_norm(array(float('nan'), float('inf')), float('inf'));   -- 
Infinity   expected NaN

-- Correct: every other degree propagates NaN
SELECT vector_norm(array(float('nan')), 1.0F);                         -- NaN
SELECT vector_norm(array(float('nan')), 2.0F);                         -- NaN
SELECT vector_norm(array(float('nan'), 5.0F), 2.0F);                   -- NaN

-- Knock-on effect in vector_normalize
SELECT vector_normalize(array(float('nan')), float('inf'));            -- NULL  
     expected [NaN]
SELECT vector_normalize(array(float('nan')), 2.0F);                    -- [NaN]
{code}

h3. Why this is a bug and not a design choice

Spark's established convention is that {{NaN}} compares as larger than any 
other value. All of
the following agree, and disagree with the infinity norm:

{code:sql}
SELECT greatest(float('nan'), 5.0F);                          -- NaN
SELECT array_max(array(float('nan'), 5.0F));                  -- NaN
SELECT max(v) FROM values (float('nan')), (5.0F) AS t(v);     -- NaN
SELECT sort_array(array(float('nan'), 5.0F));                 -- [5.0, NaN]
{code}

Since the infinity norm is defined as the maximum absolute value, it should 
follow the same
convention that {{max}} and {{array_max}} do.

h3. Root cause

{{VectorFunctionImplUtils.vectorInfNorm}}
(sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/VectorFunctionImplUtils.java)
hand-rolls the maximum with a {{>}} comparison seeded at zero:

{code:java}
float maxAbs = 0.0f;
for (int i = 0; i < len; i++) {
  if (vec.isNullAt(i)) {
    return null;
  }
  float absVal = Math.abs(vec.getFloat(i));
  if (absVal > maxAbs) {
    maxAbs = absVal;
  }
}
return (double) maxAbs;
{code}

Any comparison involving {{NaN}} is false under IEEE 754, so {{maxAbs}} is 
never updated to
{{NaN}} and the {{NaN}} never reaches the result. {{Math.max}}, which returns 
{{NaN}} when
either argument is {{NaN}}, gives the expected behaviour.

h3. Scope

This is distinct from SPARK-58544, which fixed float overflow in the 
intermediate sums of the
same file. That issue explicitly scoped its "correct as-is" cases to empty 
vectors, NULL
elements, and genuinely zero magnitude; {{NaN}} input was not covered. The 
existing behaviour
for empty vectors ({{0.0}}) and for vectors containing NULL ({{NULL}}) is 
unchanged by this
report.




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to