1// Copyright ©2013 The Gonum Authors. All rights reserved.
2// Use of this code is governed by a BSD-style
3// license that can be found in the LICENSE file
4
5package cmplxs
6
7import (
8	"fmt"
9	"math"
10	"math/cmplx"
11	"strconv"
12	"testing"
13
14	"golang.org/x/exp/rand"
15
16	"gonum.org/v1/gonum/cmplxs/cscalar"
17	"gonum.org/v1/gonum/floats"
18)
19
20const (
21	EqTolerance = 1e-14
22	Small       = 10
23	Medium      = 1000
24	Large       = 100000
25	Huge        = 10000000
26)
27
28func areSlicesEqual(t *testing.T, truth, comp []complex128, str string) {
29	if !EqualApprox(comp, truth, EqTolerance) {
30		t.Errorf(str+". Expected %v, returned %v", truth, comp)
31	}
32}
33
34func areSlicesSame(t *testing.T, truth, comp []complex128, str string) {
35	ok := len(truth) == len(comp)
36	if ok {
37		for i, a := range truth {
38			if !cscalar.EqualWithinAbsOrRel(a, comp[i], EqTolerance, EqTolerance) && !cscalar.Same(a, comp[i]) {
39				ok = false
40				break
41			}
42		}
43	}
44	if !ok {
45		t.Errorf(str+". Expected %v, returned %v", truth, comp)
46	}
47}
48
49func Panics(fun func()) (b bool) {
50	defer func() {
51		err := recover()
52		if err != nil {
53			b = true
54		}
55	}()
56	fun()
57	return
58}
59
60func TestAdd(t *testing.T) {
61	a := []complex128{1 + 1i, 2 + 2i, 3 + 3i}
62	b := []complex128{4 + 4i, 5 + 5i, 6 + 6i}
63	c := []complex128{7 + 7i, 8 + 8i, 9 + 9i}
64	truth := []complex128{12 + 12i, 15 + 15i, 18 + 18i}
65	n := make([]complex128, len(a))
66
67	Add(n, a)
68	Add(n, b)
69	Add(n, c)
70	areSlicesEqual(t, truth, n, "Wrong addition of slices new receiver")
71	Add(a, b)
72	Add(a, c)
73	areSlicesEqual(t, truth, n, "Wrong addition of slices for no new receiver")
74
75	// Test that it panics
76	if !Panics(func() { Add(make([]complex128, 2), make([]complex128, 3)) }) {
77		t.Errorf("Did not panic with length mismatch")
78	}
79}
80
81func TestAddTo(t *testing.T) {
82	a := []complex128{1 + 1i, 2 + 2i, 3 + 3i}
83	b := []complex128{4 + 4i, 5 + 5i, 6 + 6i}
84	truth := []complex128{5 + 5i, 7 + 7i, 9 + 9i}
85	n1 := make([]complex128, len(a))
86
87	n2 := AddTo(n1, a, b)
88	areSlicesEqual(t, truth, n1, "Bad addition from mutator")
89	areSlicesEqual(t, truth, n2, "Bad addition from returned slice")
90
91	// Test that it panics
92	if !Panics(func() { AddTo(make([]complex128, 2), make([]complex128, 3), make([]complex128, 3)) }) {
93		t.Errorf("Did not panic with length mismatch")
94	}
95	if !Panics(func() { AddTo(make([]complex128, 3), make([]complex128, 3), make([]complex128, 2)) }) {
96		t.Errorf("Did not panic with length mismatch")
97	}
98}
99
100func TestAddConst(t *testing.T) {
101	s := []complex128{3 + 1i, 4 + 2i, 1 + 3i, 7 + 4i, 5 + 5i}
102	c := 6 + 1i
103	truth := []complex128{9 + 2i, 10 + 3i, 7 + 4i, 13 + 5i, 11 + 6i}
104	AddConst(c, s)
105	areSlicesEqual(t, truth, s, "Wrong addition of constant")
106}
107
108func TestAddScaled(t *testing.T) {
109	s := []complex128{3, 4, 1, 7, 5}
110	alpha := 6 + 1i
111	dst := []complex128{1, 2, 3, 4, 5}
112	ans := []complex128{19 + 3i, 26 + 4i, 9 + 1i, 46 + 7i, 35 + 5i}
113	AddScaled(dst, alpha, s)
114	if !EqualApprox(dst, ans, EqTolerance) {
115		t.Errorf("Adding scaled did not match. Expected %v, returned %v", ans, dst)
116	}
117	short := []complex128{1}
118	if !Panics(func() { AddScaled(dst, alpha, short) }) {
119		t.Errorf("Doesn't panic if s is smaller than dst")
120	}
121	if !Panics(func() { AddScaled(short, alpha, s) }) {
122		t.Errorf("Doesn't panic if dst is smaller than s")
123	}
124}
125
126func TestAddScaledTo(t *testing.T) {
127	s := []complex128{3, 4, 1, 7, 5}
128	alpha := 6 + 1i
129	y := []complex128{1, 2, 3, 4, 5}
130	dst1 := make([]complex128, 5)
131	ans := []complex128{19 + 3i, 26 + 4i, 9 + 1i, 46 + 7i, 35 + 5i}
132	dst2 := AddScaledTo(dst1, y, alpha, s)
133	if !EqualApprox(dst1, ans, EqTolerance) {
134		t.Errorf("AddScaledTo did not match for mutator")
135	}
136	if !EqualApprox(dst2, ans, EqTolerance) {
137		t.Errorf("AddScaledTo did not match for returned slice")
138	}
139	AddScaledTo(dst1, y, alpha, s)
140	if !EqualApprox(dst1, ans, EqTolerance) {
141		t.Errorf("Reusing dst did not match")
142	}
143	short := []complex128{1}
144	if !Panics(func() { AddScaledTo(dst1, y, alpha, short) }) {
145		t.Errorf("Doesn't panic if s is smaller than dst")
146	}
147	if !Panics(func() { AddScaledTo(short, y, alpha, s) }) {
148		t.Errorf("Doesn't panic if dst is smaller than s")
149	}
150	if !Panics(func() { AddScaledTo(dst1, short, alpha, s) }) {
151		t.Errorf("Doesn't panic if y is smaller than dst")
152	}
153}
154
155func TestCount(t *testing.T) {
156	s := []complex128{3, 4, 1, 7, 5}
157	f := func(v complex128) bool { return cmplx.Abs(v) > 3.5 }
158	truth := 3
159	n := Count(f, s)
160	if n != truth {
161		t.Errorf("Wrong number of elements counted")
162	}
163}
164
165func TestCumProd(t *testing.T) {
166	s := []complex128{3 + 1i, 4 + 2i, 1 + 3i, 7 + 4i, 5 + 5i}
167	receiver := make([]complex128, len(s))
168	result := CumProd(receiver, s)
169	truth := []complex128{3 + 1i, 10 + 10i, -20 + 40i, -300 + 200i, -2500 - 500i}
170	areSlicesEqual(t, truth, receiver, "Wrong cumprod mutated with new receiver")
171	areSlicesEqual(t, truth, result, "Wrong cumprod result with new receiver")
172	CumProd(receiver, s)
173	areSlicesEqual(t, truth, receiver, "Wrong cumprod returned with reused receiver")
174
175	// Test that it panics
176	if !Panics(func() { CumProd(make([]complex128, 2), make([]complex128, 3)) }) {
177		t.Errorf("Did not panic with length mismatch")
178	}
179
180	// Test empty CumProd
181	emptyReceiver := make([]complex128, 0)
182	truth = []complex128{}
183	CumProd(emptyReceiver, emptyReceiver)
184	areSlicesEqual(t, truth, emptyReceiver, "Wrong cumprod returned with empty receiver")
185}
186
187func TestComplex(t *testing.T) {
188	for i, test := range []struct {
189		dst        []complex128
190		real, imag []float64
191		want       []complex128
192		panics     bool
193	}{
194		{},
195		{
196			dst:  make([]complex128, 4),
197			real: []float64{1, 2, 3, 4},
198			imag: []float64{1, 2, 3, 4},
199			want: []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i},
200		},
201		{
202			dst:    make([]complex128, 3),
203			real:   []float64{1, 2, 3, 4},
204			imag:   []float64{1, 2, 3, 4},
205			panics: true,
206		},
207		{
208			dst:    make([]complex128, 4),
209			real:   []float64{1, 2, 3},
210			imag:   []float64{1, 2, 3, 4},
211			panics: true,
212		},
213		{
214			dst:    make([]complex128, 4),
215			real:   []float64{1, 2, 3, 4},
216			imag:   []float64{1, 2, 3},
217			panics: true,
218		},
219		{
220			dst:  make([]complex128, 4),
221			real: []float64{1, 2, 3, 4},
222			imag: []float64{1, 2, 3, math.NaN()},
223			want: []complex128{1 + 1i, 2 + 2i, 3 + 3i, cmplx.NaN()},
224		},
225	} {
226		var got []complex128
227		panicked := Panics(func() {
228			got = Complex(test.dst, test.real, test.imag)
229		})
230		if panicked != test.panics {
231			if panicked {
232				t.Errorf("unexpected panic for test %d", i)
233			} else {
234				t.Errorf("expected panic for test %d", i)
235			}
236		}
237		if panicked || test.panics {
238			continue
239		}
240		if !Same(got, test.dst) {
241			t.Errorf("mismatch between dst and return test %d: got:%v want:%v", i, got, test.dst)
242		}
243		if !Same(got, test.want) {
244			t.Errorf("unexpected result for test %d: got:%v want:%v", i, got, test.want)
245		}
246	}
247
248}
249
250func TestCumSum(t *testing.T) {
251	s := []complex128{3 + 1i, 4 + 2i, 1 + 3i, 7 + 4i, 5 + 5i}
252	receiver := make([]complex128, len(s))
253	result := CumSum(receiver, s)
254	truth := []complex128{3 + 1i, 7 + 3i, 8 + 6i, 15 + 10i, 20 + 15i}
255	areSlicesEqual(t, truth, receiver, "Wrong cumsum mutated with new receiver")
256	areSlicesEqual(t, truth, result, "Wrong cumsum returned with new receiver")
257	CumSum(receiver, s)
258	areSlicesEqual(t, truth, receiver, "Wrong cumsum returned with reused receiver")
259
260	// Test that it panics
261	if !Panics(func() { CumSum(make([]complex128, 2), make([]complex128, 3)) }) {
262		t.Errorf("Did not panic with length mismatch")
263	}
264
265	// Test empty CumSum
266	emptyReceiver := make([]complex128, 0)
267	truth = []complex128{}
268	CumSum(emptyReceiver, emptyReceiver)
269	areSlicesEqual(t, truth, emptyReceiver, "Wrong cumsum returned with empty receiver")
270}
271
272func TestDistance(t *testing.T) {
273	norms := []float64{1, 2, 4, math.Inf(1)}
274	slices := []struct {
275		s []complex128
276		t []complex128
277	}{
278		{
279			nil,
280			nil,
281		},
282		{
283			[]complex128{8 + 1i, 9 + 2i, 10 + 3i, -12 + 4i},
284			[]complex128{8 + 1i, 9 + 2i, 10 + 3i, -12 + 4i},
285		},
286		{
287			[]complex128{1 + 1i, 2 + 2i, 3 + 3i, -4 + 4i, -5 + 5i, 8 + 6i},
288			[]complex128{-9.2 - 1i, -6.8 - 2i, 9 - 3i, -3 - 4i, -2 - 5i, 1 - 6i},
289		},
290	}
291
292	for j, test := range slices {
293		tmp := make([]complex128, len(test.s))
294		for i, L := range norms {
295			dist := Distance(test.s, test.t, L)
296			copy(tmp, test.s)
297			Sub(tmp, test.t)
298			norm := Norm(tmp, L)
299			if dist != norm { // Use equality because they should be identical.
300				t.Errorf("Distance does not match norm for case %v, %v. Expected %v, Found %v.", i, j, norm, dist)
301			}
302		}
303	}
304
305	if !Panics(func() { Distance([]complex128{}, []complex128{1}, 1) }) {
306		t.Errorf("Did not panic with unequal lengths")
307	}
308}
309
310func TestDiv(t *testing.T) {
311	s1 := []complex128{5 - 5i, 12 + 2i, 27 - 3i}
312	s2 := []complex128{1 - 1i, 2 + 2i, 3 - 1i}
313	ans := []complex128{5 + 0i, 3.5 - 2.5i, 8.4 + 1.8i}
314	Div(s1, s2)
315	if !EqualApprox(s1, ans, EqTolerance) {
316		t.Errorf("Div doesn't give correct answer. Expected %v, Found %v.", ans, s1)
317	}
318	s1short := []complex128{1}
319	if !Panics(func() { Div(s1short, s2) }) {
320		t.Errorf("Did not panic with unequal lengths")
321	}
322	s2short := []complex128{1}
323	if !Panics(func() { Div(s1, s2short) }) {
324		t.Errorf("Did not panic with unequal lengths")
325	}
326}
327
328func TestDivTo(t *testing.T) {
329	s1 := []complex128{5 - 5i, 12 + 2i, 27 - 3i}
330	s1orig := []complex128{5 - 5i, 12 + 2i, 27 - 3i}
331	s2 := []complex128{1 - 1i, 2 + 2i, 3 - 1i}
332	s2orig := []complex128{1 - 1i, 2 + 2i, 3 - 1i}
333	dst1 := make([]complex128, 3)
334	ans := []complex128{5 + 0i, 3.5 - 2.5i, 8.4 + 1.8i}
335	dst2 := DivTo(dst1, s1, s2)
336	if !EqualApprox(dst1, ans, EqTolerance) {
337		t.Errorf("DivTo doesn't give correct answer in mutated slice")
338	}
339	if !EqualApprox(dst2, ans, EqTolerance) {
340		t.Errorf("DivTo doesn't give correct answer in returned slice")
341	}
342	if !EqualApprox(s1, s1orig, EqTolerance) {
343		t.Errorf("S1 changes during multo")
344	}
345	if !EqualApprox(s2, s2orig, EqTolerance) {
346		t.Errorf("s2 changes during multo")
347	}
348	DivTo(dst1, s1, s2)
349	if !EqualApprox(dst1, ans, EqTolerance) {
350		t.Errorf("DivTo doesn't give correct answer reusing dst")
351	}
352	dstShort := []complex128{1}
353	if !Panics(func() { DivTo(dstShort, s1, s2) }) {
354		t.Errorf("Did not panic with s1 wrong length")
355	}
356	s1short := []complex128{1}
357	if !Panics(func() { DivTo(dst1, s1short, s2) }) {
358		t.Errorf("Did not panic with s1 wrong length")
359	}
360	s2short := []complex128{1}
361	if !Panics(func() { DivTo(dst1, s1, s2short) }) {
362		t.Errorf("Did not panic with s2 wrong length")
363	}
364}
365
366func TestDot(t *testing.T) {
367	s1 := []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i}
368	s2 := []complex128{-3 + 4i, 4 + 3i, 5 + 2i, -6 + 1i}
369	truth := 16 + 24i
370	ans := Dot(s1, s2)
371	if ans != truth {
372		t.Errorf("Dot product computed incorrectly. Expected %v, Found %v.", truth, ans)
373	}
374
375	// Test that it panics
376	if !Panics(func() { Dot(make([]complex128, 2), make([]complex128, 3)) }) {
377		t.Errorf("Did not panic with length mismatch")
378	}
379}
380
381func TestEquals(t *testing.T) {
382	s1 := []complex128{1 + 1i, 2 + 4i, 3 + 8i, 4 + 16i}
383	s2 := []complex128{1 + 1i, 2 + 4i, 3 + 8i, 4 + 16i}
384	if !Equal(s1, s2) {
385		t.Errorf("Equal slices returned as unequal")
386	}
387	s2 = []complex128{1 + 1i, 2 + 4i, 3 + 8i, 4 + 16i + 1e-14}
388	if Equal(s1, s2) {
389		t.Errorf("Unequal slices returned as equal")
390	}
391	if Equal(s1, []complex128{}) {
392		t.Errorf("Unequal slice lengths returned as equal")
393	}
394}
395
396func TestEqualApprox(t *testing.T) {
397	s1 := []complex128{1 + 1i, 2 + 4i, 3 + 8i, 4 + 16i}
398	s2 := []complex128{1 + 1i, 2 + 4i, 3 + 8i, 4 + 16i + 1e-10}
399	if EqualApprox(s1, s2, 1e-13) {
400		t.Errorf("Unequal slices returned as equal for absolute")
401	}
402	if !EqualApprox(s1, s2, 1e-5) {
403		t.Errorf("Equal slices returned as unequal for absolute")
404	}
405	s1 = []complex128{1 + 1i, 2 + 4i, 3 + 8i, 1000 + 1000i}
406	s2 = []complex128{1 + 1i, 2 + 4i, 3 + 8i, (1000 + 1000i) * (1 + 1e-7)}
407	if EqualApprox(s1, s2, 1e-8) {
408		t.Errorf("Unequal slices returned as equal for relative")
409	}
410	if !EqualApprox(s1, s2, 1e-5) {
411		t.Errorf("Equal slices returned as unequal for relative")
412	}
413	if EqualApprox(s1, []complex128{}, 1e-5) {
414		t.Errorf("Unequal slice lengths returned as equal")
415	}
416}
417
418func TestEqualFunc(t *testing.T) {
419	s1 := []complex128{1 + 1i, 2 + 4i, 3 + 8i, 4 + 16i}
420	s2 := []complex128{1 + 1i, 2 + 4i, 3 + 8i, 4 + 16i}
421	eq := func(x, y complex128) bool { return x == y }
422	if !EqualFunc(s1, s2, eq) {
423		t.Errorf("Equal slices returned as unequal")
424	}
425	s2 = []complex128{1 + 1i, 2 + 4i, 3 + 8i, 4 + 16i + 1e-14}
426	if EqualFunc(s1, s2, eq) {
427		t.Errorf("Unequal slices returned as equal")
428	}
429	if EqualFunc(s1, []complex128{}, eq) {
430		t.Errorf("Unequal slice lengths returned as equal")
431	}
432}
433
434func TestEqualLengths(t *testing.T) {
435	s1 := []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i}
436	s2 := []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i}
437	s3 := []complex128{1 + 1i, 2 + 2i, 3 + 3i}
438	if !EqualLengths(s1, s2) {
439		t.Errorf("Equal lengths returned as unequal")
440	}
441	if EqualLengths(s1, s3) {
442		t.Errorf("Unequal lengths returned as equal")
443	}
444	if !EqualLengths(s1) {
445		t.Errorf("Single slice returned as unequal")
446	}
447	if !EqualLengths() {
448		t.Errorf("No slices returned as unequal")
449	}
450}
451
452func eqIntSlice(one, two []int) string {
453	if len(one) != len(two) {
454		return "Length mismatch"
455	}
456	for i, val := range one {
457		if val != two[i] {
458			return "Index " + strconv.Itoa(i) + " mismatch"
459		}
460	}
461	return ""
462}
463
464func TestFind(t *testing.T) {
465	s := []complex128{3 + 1i, 4 - 1i, 1 + 2i, 7 + 10i, 5 - 100i}
466	f := func(v complex128) bool { return cmplx.Abs(v) > 3.5 }
467	allTrueInds := []int{1, 3, 4}
468
469	// Test finding first two elements
470	inds, err := Find(nil, f, s, 2)
471	if err != nil {
472		t.Errorf("Find first two: Improper error return")
473	}
474	trueInds := allTrueInds[:2]
475	str := eqIntSlice(inds, trueInds)
476	if str != "" {
477		t.Errorf("Find first two: " + str)
478	}
479
480	// Test finding no elements with non nil slice
481	inds = []int{1, 2, 3, 4, 5, 6}
482	inds, err = Find(inds, f, s, 0)
483	if err != nil {
484		t.Errorf("Find no elements: Improper error return")
485	}
486	str = eqIntSlice(inds, []int{})
487	if str != "" {
488		t.Errorf("Find no non-nil: " + str)
489	}
490
491	// Test finding first two elements with non nil slice
492	inds = []int{1, 2, 3, 4, 5, 6}
493	inds, err = Find(inds, f, s, 2)
494	if err != nil {
495		t.Errorf("Find first two non-nil: Improper error return")
496	}
497	str = eqIntSlice(inds, trueInds)
498	if str != "" {
499		t.Errorf("Find first two non-nil: " + str)
500	}
501
502	// Test finding too many elements
503	inds, err = Find(inds, f, s, 4)
504	if err == nil {
505		t.Errorf("Request too many: No error returned")
506	}
507	str = eqIntSlice(inds, allTrueInds)
508	if str != "" {
509		t.Errorf("Request too many: Does not match all of the inds: " + str)
510	}
511
512	// Test finding all elements
513	inds, err = Find(nil, f, s, -1)
514	if err != nil {
515		t.Errorf("Find all: Improper error returned")
516	}
517	str = eqIntSlice(inds, allTrueInds)
518	if str != "" {
519		t.Errorf("Find all: Does not match all of the inds: " + str)
520	}
521}
522
523func TestHasNaN(t *testing.T) {
524	for i, test := range []struct {
525		s   []complex128
526		ans bool
527	}{
528		{},
529		{
530			s: []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i},
531		},
532		{
533			s:   []complex128{1 + 1i, cmplx.NaN(), 3 + 3i, 4 + 4i},
534			ans: true,
535		},
536		{
537			s:   []complex128{1 + 1i, 2 + 2i, 3 + 3i, cmplx.NaN()},
538			ans: true,
539		},
540	} {
541		b := HasNaN(test.s)
542		if b != test.ans {
543			t.Errorf("HasNaN mismatch case %d. Expected %v, Found %v", i, test.ans, b)
544		}
545	}
546}
547
548func TestImag(t *testing.T) {
549	for i, test := range []struct {
550		dst    []float64
551		src    []complex128
552		want   []float64
553		panics bool
554	}{
555		{},
556		{
557			dst:  make([]float64, 4),
558			src:  []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i},
559			want: []float64{1, 2, 3, 4},
560		},
561		{
562			dst:    make([]float64, 3),
563			src:    []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i},
564			panics: true,
565		},
566		{
567			dst:  make([]float64, 4),
568			src:  []complex128{1 + 1i, 2 + 2i, 3 + 3i, cmplx.NaN()},
569			want: []float64{1, 2, 3, math.NaN()},
570		},
571	} {
572		var got []float64
573		panicked := Panics(func() {
574			got = Imag(test.dst, test.src)
575		})
576		if panicked != test.panics {
577			if panicked {
578				t.Errorf("unexpected panic for test %d", i)
579			} else {
580				t.Errorf("expected panic for test %d", i)
581			}
582		}
583		if panicked || test.panics {
584			continue
585		}
586		if !floats.Same(got, test.dst) {
587			t.Errorf("mismatch between dst and return test %d: got:%v want:%v", i, got, test.dst)
588		}
589		if !floats.Same(got, test.want) {
590			t.Errorf("unexpected result for test %d: got:%v want:%v", i, got, test.want)
591		}
592	}
593
594}
595
596func TestLogSpan(t *testing.T) {
597	// FIXME(kortschak)
598	receiver1 := make([]complex128, 6)
599	truth := []complex128{0.001, 0.01, 0.1, 1, 10, 100}
600	receiver2 := LogSpan(receiver1, 0.001, 100)
601	tst := make([]complex128, 6)
602	for i := range truth {
603		tst[i] = receiver1[i] / truth[i]
604	}
605	comp := make([]complex128, 6)
606	for i := range comp {
607		comp[i] = 1
608	}
609	areSlicesEqual(t, comp, tst, "Improper logspace from mutator")
610
611	for i := range truth {
612		tst[i] = receiver2[i] / truth[i]
613	}
614	areSlicesEqual(t, comp, tst, "Improper logspace from returned slice")
615
616	if !Panics(func() { LogSpan(nil, 1, 5) }) {
617		t.Errorf("Span accepts nil argument")
618	}
619	if !Panics(func() { LogSpan(make([]complex128, 1), 1, 5) }) {
620		t.Errorf("Span accepts argument of len = 1")
621	}
622}
623
624func TestMaxAbsAndIdx(t *testing.T) {
625	for _, test := range []struct {
626		in      []complex128
627		wantIdx int
628		wantVal complex128
629		desc    string
630	}{
631		{
632			in:      []complex128{3 + 1i, 4 + 1i, 1 + 1i, 7 + 1i, 5 + 1i},
633			wantIdx: 3,
634			wantVal: 7 + 1i,
635			desc:    "with only finite entries",
636		},
637		{
638			in:      []complex128{cmplx.NaN(), 4 + 1i, 1 + 1i, 7 + 1i, 5 + 1i},
639			wantIdx: 3,
640			wantVal: 7 + 1i,
641			desc:    "with leading NaN",
642		},
643		{
644			in:      []complex128{cmplx.NaN(), cmplx.NaN(), cmplx.NaN()},
645			wantIdx: 0,
646			wantVal: cmplx.NaN(),
647			desc:    "when only NaN elements exist",
648		},
649		{
650			in:      []complex128{cmplx.NaN(), cmplx.Inf()},
651			wantIdx: 1,
652			wantVal: cmplx.Inf(),
653			desc:    "leading NaN followed by Inf",
654		},
655	} {
656		ind := MaxAbsIdx(test.in)
657		if ind != test.wantIdx {
658			t.Errorf("Wrong index "+test.desc+": got:%d want:%d", ind, test.wantIdx)
659		}
660		val := MaxAbs(test.in)
661		if !cscalar.Same(val, test.wantVal) {
662			t.Errorf("Wrong value "+test.desc+": got:%f want:%f", val, test.wantVal)
663		}
664	}
665}
666
667func TestMinAbsAndIdx(t *testing.T) {
668	for _, test := range []struct {
669		in      []complex128
670		wantIdx int
671		wantVal complex128
672		desc    string
673	}{
674		{
675			in:      []complex128{3 + 1i, 4 + 1i, 1 + 1i, 7 + 1i, 5 + 1i},
676			wantIdx: 2,
677			wantVal: 1 + 1i,
678			desc:    "with only finite entries",
679		},
680		{
681			in:      []complex128{cmplx.NaN(), 4 + 1i, 1 + 1i, 7 + 1i, 5 + 1i},
682			wantIdx: 2,
683			wantVal: 1 + 1i,
684			desc:    "with leading NaN",
685		},
686		{
687			in:      []complex128{cmplx.NaN(), cmplx.NaN(), cmplx.NaN()},
688			wantIdx: 0,
689			wantVal: cmplx.NaN(),
690			desc:    "when only NaN elements exist",
691		},
692		{
693			in:      []complex128{cmplx.NaN(), cmplx.Inf()},
694			wantIdx: 1,
695			wantVal: cmplx.Inf(),
696			desc:    "leading NaN followed by Inf",
697		},
698	} {
699		ind := MinAbsIdx(test.in)
700		if ind != test.wantIdx {
701			t.Errorf("Wrong index "+test.desc+": got:%d want:%d", ind, test.wantIdx)
702		}
703		val := MinAbs(test.in)
704		if !cscalar.Same(val, test.wantVal) {
705			t.Errorf("Wrong value "+test.desc+": got:%f want:%f", val, test.wantVal)
706		}
707	}
708}
709
710func TestMul(t *testing.T) {
711	s1 := []complex128{1 + 1i, 2 + 2i, 3 + 3i}
712	s2 := []complex128{1 + 1i, 2 + 2i, 3 + 3i}
713	ans := []complex128{0 + 2i, 0 + 8i, 0 + 18i}
714	Mul(s1, s2)
715	if !EqualApprox(s1, ans, EqTolerance) {
716		t.Errorf("Mul doesn't give correct answer. Expected %v, Found %v", ans, s1)
717	}
718	s1short := []complex128{1}
719	if !Panics(func() { Mul(s1short, s2) }) {
720		t.Errorf("Did not panic with unequal lengths")
721	}
722	s2short := []complex128{1}
723	if !Panics(func() { Mul(s1, s2short) }) {
724		t.Errorf("Did not panic with unequal lengths")
725	}
726}
727
728func TestMulTo(t *testing.T) {
729	s1 := []complex128{1 + 1i, 2 + 2i, 3 + 3i}
730	s1orig := []complex128{1 + 1i, 2 + 2i, 3 + 3i}
731	s2 := []complex128{1 + 1i, 2 + 2i, 3 + 3i}
732	s2orig := []complex128{1 + 1i, 2 + 2i, 3 + 3i}
733	dst1 := make([]complex128, 3)
734	ans := []complex128{0 + 2i, 0 + 8i, 0 + 18i}
735	dst2 := MulTo(dst1, s1, s2)
736	if !EqualApprox(dst1, ans, EqTolerance) {
737		t.Errorf("MulTo doesn't give correct answer in mutated slice")
738	}
739	if !EqualApprox(dst2, ans, EqTolerance) {
740		t.Errorf("MulTo doesn't give correct answer in returned slice")
741	}
742	if !EqualApprox(s1, s1orig, EqTolerance) {
743		t.Errorf("S1 changes during multo")
744	}
745	if !EqualApprox(s2, s2orig, EqTolerance) {
746		t.Errorf("s2 changes during multo")
747	}
748	MulTo(dst1, s1, s2)
749	if !EqualApprox(dst1, ans, EqTolerance) {
750		t.Errorf("MulTo doesn't give correct answer reusing dst")
751	}
752	dstShort := []complex128{1}
753	if !Panics(func() { MulTo(dstShort, s1, s2) }) {
754		t.Errorf("Did not panic with s1 wrong length")
755	}
756	s1short := []complex128{1}
757	if !Panics(func() { MulTo(dst1, s1short, s2) }) {
758		t.Errorf("Did not panic with s1 wrong length")
759	}
760	s2short := []complex128{1}
761	if !Panics(func() { MulTo(dst1, s1, s2short) }) {
762		t.Errorf("Did not panic with s2 wrong length")
763	}
764}
765
766// Complexify
767
768func TestNearestIdx(t *testing.T) {
769	for _, test := range []struct {
770		in    []complex128
771		query complex128
772		want  int
773		desc  string
774	}{
775		{
776			in:    []complex128{6.2, 3, 5, 6.2, 8},
777			query: 2,
778			want:  1,
779			desc:  "Wrong index returned when value is less than all of elements",
780		},
781		{
782			in:    []complex128{6.2, 3, 5, 6.2, 8},
783			query: 9,
784			want:  4,
785			desc:  "Wrong index returned when value is greater than all of elements",
786		},
787		{
788			in:    []complex128{6.2, 3, 5, 6.2, 8},
789			query: 3.1,
790			want:  1,
791			desc:  "Wrong index returned when value is greater than closest element",
792		},
793		{
794			in:    []complex128{6.2, 3, 5, 6.2, 8},
795			query: 2.9,
796			want:  1,
797			desc:  "Wrong index returned when value is less than closest element",
798		},
799		{
800			in:    []complex128{6.2, 3, 5, 6.2, 8},
801			query: 3,
802			want:  1,
803			desc:  "Wrong index returned when value is equal to element",
804		},
805		{
806			in:    []complex128{6.2, 3, 5, 6.2, 8},
807			query: 6.2,
808			want:  0,
809			desc:  "Wrong index returned when value is equal to several elements",
810		},
811		{
812			in:    []complex128{6.2, 3, 5, 6.2, 8},
813			query: 4,
814			want:  1,
815			desc:  "Wrong index returned when value is exactly between two closest elements",
816		},
817		{
818			in:    []complex128{cmplx.NaN(), 3, 2, -1},
819			query: 2,
820			want:  2,
821			desc:  "Wrong index returned when initial element is NaN",
822		},
823		{
824			in:    []complex128{0, cmplx.NaN(), -1, 2},
825			query: cmplx.NaN(),
826			want:  0,
827			desc:  "Wrong index returned when query is NaN and a NaN element exists",
828		},
829		{
830			in:    []complex128{0, cmplx.NaN(), -1, 2},
831			query: cmplx.Inf(),
832			want:  3,
833			desc:  "Wrong index returned when query is Inf and no Inf element exists",
834		},
835		{
836			in:    []complex128{cmplx.NaN(), cmplx.NaN(), cmplx.NaN()},
837			query: 1,
838			want:  0,
839			desc:  "Wrong index returned when query is a number and only NaN elements exist",
840		},
841		{
842			in:    []complex128{cmplx.NaN(), cmplx.Inf()},
843			query: 1,
844			want:  1,
845			desc:  "Wrong index returned when query is a number and single NaN precedes Inf",
846		},
847	} {
848		ind := NearestIdx(test.in, test.query)
849		if ind != test.want {
850			t.Errorf(test.desc+": got:%d want:%d", ind, test.want)
851		}
852	}
853}
854
855func TestNorm(t *testing.T) {
856	s := []complex128{-1, -3.4, 5, -6}
857	val := Norm(s, math.Inf(1))
858	truth := 6.0
859	if math.Abs(val-truth) > EqTolerance {
860		t.Errorf("Doesn't match for inf norm. %v expected, %v found", truth, val)
861	}
862	// http://www.wolframalpha.com/input/?i=%28%28-1%29%5E2+%2B++%28-3.4%29%5E2+%2B+5%5E2%2B++6%5E2%29%5E%281%2F2%29
863	val = Norm(s, 2)
864	truth = 8.5767126569566267590651614132751986658027271236078592
865	if math.Abs(val-truth) > EqTolerance {
866		t.Errorf("Doesn't match for inf norm. %v expected, %v found", truth, val)
867	}
868	// http://www.wolframalpha.com/input/?i=%28%28%7C-1%7C%29%5E3+%2B++%28%7C-3.4%7C%29%5E3+%2B+%7C5%7C%5E3%2B++%7C6%7C%5E3%29%5E%281%2F3%29
869	val = Norm(s, 3)
870	truth = 7.2514321388020228478109121239004816430071237369356233
871	if math.Abs(val-truth) > EqTolerance {
872		t.Errorf("Doesn't match for inf norm. %v expected, %v found", truth, val)
873	}
874
875	//http://www.wolframalpha.com/input/?i=%7C-1%7C+%2B+%7C-3.4%7C+%2B+%7C5%7C%2B++%7C6%7C
876	val = Norm(s, 1)
877	truth = 15.4
878	if math.Abs(val-truth) > EqTolerance {
879		t.Errorf("Doesn't match for inf norm. %v expected, %v found", truth, val)
880	}
881}
882
883func TestProd(t *testing.T) {
884	s := []complex128{}
885	val := Prod(s)
886	if val != 1 {
887		t.Errorf("Val not returned as default when slice length is zero")
888	}
889	s = []complex128{3, 4, 1, 7, 5}
890	val = Prod(s)
891	if val != 420 {
892		t.Errorf("Wrong prod returned. Expected %v returned %v", 420, val)
893	}
894}
895
896func TestReverse(t *testing.T) {
897	for _, s := range [][]complex128{
898		{0},
899		{1, 0},
900		{2, 1, 0},
901		{3, 2, 1, 0},
902		{9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
903	} {
904		Reverse(s)
905		for i, v := range s {
906			if v != complex(float64(i), 0) {
907				t.Errorf("unexpected values for element %d: got:%v want:%v", i, v, i)
908			}
909		}
910	}
911}
912
913func TestReal(t *testing.T) {
914	for i, test := range []struct {
915		dst    []float64
916		src    []complex128
917		want   []float64
918		panics bool
919	}{
920		{},
921		{
922			dst:  make([]float64, 4),
923			src:  []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i},
924			want: []float64{1, 2, 3, 4},
925		},
926		{
927			dst:    make([]float64, 3),
928			src:    []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i},
929			panics: true,
930		},
931		{
932			dst:  make([]float64, 4),
933			src:  []complex128{1 + 1i, 2 + 2i, 3 + 3i, cmplx.NaN()},
934			want: []float64{1, 2, 3, math.NaN()},
935		},
936	} {
937		var got []float64
938		panicked := Panics(func() {
939			got = Real(test.dst, test.src)
940		})
941		if panicked != test.panics {
942			if panicked {
943				t.Errorf("unexpected panic for test %d", i)
944			} else {
945				t.Errorf("expected panic for test %d", i)
946			}
947		}
948		if panicked || test.panics {
949			continue
950		}
951		if !floats.Same(got, test.dst) {
952			t.Errorf("mismatch between dst and return test %d: got:%v want:%v", i, got, test.dst)
953		}
954		if !floats.Same(got, test.want) {
955			t.Errorf("unexpected result for test %d: got:%v want:%v", i, got, test.want)
956		}
957	}
958
959}
960func TestSame(t *testing.T) {
961	s1 := []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i}
962	s2 := []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i}
963	if !Same(s1, s2) {
964		t.Errorf("Equal slices returned as unequal")
965	}
966	s2 = []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i + 1e-14}
967	if Same(s1, s2) {
968		t.Errorf("Unequal slices returned as equal")
969	}
970	if Same(s1, []complex128{}) {
971		t.Errorf("Unequal slice lengths returned as equal")
972	}
973	s1 = []complex128{1 + 1i, 2 + 2i, cmplx.NaN(), 4 + 4i}
974	s2 = []complex128{1 + 1i, 2 + 2i, cmplx.NaN(), 4 + 4i}
975	if !Same(s1, s2) {
976		t.Errorf("Slices with matching NaN values returned as unequal")
977	}
978	s1 = []complex128{1 + 1i, 2 + 2i, cmplx.NaN(), 4 + 4i}
979	s2 = []complex128{1 + 1i, cmplx.NaN(), 3 + 3i, 4 + 4i}
980	if Same(s1, s2) {
981		t.Errorf("Slices with unmatching NaN values returned as equal")
982	}
983}
984
985func TestScale(t *testing.T) {
986	s := []complex128{3, 4, 1, 7, 5}
987	c := 5 + 5i
988	truth := []complex128{15 + 15i, 20 + 20i, 5 + 5i, 35 + 35i, 25 + 25i}
989	Scale(c, s)
990	areSlicesEqual(t, truth, s, "Bad scaling")
991}
992
993func TestScaleTo(t *testing.T) {
994	s := []complex128{3, 4, 1, 7, 5}
995	sCopy := make([]complex128, len(s))
996	copy(sCopy, s)
997	c := 5 + 5i
998	truth := []complex128{15 + 15i, 20 + 20i, 5 + 5i, 35 + 35i, 25 + 25i}
999	dst := make([]complex128, len(s))
1000	ScaleTo(dst, c, s)
1001	if !Same(dst, truth) {
1002		t.Errorf("Scale to does not match. Got %v, want %v", dst, truth)
1003	}
1004	if !Same(s, sCopy) {
1005		t.Errorf("Source modified during call. Got %v, want %v", s, sCopy)
1006	}
1007}
1008
1009func TestSpan(t *testing.T) {
1010	receiver1 := make([]complex128, 5)
1011	truth := []complex128{1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i, 5 + 5i}
1012	receiver2 := Span(receiver1, 1+1i, 5+5i)
1013	areSlicesEqual(t, truth, receiver1, "Improper linspace from mutator")
1014	areSlicesEqual(t, truth, receiver2, "Improper linspace from returned slice")
1015	receiver1 = make([]complex128, 6)
1016	truth = []complex128{0, 0.2 + 0.4i, 0.4 + 0.8i, 0.6 + 1.2i, 0.8 + 1.6i, 1 + 2i}
1017	Span(receiver1, 0, 1+2i)
1018	areSlicesEqual(t, truth, receiver1, "Improper linspace")
1019	if !Panics(func() { Span(nil, 1, 5) }) {
1020		t.Errorf("Span accepts nil argument")
1021	}
1022	if !Panics(func() { Span(make([]complex128, 1), 1, 5) }) {
1023		t.Errorf("Span accepts argument of len = 1")
1024	}
1025
1026	for _, test := range []struct {
1027		n    int
1028		l, u complex128
1029		want []complex128
1030	}{
1031		{
1032			n: 5, l: cmplx.Inf(), u: cmplx.Inf(),
1033			want: []complex128{cmplx.Inf(), cmplx.Inf(), cmplx.Inf(), cmplx.Inf(), cmplx.Inf()},
1034		},
1035		{
1036			n: 5, l: cmplx.Inf(), u: cmplx.NaN(),
1037			want: []complex128{cmplx.Inf(), cmplx.NaN(), cmplx.NaN(), cmplx.NaN(), cmplx.NaN()},
1038		},
1039		{
1040			n: 5, l: cmplx.NaN(), u: cmplx.Inf(),
1041			want: []complex128{cmplx.NaN(), cmplx.NaN(), cmplx.NaN(), cmplx.NaN(), cmplx.Inf()},
1042		},
1043		{
1044			n: 5, l: 42, u: cmplx.Inf(),
1045			want: []complex128{42, cmplx.Inf(), cmplx.Inf(), cmplx.Inf(), cmplx.Inf()},
1046		},
1047		{
1048			n: 5, l: 42, u: cmplx.NaN(),
1049			want: []complex128{42, cmplx.NaN(), cmplx.NaN(), cmplx.NaN(), cmplx.NaN()},
1050		},
1051		{
1052			n: 5, l: cmplx.Inf(), u: 42,
1053			want: []complex128{cmplx.Inf(), cmplx.Inf(), cmplx.Inf(), cmplx.Inf(), 42},
1054		},
1055		{
1056			n: 5, l: cmplx.NaN(), u: 42,
1057			want: []complex128{cmplx.NaN(), cmplx.NaN(), cmplx.NaN(), cmplx.NaN(), 42},
1058		},
1059	} {
1060		got := Span(make([]complex128, test.n), test.l, test.u)
1061		areSlicesSame(t, test.want, got,
1062			fmt.Sprintf("Unexpected slice of length %d for %f to %f", test.n, test.l, test.u))
1063	}
1064}
1065
1066func TestSub(t *testing.T) {
1067	s := []complex128{3 + 2i, 4 + 3i, 1 + 7i, 7 + 1i, 5 - 1i}
1068	v := []complex128{1 + 1i, 2 + 4i, 3, 4, 5 - 1i}
1069	truth := []complex128{2 + 1i, 2 - 1i, -2 + 7i, 3 + 1i, 0}
1070	Sub(s, v)
1071	areSlicesEqual(t, truth, s, "Bad subtract")
1072	// Test that it panics
1073	if !Panics(func() { Sub(make([]complex128, 2), make([]complex128, 3)) }) {
1074		t.Errorf("Did not panic with length mismatch")
1075	}
1076}
1077
1078func TestSubTo(t *testing.T) {
1079	s := []complex128{3 + 2i, 4 + 3i, 1 + 7i, 7 + 1i, 5 - 1i}
1080	v := []complex128{1 + 1i, 2 + 4i, 3, 4, 5 - 1i}
1081	truth := []complex128{2 + 1i, 2 - 1i, -2 + 7i, 3 + 1i, 0}
1082	dst1 := make([]complex128, len(s))
1083	dst2 := SubTo(dst1, s, v)
1084	areSlicesEqual(t, truth, dst1, "Bad subtract from mutator")
1085	areSlicesEqual(t, truth, dst2, "Bad subtract from returned slice")
1086	// Test that all mismatch combinations panic
1087	if !Panics(func() { SubTo(make([]complex128, 2), make([]complex128, 3), make([]complex128, 3)) }) {
1088		t.Errorf("Did not panic with dst different length")
1089	}
1090	if !Panics(func() { SubTo(make([]complex128, 3), make([]complex128, 2), make([]complex128, 3)) }) {
1091		t.Errorf("Did not panic with subtractor different length")
1092	}
1093	if !Panics(func() { SubTo(make([]complex128, 3), make([]complex128, 3), make([]complex128, 2)) }) {
1094		t.Errorf("Did not panic with subtractee different length")
1095	}
1096}
1097
1098func TestSum(t *testing.T) {
1099	s := []complex128{}
1100	val := Sum(s)
1101	if val != 0 {
1102		t.Errorf("Val not returned as default when slice length is zero")
1103	}
1104	s = []complex128{3 + 1i, 4 + 2i, 1 + 3i, 7 + 4i, 5 + 5i}
1105	val = Sum(s)
1106	if val != 20+15i {
1107		t.Errorf("Wrong sum returned")
1108	}
1109}
1110
1111func randomSlice(l int, src rand.Source) []complex128 {
1112	rnd := rand.New(src)
1113	s := make([]complex128, l)
1114	for i := range s {
1115		s[i] = complex(rnd.Float64(), rnd.Float64())
1116	}
1117	return s
1118}
1119
1120func benchmarkAdd(b *testing.B, size int) {
1121	src := rand.NewSource(1)
1122	s1 := randomSlice(size, src)
1123	s2 := randomSlice(size, src)
1124	b.ResetTimer()
1125	for i := 0; i < b.N; i++ {
1126		Add(s1, s2)
1127	}
1128}
1129func BenchmarkAddSmall(b *testing.B) { benchmarkAdd(b, Small) }
1130func BenchmarkAddMed(b *testing.B)   { benchmarkAdd(b, Medium) }
1131func BenchmarkAddLarge(b *testing.B) { benchmarkAdd(b, Large) }
1132func BenchmarkAddHuge(b *testing.B)  { benchmarkAdd(b, Huge) }
1133
1134func benchmarkAddTo(b *testing.B, size int) {
1135	src := rand.NewSource(1)
1136	s1 := randomSlice(size, src)
1137	s2 := randomSlice(size, src)
1138	dst := randomSlice(size, src)
1139	b.ResetTimer()
1140	for i := 0; i < b.N; i++ {
1141		AddTo(dst, s1, s2)
1142	}
1143}
1144func BenchmarkAddToSmall(b *testing.B) { benchmarkAddTo(b, Small) }
1145func BenchmarkAddToMed(b *testing.B)   { benchmarkAddTo(b, Medium) }
1146func BenchmarkAddToLarge(b *testing.B) { benchmarkAddTo(b, Large) }
1147func BenchmarkAddToHuge(b *testing.B)  { benchmarkAddTo(b, Huge) }
1148
1149func benchmarkCumProd(b *testing.B, size int) {
1150	src := rand.NewSource(1)
1151	s := randomSlice(size, src)
1152	dst := randomSlice(size, src)
1153	b.ResetTimer()
1154	for i := 0; i < b.N; i++ {
1155		CumProd(dst, s)
1156	}
1157}
1158func BenchmarkCumProdSmall(b *testing.B) { benchmarkCumProd(b, Small) }
1159func BenchmarkCumProdMed(b *testing.B)   { benchmarkCumProd(b, Medium) }
1160func BenchmarkCumProdLarge(b *testing.B) { benchmarkCumProd(b, Large) }
1161func BenchmarkCumProdHuge(b *testing.B)  { benchmarkCumProd(b, Huge) }
1162
1163func benchmarkCumSum(b *testing.B, size int) {
1164	src := rand.NewSource(1)
1165	s := randomSlice(size, src)
1166	dst := randomSlice(size, src)
1167	b.ResetTimer()
1168	for i := 0; i < b.N; i++ {
1169		CumSum(dst, s)
1170	}
1171}
1172func BenchmarkCumSumSmall(b *testing.B) { benchmarkCumSum(b, Small) }
1173func BenchmarkCumSumMed(b *testing.B)   { benchmarkCumSum(b, Medium) }
1174func BenchmarkCumSumLarge(b *testing.B) { benchmarkCumSum(b, Large) }
1175func BenchmarkCumSumHuge(b *testing.B)  { benchmarkCumSum(b, Huge) }
1176
1177func benchmarkDiv(b *testing.B, size int) {
1178	src := rand.NewSource(1)
1179	s := randomSlice(size, src)
1180	dst := randomSlice(size, src)
1181	b.ResetTimer()
1182	for i := 0; i < b.N; i++ {
1183		Div(dst, s)
1184	}
1185}
1186func BenchmarkDivSmall(b *testing.B) { benchmarkDiv(b, Small) }
1187func BenchmarkDivMed(b *testing.B)   { benchmarkDiv(b, Medium) }
1188func BenchmarkDivLarge(b *testing.B) { benchmarkDiv(b, Large) }
1189func BenchmarkDivHuge(b *testing.B)  { benchmarkDiv(b, Huge) }
1190
1191func benchmarkDivTo(b *testing.B, size int) {
1192	src := rand.NewSource(1)
1193	s1 := randomSlice(size, src)
1194	s2 := randomSlice(size, src)
1195	dst := randomSlice(size, src)
1196	b.ResetTimer()
1197	for i := 0; i < b.N; i++ {
1198		DivTo(dst, s1, s2)
1199	}
1200}
1201func BenchmarkDivToSmall(b *testing.B) { benchmarkDivTo(b, Small) }
1202func BenchmarkDivToMed(b *testing.B)   { benchmarkDivTo(b, Medium) }
1203func BenchmarkDivToLarge(b *testing.B) { benchmarkDivTo(b, Large) }
1204func BenchmarkDivToHuge(b *testing.B)  { benchmarkDivTo(b, Huge) }
1205
1206func benchmarkSub(b *testing.B, size int) {
1207	src := rand.NewSource(1)
1208	s1 := randomSlice(size, src)
1209	s2 := randomSlice(size, src)
1210	b.ResetTimer()
1211	for i := 0; i < b.N; i++ {
1212		Sub(s1, s2)
1213	}
1214}
1215func BenchmarkSubSmall(b *testing.B) { benchmarkSub(b, Small) }
1216func BenchmarkSubMed(b *testing.B)   { benchmarkSub(b, Medium) }
1217func BenchmarkSubLarge(b *testing.B) { benchmarkSub(b, Large) }
1218func BenchmarkSubHuge(b *testing.B)  { benchmarkSub(b, Huge) }
1219
1220func benchmarkSubTo(b *testing.B, size int) {
1221	src := rand.NewSource(1)
1222	s1 := randomSlice(size, src)
1223	s2 := randomSlice(size, src)
1224	dst := randomSlice(size, src)
1225	b.ResetTimer()
1226	for i := 0; i < b.N; i++ {
1227		SubTo(dst, s1, s2)
1228	}
1229}
1230func BenchmarkSubToSmall(b *testing.B) { benchmarkSubTo(b, Small) }
1231func BenchmarkSubToMed(b *testing.B)   { benchmarkSubTo(b, Medium) }
1232func BenchmarkSubToLarge(b *testing.B) { benchmarkSubTo(b, Large) }
1233func BenchmarkSubToHuge(b *testing.B)  { benchmarkSubTo(b, Huge) }
1234
1235func benchmarkDot(b *testing.B, size int) {
1236	src := rand.NewSource(1)
1237	s1 := randomSlice(size, src)
1238	s2 := randomSlice(size, src)
1239	b.ResetTimer()
1240	for i := 0; i < b.N; i++ {
1241		Dot(s1, s2)
1242	}
1243}
1244func BenchmarkDotSmall(b *testing.B) { benchmarkDot(b, Small) }
1245func BenchmarkDotMed(b *testing.B)   { benchmarkDot(b, Medium) }
1246func BenchmarkDotLarge(b *testing.B) { benchmarkDot(b, Large) }
1247func BenchmarkDotHuge(b *testing.B)  { benchmarkDot(b, Huge) }
1248
1249func benchmarkAddScaledTo(b *testing.B, size int) {
1250	src := rand.NewSource(1)
1251	dst := randomSlice(size, src)
1252	y := randomSlice(size, src)
1253	s := randomSlice(size, src)
1254	b.ResetTimer()
1255	for i := 0; i < b.N; i++ {
1256		AddScaledTo(dst, y, 2.3, s)
1257	}
1258}
1259func BenchmarkAddScaledToSmall(b *testing.B)  { benchmarkAddScaledTo(b, Small) }
1260func BenchmarkAddScaledToMedium(b *testing.B) { benchmarkAddScaledTo(b, Medium) }
1261func BenchmarkAddScaledToLarge(b *testing.B)  { benchmarkAddScaledTo(b, Large) }
1262func BenchmarkAddScaledToHuge(b *testing.B)   { benchmarkAddScaledTo(b, Huge) }
1263
1264func benchmarkScale(b *testing.B, size int) {
1265	src := rand.NewSource(1)
1266	dst := randomSlice(size, src)
1267	b.ResetTimer()
1268	for i := 0; i < b.N; i += 2 {
1269		Scale(2.0, dst)
1270		Scale(0.5, dst)
1271	}
1272}
1273func BenchmarkScaleSmall(b *testing.B)  { benchmarkScale(b, Small) }
1274func BenchmarkScaleMedium(b *testing.B) { benchmarkScale(b, Medium) }
1275func BenchmarkScaleLarge(b *testing.B)  { benchmarkScale(b, Large) }
1276func BenchmarkScaleHuge(b *testing.B)   { benchmarkScale(b, Huge) }
1277
1278func benchmarkNorm2(b *testing.B, size int) {
1279	src := rand.NewSource(1)
1280	s := randomSlice(size, src)
1281	b.ResetTimer()
1282	for i := 0; i < b.N; i++ {
1283		Norm(s, 2)
1284	}
1285}
1286func BenchmarkNorm2Small(b *testing.B)  { benchmarkNorm2(b, Small) }
1287func BenchmarkNorm2Medium(b *testing.B) { benchmarkNorm2(b, Medium) }
1288func BenchmarkNorm2Large(b *testing.B)  { benchmarkNorm2(b, Large) }
1289func BenchmarkNorm2Huge(b *testing.B)   { benchmarkNorm2(b, Huge) }
1290