github.com/m3db/m3@v1.5.0/src/query/functions/linear/math_test.go (about)

     1  // Copyright (c) 2018 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package linear
    22  
    23  import (
    24  	"math"
    25  	"testing"
    26  
    27  	"github.com/m3db/m3/src/query/executor/transform"
    28  	"github.com/m3db/m3/src/query/models"
    29  	"github.com/m3db/m3/src/query/parser"
    30  	"github.com/m3db/m3/src/query/test"
    31  	"github.com/m3db/m3/src/query/test/compare"
    32  	"github.com/m3db/m3/src/query/test/executor"
    33  
    34  	"github.com/stretchr/testify/assert"
    35  	"github.com/stretchr/testify/require"
    36  )
    37  
    38  func expectedMathVals(values [][]float64, fn func(x float64) float64) [][]float64 {
    39  	expected := make([][]float64, 0, len(values))
    40  	for _, val := range values {
    41  		v := make([]float64, len(val))
    42  		for i, ev := range val {
    43  			v[i] = fn(ev)
    44  		}
    45  
    46  		expected = append(expected, v)
    47  	}
    48  	return expected
    49  }
    50  
    51  func TestAbsWithAllValues(t *testing.T) {
    52  	values, bounds := test.GenerateValuesAndBounds(nil, nil)
    53  	values[0][0] = -values[0][0]
    54  	values[1][1] = -values[1][1]
    55  
    56  	block := test.NewBlockFromValues(bounds, values)
    57  	c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1)))
    58  	mathOp, err := NewMathOp(AbsType)
    59  	require.NoError(t, err)
    60  
    61  	op, ok := mathOp.(transform.Params)
    62  	require.True(t, ok)
    63  	node := op.Node(c, transform.Options{})
    64  	err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block)
    65  	require.NoError(t, err)
    66  	expected := expectedMathVals(values, math.Abs)
    67  	assert.Len(t, sink.Values, 2)
    68  	assert.Equal(t, expected, sink.Values)
    69  }
    70  
    71  func TestAbsWithSomeValues(t *testing.T) {
    72  	v := [][]float64{
    73  		{0, math.NaN(), 2, 3, 4},
    74  		{math.NaN(), 6, 7, 8, 9},
    75  	}
    76  
    77  	values, bounds := test.GenerateValuesAndBounds(v, nil)
    78  	block := test.NewBlockFromValues(bounds, values)
    79  	c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1)))
    80  	mathOp, err := NewMathOp(AbsType)
    81  	require.NoError(t, err)
    82  
    83  	op, ok := mathOp.(transform.Params)
    84  	require.True(t, ok)
    85  
    86  	node := op.Node(c, transform.Options{})
    87  	err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block)
    88  	require.NoError(t, err)
    89  	expected := expectedMathVals(values, math.Abs)
    90  	assert.Len(t, sink.Values, 2)
    91  	compare.EqualsWithNans(t, expected, sink.Values)
    92  }
    93  
    94  func TestLn(t *testing.T) {
    95  	values, bounds := test.GenerateValuesAndBounds(nil, nil)
    96  
    97  	block := test.NewBlockFromValues(bounds, values)
    98  	c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1)))
    99  	mathOp, err := NewMathOp(LnType)
   100  	require.NoError(t, err)
   101  
   102  	op, ok := mathOp.(transform.Params)
   103  	require.True(t, ok)
   104  
   105  	node := op.Node(c, transform.Options{})
   106  	err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block)
   107  	require.NoError(t, err)
   108  	expected := expectedMathVals(values, math.Log)
   109  	assert.Len(t, sink.Values, 2)
   110  	assert.Equal(t, expected, sink.Values)
   111  }
   112  
   113  func TestLog10WithNoValues(t *testing.T) {
   114  	v := [][]float64{
   115  		{nan, nan, nan, nan, nan},
   116  		{nan, nan, nan, nan, nan},
   117  	}
   118  
   119  	values, bounds := test.GenerateValuesAndBounds(v, nil)
   120  	block := test.NewBlockFromValues(bounds, values)
   121  	c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1)))
   122  	mathOp, err := NewMathOp(Log10Type)
   123  	require.NoError(t, err)
   124  
   125  	op, ok := mathOp.(transform.Params)
   126  	require.True(t, ok)
   127  
   128  	node := op.Node(c, transform.Options{})
   129  	err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block)
   130  	require.NoError(t, err)
   131  	expected := expectedMathVals(values, math.Log10)
   132  	assert.Len(t, sink.Values, 2)
   133  	compare.EqualsWithNans(t, expected, sink.Values)
   134  }
   135  
   136  func TestLog2WithSomeValues(t *testing.T) {
   137  	v := [][]float64{
   138  		{nan, 1, 2, 3, 3},
   139  		{nan, 4, 5, 6, 6},
   140  	}
   141  
   142  	values, bounds := test.GenerateValuesAndBounds(v, nil)
   143  	block := test.NewBlockFromValues(bounds, values)
   144  	c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1)))
   145  	mathOp, err := NewMathOp(Log2Type)
   146  	require.NoError(t, err)
   147  
   148  	op, ok := mathOp.(transform.Params)
   149  	require.True(t, ok)
   150  
   151  	node := op.Node(c, transform.Options{})
   152  	err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block)
   153  	require.NoError(t, err)
   154  	expected := expectedMathVals(values, math.Log2)
   155  	assert.Len(t, sink.Values, 2)
   156  	compare.EqualsWithNans(t, expected, sink.Values)
   157  }
   158  
   159  func TestFloorWithSomeValues(t *testing.T) {
   160  	v := [][]float64{
   161  		{0, math.NaN(), 2.2, 3.3, 4},
   162  		{math.NaN(), 6, 7.77, 8, 9.9},
   163  	}
   164  
   165  	values, bounds := test.GenerateValuesAndBounds(v, nil)
   166  	block := test.NewBlockFromValues(bounds, values)
   167  	c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1)))
   168  	mathOp, err := NewMathOp(FloorType)
   169  	require.NoError(t, err)
   170  
   171  	op, ok := mathOp.(transform.Params)
   172  	require.True(t, ok)
   173  
   174  	node := op.Node(c, transform.Options{})
   175  	err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block)
   176  	require.NoError(t, err)
   177  	expected := expectedMathVals(values, math.Floor)
   178  	assert.Len(t, sink.Values, 2)
   179  	compare.EqualsWithNans(t, expected, sink.Values)
   180  }
   181  
   182  func TestCeilWithSomeValues(t *testing.T) {
   183  	v := [][]float64{
   184  		{0, math.NaN(), 2.2, 3.3, 4},
   185  		{math.NaN(), 6, 7.77, 8, 9.9},
   186  	}
   187  
   188  	values, bounds := test.GenerateValuesAndBounds(v, nil)
   189  	block := test.NewBlockFromValues(bounds, values)
   190  	c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1)))
   191  	mathOp, err := NewMathOp(CeilType)
   192  	require.NoError(t, err)
   193  
   194  	op, ok := mathOp.(transform.Params)
   195  	require.True(t, ok)
   196  
   197  	node := op.Node(c, transform.Options{})
   198  	err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block)
   199  	require.NoError(t, err)
   200  	expected := expectedMathVals(values, math.Ceil)
   201  	assert.Len(t, sink.Values, 2)
   202  	compare.EqualsWithNans(t, expected, sink.Values)
   203  }
   204  func TestExpWithSomeValues(t *testing.T) {
   205  	v := [][]float64{
   206  		{0, math.NaN(), 2, 3, 4},
   207  		{math.NaN(), 6, 7, 8, 9},
   208  	}
   209  
   210  	values, bounds := test.GenerateValuesAndBounds(v, nil)
   211  	block := test.NewBlockFromValues(bounds, values)
   212  	c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1)))
   213  	mathOp, err := NewMathOp(ExpType)
   214  	require.NoError(t, err)
   215  
   216  	op, ok := mathOp.(transform.Params)
   217  	require.True(t, ok)
   218  
   219  	node := op.Node(c, transform.Options{})
   220  	err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block)
   221  	require.NoError(t, err)
   222  	expected := expectedMathVals(values, math.Exp)
   223  	assert.Len(t, sink.Values, 2)
   224  	compare.EqualsWithNans(t, expected, sink.Values)
   225  }
   226  
   227  func TestSqrtWithSomeValues(t *testing.T) {
   228  	v := [][]float64{
   229  		{0, math.NaN(), 2, 3, 4},
   230  		{math.NaN(), 6, 7, 8, 9},
   231  	}
   232  
   233  	values, bounds := test.GenerateValuesAndBounds(v, nil)
   234  	block := test.NewBlockFromValues(bounds, values)
   235  	c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1)))
   236  	mathOp, err := NewMathOp(SqrtType)
   237  	require.NoError(t, err)
   238  
   239  	op, ok := mathOp.(transform.Params)
   240  	require.True(t, ok)
   241  
   242  	node := op.Node(c, transform.Options{})
   243  	err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block)
   244  	require.NoError(t, err)
   245  	expected := expectedMathVals(values, math.Sqrt)
   246  	assert.Len(t, sink.Values, 2)
   247  	compare.EqualsWithNans(t, expected, sink.Values)
   248  }
   249  
   250  func TestNonExistentFunc(t *testing.T) {
   251  	_, err := NewMathOp("nonexistent_func")
   252  	require.Error(t, err)
   253  }