Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/itsubaki/q
Browse files Browse the repository at this point in the history
  • Loading branch information
itsubaki committed Jun 5, 2024
2 parents ba1007c + 65e7985 commit 171b82c
Show file tree
Hide file tree
Showing 17 changed files with 338 additions and 313 deletions.
8 changes: 5 additions & 3 deletions .github/workflows/tests.yml → .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,19 @@ jobs:
uses: actions/checkout@v4

- name: Setup Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: "1.22"
go-version-file: go.mod
cache: false

- name: Tests
run: |
make test
- name: Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

- name: Benchmark
run: |
Expand Down
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ secret
.DS_Store

# test
cover.html
cover.out
coverage.txt
coverage.html

Expand Down
30 changes: 25 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

### Bell state

```golang
```go
qsim := q.New()

// generate qubits of |0>|0>
Expand Down Expand Up @@ -43,7 +43,7 @@ for _, s := range qsim.State() {

### Quantum teleportation

```golang
```go
qsim := q.New()

// generate qubits of |phi>|0>|0>
Expand Down Expand Up @@ -79,7 +79,7 @@ for _, s := range qsim.State(q1) {

### Error correction

```golang
```go
qsim := q.New()

q0 := qsim.New(1, 2) // (0.2, 0.8)
Expand Down Expand Up @@ -119,7 +119,7 @@ for _, s := range qsim.State(q0) {

### Grover's search algorithm

```golang
```go
qsim := q.New()

// initial state
Expand Down Expand Up @@ -171,7 +171,7 @@ for _, s := range qsim.State() {

### Shor's factoring algorithm

```golang
```go
N := 15
a := 7 // co-prime

Expand Down Expand Up @@ -228,6 +228,26 @@ for i := 0; i < 10; i++{

- In general, See [`cmd/shor`](./cmd/shor/main.go)

### Any quantum gate and its controlled gate

```go
h := gate.U(math.Pi/2, 0, math.Pi)
x := gate.U(math.Pi, 0, math.Pi)

qsim := q.New()
q0 := qsim.Zero()
q1 := qsim.Zero()

qsim.Apply(h, q0)
qsim.C(x, q0, q1)

for _, s := range qsim.State() {
fmt.Println(s)
}
// [00][ 0]( 0.7071 0.0000i): 0.5000
// [11][ 3]( 0.7071 0.0000i): 0.5000
```

## References

- Michael A. Nielsen, Issac L. Chuang. Quantum Computation and Quantum Information.
27 changes: 27 additions & 0 deletions math/number/log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package number

import "fmt"

// Log2 returns the base 2 logarithm of N.
// N must be a power of 2.
func Log2(N int) (int, error) {
if N == 1 {
return 0, nil
}

var n int = 1
for {
if N%2 != 0 {
return -1, fmt.Errorf("N must be a power of 2")
}

if N/2 == 1 {
break
}

N = N / 2
n++
}

return n, nil
}
50 changes: 50 additions & 0 deletions math/number/log_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package number_test

import (
"fmt"
"testing"

"github.com/itsubaki/q/math/number"
)

func ExampleLog2() {
fmt.Println(number.Log2(8))
fmt.Println(number.Log2(32))
fmt.Println(number.Log2(15))
fmt.Println(number.Log2(20))

// Output:
// 3 <nil>
// 5 <nil>
// -1 N must be a power of 2
// -1 N must be a power of 2
}

func TestLog2(t *testing.T) {
cases := []struct {
n int
want int
}{
{1, 0},
{2, 1},
{4, 2},
{8, 3},
{16, 4},
{32, 5},
{64, 6},
{128, 7},
{256, 8},
{512, 9},
{1024, 10},
{2048, 11},
{4096, 12},
{8192, 13},
}

for _, c := range cases {
got := number.Must(number.Log2(c.n))
if got != c.want {
t.Errorf("got=%v want=%d", got, c.want)
}
}
}
26 changes: 26 additions & 0 deletions math/number/must_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package number_test

import (
"fmt"
"testing"

"github.com/itsubaki/q/math/number"
)

func TestMustPanic(t *testing.T) {
defer func() {
if rec := recover(); rec != nil {
err, ok := rec.(error)
if !ok {
t.Fail()
}

if err.Error() != "something went wrong" {
t.Fail()
}
}
}()

number.Must(-1, fmt.Errorf("something went wrong"))
t.Fail()
}
18 changes: 0 additions & 18 deletions math/number/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,24 +56,6 @@ func TestParseFloat(t *testing.T) {
}
}

func TestMustPanic(t *testing.T) {
defer func() {
if rec := recover(); rec != nil {
err, ok := rec.(error)
if !ok {
t.Fail()
}

if err.Error() != "something went wrong" {
t.Fail()
}
}
}()

number.Must(-1, fmt.Errorf("something went wrong"))
t.Fail()
}

func FuzzParseFloat(f *testing.F) {
seed := []string{"123", "101", "1.0101", "abc", "a.bc"}
for i := range seed {
Expand Down
2 changes: 1 addition & 1 deletion math/rand/math.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

var Float64 = rand.Float64

// Const returns a constant number in [0.0, 1.0).
// Const returns a sequence of numbers fixed by seeds.
func Const(seed ...uint64) func() float64 {
var s0, s1 uint64
if len(seed) > 0 {
Expand Down
7 changes: 4 additions & 3 deletions q.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func (q *Q) One() Qubit {
return q.New(0, 1)
}

// ZeroWith returns a qubit in the zero state with n qubits.
// ZeroWith returns n qubits in the zero state.
func (q *Q) ZeroWith(n int) []Qubit {
qb := make([]Qubit, n)
for i := 0; i < n; i++ {
Expand All @@ -93,7 +93,7 @@ func (q *Q) ZeroWith(n int) []Qubit {
return qb
}

// One returns a qubit in the one state with n qubits.
// One returns n qubits in the one state.
func (q *Q) OneWith(n int) []Qubit {
qb := make([]Qubit, n)
for i := 0; i < n; i++ {
Expand All @@ -103,7 +103,8 @@ func (q *Q) OneWith(n int) []Qubit {
return qb
}

// ZeroLog2 returns a qubit in the zero state with log2(N) qubits.
// ZeroLog2 returns n qubits in the zero state.
// n is greater than or equal to log2(N).
func (q *Q) ZeroLog2(N int) []Qubit {
n := int(math.Log2(float64(N))) + 1
return q.ZeroWith(n)
Expand Down
20 changes: 20 additions & 0 deletions q_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1212,6 +1212,26 @@ func Example_shorFactoring85() {
// N=85, a=14. p=5, q=17. s/r=7/16 ([0.0111]~0.438)
}

func Example_any() {
h := gate.U(math.Pi/2, 0, math.Pi)
x := gate.U(math.Pi, 0, math.Pi)

qsim := q.New()
q0 := qsim.Zero()
q1 := qsim.Zero()

qsim.Apply(h, q0)
qsim.C(x, q0, q1)

for _, s := range qsim.State() {
fmt.Println(s)
}

// Output:
// [00][ 0]( 0.7071 0.0000i): 0.5000
// [11][ 3]( 0.7071 0.0000i): 0.5000
}

func Example_top() {
N := 21
a := 11
Expand Down
39 changes: 39 additions & 0 deletions quantum/density/flip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package density

import (
"fmt"
"math"

"github.com/itsubaki/q/math/matrix"
"github.com/itsubaki/q/math/number"
"github.com/itsubaki/q/quantum/gate"
)

// Flip returns the flip channel.
func Flip(p float64, m matrix.Matrix) (matrix.Matrix, matrix.Matrix, error) {
if p < 0 || p > 1 {
return nil, nil, fmt.Errorf("p must be 0 <= p =< 1. p=%v", p)
}

d, _ := m.Dimension()
n := number.Must(number.Log2(d))

e0 := gate.I(n).Mul(complex(math.Sqrt(p), 0))
e1 := m.Mul(complex(math.Sqrt(1-p), 0))
return e0, e1, nil
}

// BitFlip returns the bit flip channel.
func BitFlip(p float64) (matrix.Matrix, matrix.Matrix, error) {
return Flip(p, gate.X())
}

// PhaseFlip returns the phase flip channel.
func PhaseFlip(p float64) (matrix.Matrix, matrix.Matrix, error) {
return Flip(p, gate.Z())
}

// BitPhaseFlip returns the bit-phase flip channel.
func BitPhaseFlip(p float64) (matrix.Matrix, matrix.Matrix, error) {
return Flip(p, gate.Y())
}
Loading

0 comments on commit 171b82c

Please sign in to comment.