Repository: gonum/gonum
Pull request #1627 (2021-05-12 08:27:38)

cmplxs: add conjugate multiplies and real scales
Please take a look.

<!--
Checklist:

- API changes have been discussed
- code is goformated correctly (goimports)
- packages with generated code have had code generation run
- tests pass locally
- linked to relevant issues

Please make sure your commit message summary line and pull request
title match the Go convention; a one-line summary of the change,
prefixed by the primary affected package that should complete the
sentence, "This change modifies Gonum to _____."
-->


codecov-commenter: # [Codecov](https://codecov.io/gh/gonum/gonum/pull/1627?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum) Report
> Merging [#1627](https://codecov.io/gh/gonum/gonum/pull/1627?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum) (d6a0ef8) into [master](https://codecov.io/gh/gonum/gonum/commit/674d3f1c732ceb32379dd0658314ab5131af5fd5?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum) (674d3f1) will **decrease** coverage by `0.07%`.
> The diff coverage is `85.71%`.

> :exclamation: Current head d6a0ef8 differs from pull request most recent head f318e1a. Consider uploading reports for the commit f318e1a to get more accurate results
[![Impacted file tree graph](https://codecov.io/gh/gonum/gonum/pull/1627/graphs/tree.svg?width=650&height=150&src=pr&token=B7qHnqSPNL&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum)](https://codecov.io/gh/gonum/gonum/pull/1627?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum)

```diff
@@            Coverage Diff             @@
##           master    #1627      +/-   ##
==========================================
- Coverage   73.24%   73.16%   -0.08%     
==========================================
  Files         503      498       -5     
  Lines       59592    59351     -241     
==========================================
- Hits        43648    43427     -221     
+ Misses      13489    13478      -11     
+ Partials     2455     2446       -9     
```


| [Impacted Files](https://codecov.io/gh/gonum/gonum/pull/1627?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum) | Coverage Δ | |
|---|---|---|
| [cmplxs/cmplxs.go](https://codecov.io/gh/gonum/gonum/pull/1627/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum#diff-Y21wbHhzL2NtcGx4cy5nbw==) | `94.92% <85.71%> (-0.54%)` | :arrow_down: |
| [mat/matrix.go](https://codecov.io/gh/gonum/gonum/pull/1627/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum#diff-bWF0L21hdHJpeC5nbw==) | `79.13% <0.00%> (-2.05%)` | :arrow_down: |
| [mat/tridiag.go](https://codecov.io/gh/gonum/gonum/pull/1627/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum#diff-bWF0L3RyaWRpYWcuZ28=) | `88.77% <0.00%> (-0.96%)` | :arrow_down: |
| [mat/vector.go](https://codecov.io/gh/gonum/gonum/pull/1627/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum#diff-bWF0L3ZlY3Rvci5nbw==) | `78.81% <0.00%> (-0.39%)` | :arrow_down: |
| [mat/dense.go](https://codecov.io/gh/gonum/gonum/pull/1627/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum#diff-bWF0L2RlbnNlLmdv) | `83.92% <0.00%> (-0.27%)` | :arrow_down: |
| [mat/triangular.go](https://codecov.io/gh/gonum/gonum/pull/1627/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum#diff-bWF0L3RyaWFuZ3VsYXIuZ28=) | `81.10% <0.00%> (-0.17%)` | :arrow_down: |
| [mat/symmetric.go](https://codecov.io/gh/gonum/gonum/pull/1627/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum#diff-bWF0L3N5bW1ldHJpYy5nbw==) | `79.74% <0.00%> (-0.13%)` | :arrow_down: |
| [mat/index\_bound\_checks.go](https://codecov.io/gh/gonum/gonum/pull/1627/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum#diff-bWF0L2luZGV4X2JvdW5kX2NoZWNrcy5nbw==) | | |
| [mat/offset\_appengine.go](https://codecov.io/gh/gonum/gonum/pull/1627/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum#diff-bWF0L29mZnNldF9hcHBlbmdpbmUuZ28=) | | |
| [graph/internal/set/same\_appengine.go](https://codecov.io/gh/gonum/gonum/pull/1627/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum#diff-Z3JhcGgvaW50ZXJuYWwvc2V0L3NhbWVfYXBwZW5naW5lLmdv) | | |
| ... and [5 more](https://codecov.io/gh/gonum/gonum/pull/1627/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/gonum/gonum/pull/1627?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/gonum/gonum/pull/1627?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum). Last update [674d3f1...f318e1a](https://codecov.io/gh/gonum/gonum/pull/1627?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gonum).

kortschak: PTAL

Patch:
diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml
index 70c0ef53..3c9b468c 100644
--- a/.github/workflows/codecov.yml
+++ b/.github/workflows/codecov.yml
@@ -63,6 +63,5 @@ jobs:
       if: matrix.platform == 'ubuntu-latest'
       uses: codecov/codecov-action@v1
       with:
-        override_pr: ${{ github.event.pull_request.number }}
         override_commit: ${{ github.event.pull_request.merge_commit_sha }}
         override_branch: "master"
diff --git a/cmplxs/cmplxs.go b/cmplxs/cmplxs.go
index 91a66948..f03c9de7 100644
--- a/cmplxs/cmplxs.go
+++ b/cmplxs/cmplxs.go
@@ -424,6 +424,34 @@ func Mul(dst, s []complex128) {
 	}
 }
 
+// MulConj performs element-wise multiplication between dst
+// and the conjugate of s and stores the result in dst.
+// It panics if the argument lengths do not match.
+func MulConj(dst, s []complex128) {
+	if len(dst) != len(s) {
+		panic(badLength)
+	}
+	for i, val := range s {
+		dst[i] *= cmplx.Conj(val)
+	}
+}
+
+// MulConjTo performs element-wise multiplication between s
+// and the conjugate of t and stores the result in dst.
+// It panics if the argument lengths do not match.
+func MulConjTo(dst, s, t []complex128) []complex128 {
+	if len(s) != len(t) {
+		panic(badLength)
+	}
+	if len(dst) != len(s) {
+		panic(badDstLength)
+	}
+	for i, val := range t {
+		dst[i] = cmplx.Conj(val) * s[i]
+	}
+	return dst
+}
+
 // MulTo performs element-wise multiplication between s
 // and t and stores the result in dst.
 // It panics if the argument lengths do not match.
@@ -559,6 +587,26 @@ func Scale(c complex128, dst []complex128) {
 	}
 }
 
+// ScaleReal multiplies every element in dst by the real scalar f.
+func ScaleReal(f float64, dst []complex128) {
+	for i, z := range dst {
+		dst[i] = complex(f*real(z), f*imag(z))
+	}
+}
+
+// ScaleRealTo multiplies the elements in s by the real scalar f and
+// stores the result in dst.
+// It panics if the slice argument lengths do not match.
+func ScaleRealTo(dst []complex128, f float64, s []complex128) []complex128 {
+	if len(dst) != len(s) {
+		panic(badDstLength)
+	}
+	for i, z := range s {
+		dst[i] = complex(f*real(z), f*imag(z))
+	}
+	return dst
+}
+
 // ScaleTo multiplies the elements in s by c and stores the result in dst.
 // It panics if the slice argument lengths do not match.
 func ScaleTo(dst []complex128, c complex128, s []complex128) []complex128 {


Test patch:
diff --git a/cmplxs/cmplxs_test.go b/cmplxs/cmplxs_test.go
index 5061e80c..112806c7 100644
--- a/cmplxs/cmplxs_test.go
+++ b/cmplxs/cmplxs_test.go
@@ -725,6 +725,66 @@ func TestMul(t *testing.T) {
 	}
 }
 
+func TestMulConj(t *testing.T) {
+	s1 := []complex128{2 + 1i, 3 + 2i, 4 + 3i}
+	s2 := []complex128{1 + 2i, 2 + 3i, 3 + 4i}
+	s2orig := []complex128{1 + 2i, 2 + 3i, 3 + 4i}
+	ans := []complex128{4 - 3i, 12 - 5i, 24 - 7i}
+	MulConj(s1, s2)
+	if !Equal(s1, ans) {
+		t.Errorf("MulConj doesn't give correct answer. Expected %v, Found %v", ans, s1)
+	}
+	if !Equal(s2, s2orig) {
+		t.Errorf("s2 changes during MulTo")
+	}
+	s1short := []complex128{1}
+	if !Panics(func() { MulConj(s1short, s2) }) {
+		t.Errorf("Did not panic with unequal lengths")
+	}
+	s2short := []complex128{1}
+	if !Panics(func() { MulConj(s1, s2short) }) {
+		t.Errorf("Did not panic with unequal lengths")
+	}
+}
+
+func TestMulConjTo(t *testing.T) {
+	s1 := []complex128{2 + 1i, 3 + 2i, 4 + 3i}
+	s1orig := []complex128{2 + 1i, 3 + 2i, 4 + 3i}
+	s2 := []complex128{1 + 2i, 2 + 3i, 3 + 4i}
+	s2orig := []complex128{1 + 2i, 2 + 3i, 3 + 4i}
+	dst1 := make([]complex128, 3)
+	ans := []complex128{4 - 3i, 12 - 5i, 24 - 7i}
+	dst2 := MulConjTo(dst1, s1, s2)
+	if !Equal(dst1, ans) {
+		t.Errorf("MulConjTo doesn't give correct answer in mutated slice")
+	}
+	if !Equal(dst2, ans) {
+		t.Errorf("MulConjTo doesn't give correct answer in returned slice")
+	}
+	if !Equal(s1, s1orig) {
+		t.Errorf("S1 changes during MulConjTo")
+	}
+	if !Equal(s2, s2orig) {
+		t.Errorf("s2 changes during MulConjTo")
+	}
+	MulConjTo(dst1, s1, s2)
+	if !Equal(dst1, ans) {
+		t.Errorf("MulConjTo doesn't give correct answer reusing dst")
+	}
+	dstShort := []complex128{1}
+	if !Panics(func() { MulConjTo(dstShort, s1, s2) }) {
+		t.Errorf("Did not panic with dst wrong length")
+	}
+	s1short := []complex128{1}
+	if !Panics(func() { MulConjTo(dst1, s1short, s2) }) {
+		t.Errorf("Did not panic with s1 wrong length")
+	}
+	s2short := []complex128{1}
+	if !Panics(func() { MulConjTo(dst1, s1, s2short) }) {
+		t.Errorf("Did not panic with s2 wrong length")
+	}
+}
+
 func TestMulTo(t *testing.T) {
 	s1 := []complex128{1 + 1i, 2 + 2i, 3 + 3i}
 	s1orig := []complex128{1 + 1i, 2 + 2i, 3 + 3i}
@@ -984,25 +1044,49 @@ func TestSame(t *testing.T) {
 
 func TestScale(t *testing.T) {
 	s := []complex128{3, 4, 1, 7, 5}
-	c := 5 + 5i
-	truth := []complex128{15 + 15i, 20 + 20i, 5 + 5i, 35 + 35i, 25 + 25i}
+	c := 4 + 5i
+	truth := []complex128{12 + 15i, 16 + 20i, 4 + 5i, 28 + 35i, 20 + 25i}
 	Scale(c, s)
 	areSlicesEqual(t, truth, s, "Bad scaling")
 }
 
+func TestScaleReal(t *testing.T) {
+	s := []complex128{3 + 4i, 4 + 5i, 1 + 2i, 7 + 6i, 5 + 2i}
+	f := 5.0
+	truth := []complex128{15 + 20i, 20 + 25i, 5 + 10i, 35 + 30i, 25 + 10i}
+	ScaleReal(f, s)
+	areSlicesEqual(t, truth, s, "Bad scaling")
+}
+
+func TestScaleRealTo(t *testing.T) {
+	s := []complex128{3 + 4i, 4 + 5i, 1 + 2i, 7 + 6i, 5 + 2i}
+	sCopy := make([]complex128, len(s))
+	copy(sCopy, s)
+	f := 5.0
+	truth := []complex128{15 + 20i, 20 + 25i, 5 + 10i, 35 + 30i, 25 + 10i}
+	dst := make([]complex128, len(s))
+	ScaleRealTo(dst, f, s)
+	if !Same(dst, truth) {
+		t.Errorf("ScaleRealTo dst does not match. Got %v, want %v", dst, truth)
+	}
+	if !Same(s, sCopy) {
+		t.Errorf("SourceRealTo s modified during call. Got %v, want %v", s, sCopy)
+	}
+}
+
 func TestScaleTo(t *testing.T) {
 	s := []complex128{3, 4, 1, 7, 5}
 	sCopy := make([]complex128, len(s))
 	copy(sCopy, s)
-	c := 5 + 5i
-	truth := []complex128{15 + 15i, 20 + 20i, 5 + 5i, 35 + 35i, 25 + 25i}
+	c := 4 + 5i
+	truth := []complex128{12 + 15i, 16 + 20i, 4 + 5i, 28 + 35i, 20 + 25i}
 	dst := make([]complex128, len(s))
 	ScaleTo(dst, c, s)
 	if !Same(dst, truth) {
-		t.Errorf("Scale to does not match. Got %v, want %v", dst, truth)
+		t.Errorf("ScaleTo dst does not match. Got %v, want %v", dst, truth)
 	}
 	if !Same(s, sCopy) {
-		t.Errorf("Source modified during call. Got %v, want %v", s, sCopy)
+		t.Errorf("SourceTo s modified during call. Got %v, want %v", s, sCopy)
 	}
 }