diff --git a/CHANGES b/CHANGES index 08733b4..68d0d35 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,15 @@ +libquantum 0.2.1: + - Completed GNU/Hurd and FreeBSD ports + - Added unbounded toffoli gate + - Changed hashing method to linear probing (breaks backward + compatibility) + - Optimized quantum_gate1 and gates using quantum_cexp + - Added a bit measurement function that does not remove the + measured bit + - Corrected qft, added qft_inv and adjusted shor + - Corrected the implementation of the Walsh-Hadamard transform + - Supplied version information + libquantum 0.2.0: - Added Quantum Error Correction - Included an Implementation of Grover's algorithm diff --git a/INSTALL b/INSTALL index 92b5581..63407b9 100644 --- a/INSTALL +++ b/INSTALL @@ -1,4 +1,4 @@ -libquantum 0.2.0 installation guide +libquantum 0.2.1 installation guide ----------------------------------- Contents: @@ -13,7 +13,7 @@ Contents: --------------- libquantum needs a C compiler with complex number support (C99 -prefered). A recent gcc (>=2.9.5) will do the job. Furthermore, the +prefered). A recent gcc (>=2.95) will do the job. Furthermore, the host must support 64-bit integers, even if it is not a 64-bit machine. If you encounter any difficulties while building, installing or using @@ -27,7 +27,7 @@ libquantum@enyo.de. As libquantum was created using autoconf and libtool, this step should not be a major problem. Simply extract the tarball to a directory: - tar xzvf libquantum-0.1.0.tar.gz + tar xzvf libquantum-0.2.1.tar.gz Next, run the configure script: diff --git a/Makefile.in b/Makefile.in index cae79a1..33ebc4b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -26,44 +26,44 @@ SHELL=/bin/sh # Target directory prefix PREFIX=@prefix@ +EPREFIX=${PREFIX} # Other directories -LIBDIR=${PREFIX}/lib +LIBDIR=${EPREFIX}/lib INCLUDEDIR=${PREFIX}/include top_builddir=. -# Release information +# Version information -MAJOR=0 -MINOR=2 -RELEASE=0 +VERSION=@PACKAGE_VERSION@ # Tools needed to build libquantum -CC=@CC@ -O2 -g -pg +CC=@CC@ INSTALL=@INSTALL@ LIBTOOL=@LIBTOOL@ # Flags passed to C compiler CFLAGS=@CFLAGS@ -LDFLAGS=-rpath $(LIBDIR) -version-info 2:0:2 +LDFLAGS=-rpath $(LIBDIR) -version-info 3:0:0 # Dependencies all: libquantum.la libquantum.la: complex.lo measure.lo matrix.lo gates.lo qft.lo classic.lo\ - qureg.lo decoherence.lo oaddn.lo omuln.lo expn.lo qec.lo Makefile + qureg.lo decoherence.lo oaddn.lo omuln.lo expn.lo qec.lo version.lo\ + Makefile $(LIBTOOL) $(CC) $(LDFLAGS) -o libquantum.la complex.lo measure.lo\ matrix.lo gates.lo oaddn.lo omuln.lo expn.lo qft.lo classic.lo\ - qureg.lo decoherence.lo qec.lo -lm + qureg.lo decoherence.lo qec.lo version.lo -lm complex.lo: complex.c complex.h Makefile $(LIBTOOL) $(CC) $(CFLAGS) -c complex.c -measure.lo: measure.c measure.h matrix.h qureg.h config.h Makefile +measure.lo: measure.c measure.h matrix.h qureg.h complex.h config.h Makefile $(LIBTOOL) $(CC) $(CFLAGS) -c measure.c matrix.lo: matrix.c matrix.h complex.h Makefile @@ -94,14 +94,11 @@ decoherence.lo: decoherence.c decoherence.h measure.h gates.h qureg.h\ complex.h config.h Makefile $(LIBTOOL) $(CC) $(CFLAGS) -c decoherence.c -qec.lo: qec.c qec.h gates.h qureg.h config.h Makefile +qec.lo: qec.c qec.h gates.h qureg.h decoherence.h measure.h config.h Makefile $(LIBTOOL) $(CC) $(CFLAGS) -c qec.c -# Bring this savage back home - -install: libquantum.la - $(LIBTOOL) $(INSTALL) -m 0644 libquantum.la $(LIBDIR) - $(INSTALL) -m 0644 quantum.h $(INCLUDEDIR) +version.lo: version.c version.h config.h Makefile + $(LIBTOOL) $(CC) $(CFLAGS) -c version.c # Build demos of Shor's and Grover's algorithms @@ -114,6 +111,12 @@ grover: libquantum.la grover.c Makefile $(LIBTOOL) $(CC) $(CFLAGS) -o grover grover.c -I./ -lquantum -static\ -lm +# Bring this savage back home + +install: libquantum.la + $(LIBTOOL) $(INSTALL) -m 0644 libquantum.la $(LIBDIR) + $(INSTALL) -m 0644 quantum.h $(INCLUDEDIR) + # Make everything neat and tidy clean: @@ -127,10 +130,9 @@ distclean: dist: -rm quantum.h config.h - mkdir libquantum-$(MAJOR).$(MINOR).$(RELEASE) + mkdir libquantum-$(VERSION) cp *.c *.h quantum.h.in Makefile.in config.h.in configure configure.in\ COPYING install-sh ltmain.sh config.sub config.guess README INSTALL\ - CHANGES libquantum-$(MAJOR).$(MINOR).$(RELEASE) - tar czf libquantum-$(MAJOR).$(MINOR).$(RELEASE).tar.gz\ - libquantum-$(MAJOR).$(MINOR).$(RELEASE)/ - rm -rf libquantum-$(MAJOR).$(MINOR).$(RELEASE) + CHANGES libquantum-$(VERSION) + tar czf libquantum-$(VERSION).tar.gz libquantum-$(VERSION)/ + rm -rf libquantum-$(VERSION) diff --git a/README b/README index 300ca1f..d6bc8a0 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -libquantum 0.2.0 README file +libquantum 0.2.1 README file ---------------------------- libquantum is a C library for quantum computing. It provides quantum diff --git a/complex.c b/complex.c index f37dd85..06024a6 100644 --- a/complex.c +++ b/complex.c @@ -26,24 +26,6 @@ #include "complex.h" #include "config.h" -/* Return the real part of a complex number */ - -float -quantum_real(COMPLEX_FLOAT a) -{ - float *p = (float *) &a; - return p[0]; -} - -/* Return the imaginary part of a complex number */ - -float -quantum_imag(COMPLEX_FLOAT a) -{ - float *p = (float *) &a; - return p[1]; -} - /* Return the complex conjugate of a complex number */ COMPLEX_FLOAT @@ -62,7 +44,7 @@ quantum_conj(COMPLEX_FLOAT a) float quantum_prob(COMPLEX_FLOAT a) { - return (float) (a * quantum_conj(a)); + return quantum_prob_inline(a); } /* Calculate e^(i * phi) */ diff --git a/complex.h b/complex.h index fbac4c3..31a7731 100644 --- a/complex.h +++ b/complex.h @@ -27,11 +27,40 @@ #include "config.h" -extern float quantum_real(COMPLEX_FLOAT a); -extern float quantum_imag(COMPLEX_FLOAT a); extern COMPLEX_FLOAT quantum_conj(COMPLEX_FLOAT a); extern float quantum_prob (COMPLEX_FLOAT a); extern COMPLEX_FLOAT quantum_cexp(float phi); +/* Return the real part of a complex number */ + +static inline float +quantum_real(COMPLEX_FLOAT a) +{ + float *p = (float *) &a; + return p[0]; +} + +/* Return the imaginary part of a complex number */ + +static inline float +quantum_imag(COMPLEX_FLOAT a) +{ + float *p = (float *) &a; + return p[1]; +} + +/* Calculate the square of a complex number (i.e. the probability) */ + +static inline float +quantum_prob_inline(COMPLEX_FLOAT a) +{ + float r, i; + + r = quantum_real(a); + i = quantum_imag(a); + + return r * r + i * i; +} + #endif diff --git a/configure b/configure index 737b78f..e65aa1a 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.57 for libquantum 0.2.0. +# Generated by GNU Autoconf 2.57 for libquantum 0.2.1. # # Report bugs to . # @@ -427,8 +427,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='libquantum' PACKAGE_TARNAME='libquantum' -PACKAGE_VERSION='0.2.0' -PACKAGE_STRING='libquantum 0.2.0' +PACKAGE_VERSION='0.2.1' +PACKAGE_STRING='libquantum 0.2.1' PACKAGE_BUGREPORT='libquantum@enyo.de' ac_unique_file="classic.c" @@ -938,7 +938,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures libquantum 0.2.0 to adapt to many kinds of systems. +\`configure' configures libquantum 0.2.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -999,7 +999,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of libquantum 0.2.0:";; + short | recursive ) echo "Configuration of libquantum 0.2.1:";; esac cat <<\_ACEOF @@ -1010,6 +1010,7 @@ Optional Features: --enable-static=PKGS build static libraries default=yes --enable-fast-install=PKGS optimize for fast installation default=yes --disable-libtool-lock avoid locking (might break parallel builds) + --enable-profiling compile with profiling support Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -1092,7 +1093,7 @@ fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF -libquantum configure 0.2.0 +libquantum configure 0.2.1 generated by GNU Autoconf 2.57 Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 @@ -1107,7 +1108,7 @@ cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by libquantum $as_me 0.2.0, which was +It was created by libquantum $as_me 0.2.1, which was generated by GNU Autoconf 2.57. Invocation command line was $ $0 $@ @@ -2225,12 +2226,12 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (exit $ac_status); }; }; then for ac_declaration in \ ''\ - '#include ' \ 'extern "C" void std::exit (int) throw (); using std::exit;' \ 'extern "C" void std::exit (int); using std::exit;' \ 'extern "C" void exit (int) throw ();' \ 'extern "C" void exit (int);' \ - 'void exit (int);' + 'void exit (int);' \ + '#include ' do cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" @@ -4130,7 +4131,7 @@ test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes case $host in *-*-irix6*) # Find out which ABI we are using. - echo '#line 4133 "configure"' > conftest.$ac_ext + echo '#line 4134 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -4673,7 +4674,7 @@ chmod -w . save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -o out/conftest2.$ac_objext" compiler_c_o=no -if { (eval echo configure:4676: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then +if { (eval echo configure:4677: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test -s out/conftest.err; then @@ -6556,7 +6557,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5 echo $ECHO_N "checking for sqrt in -lm... $ECHO_C" >&6 @@ -8255,9 +8255,24 @@ fi echo "$as_me:$LINENO: result: $I" >&5 echo "${ECHO_T}$I" >&6 +# Substitute fields in quantum.h.in +# Profiling check +# Check whether --enable-profiling or --disable-profiling was given. +if test "${enable_profiling+set}" = set; then + enableval="$enable_profiling" + CFLAGS="$CFLAGS -pg" +fi; + +# Enable -Wall for gcc +if test $CC = "gcc" +then + CFLAGS="$CFLAGS -Wall" +fi + +# Write the output files ac_config_files="$ac_config_files Makefile quantum.h" cat >confcache <<\_ACEOF @@ -8620,7 +8635,7 @@ _ASBOX } >&5 cat >&5 <<_CSEOF -This file was extended by libquantum $as_me 0.2.0, which was +This file was extended by libquantum $as_me 0.2.1, which was generated by GNU Autoconf 2.57. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -8680,7 +8695,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -libquantum config.status 0.2.0 +libquantum config.status 0.2.1 configured by $0, generated by GNU Autoconf 2.57, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" @@ -9358,3 +9373,4 @@ if test "$no_create" != yes; then # would make configure fail if this is the last instruction. $ac_cs_success || { (exit 1); exit 1; } fi + diff --git a/configure.in b/configure.in index d5ed163..ede0d90 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ # Process this file with autoconf to produce a configure script. -AC_INIT([libquantum], [0.2.0], [libquantum@enyo.de]) +AC_INIT([libquantum], [0.2.1], [libquantum@enyo.de]) AC_CONFIG_SRCDIR([classic.c]) AC_CONFIG_HEADER([config.h]) @@ -12,7 +12,6 @@ AC_PROG_INSTALL AC_PROG_LIBTOOL # Checks for libraries. -# FIXME: Replace `main' with a function in `-lm': AC_CHECK_LIB([m], [sqrt]) # Checks for header files. @@ -72,8 +71,22 @@ then fi AC_MSG_RESULT($I) +# Substitute fields in quantum.h.in AC_SUBST(MU_TYPE) AC_SUBST(CF_TYPE) +# Profiling check +AC_ARG_ENABLE(profiling, + [ --enable-profiling compile with profiling support], + [CFLAGS="$CFLAGS -pg"], + []) + +# Enable -Wall for gcc +if test $CC = "gcc" +then + CFLAGS="$CFLAGS -Wall" +fi + +# Write the output files AC_CONFIG_FILES([Makefile quantum.h]) -AC_OUTPUT \ No newline at end of file +AC_OUTPUT diff --git a/gates.c b/gates.c index 52ac528..5e917cd 100644 --- a/gates.c +++ b/gates.c @@ -1,4 +1,4 @@ - /* gates.c: Basic gates for quantum register manipulation +/* gates.c: Basic gates for quantum register manipulation Copyright 2003 Bjoern Butscher, Hendrik Weimer @@ -24,6 +24,7 @@ #include #include #include +#include #include "matrix.h" #include "defs.h" @@ -48,7 +49,7 @@ quantum_cnot(int control, int target, quantum_reg *reg) { for(i=0; isize; i++) { - /* Flip the target bit of a base state if the control bit is set */ + /* Flip the target bit of a basis state if the control bit is set */ if((reg->node[i].state & ((MAX_UNSIGNED) 1 << control))) reg->node[i].state ^= ((MAX_UNSIGNED) 1 << target); @@ -73,7 +74,7 @@ quantum_toffoli(int control1, int control2, int target, quantum_reg *reg) { for(i=0; isize; i++) { - /* Flip the target bit of a base state if both control bits are + /* Flip the target bit of a basis state if both control bits are set */ if(reg->node[i].state & ((MAX_UNSIGNED) 1 << control1)) @@ -88,6 +89,53 @@ quantum_toffoli(int control1, int control2, int target, quantum_reg *reg) } } +/* Apply an unbounded toffoli gate. This gate is not considered +elementary and is not available on all physical realizations of a +quantum computer. Be sure to pass the function the correct number of +controlling qubits. The target is given in the last argument. */ + +void +quantum_unbounded_toffoli(int controlling, quantum_reg *reg, ...) +{ + va_list bits; + int target; + int *controls; + int i, j; + + controls = malloc(controlling * sizeof(int)); + if(!controls) + { + printf("Error allocating %i-element int array!\n", controlling); + exit(1); + } + quantum_memman(controlling * sizeof(int)); + + va_start(bits, reg); + + for(i=0; isize; i++) + { + for(j=0; (j < controlling) && + (reg->node[i].state & (MAX_UNSIGNED) 1 << controls[j]); j++); + + if(j == controlling) /* all control bits are set */ + reg->node[i].state ^= ((MAX_UNSIGNED) 1 << target); + } + + free(controls); + quantum_memman(-controlling * sizeof(int)); + + quantum_decohere(reg); + +} + + /* Apply a sigma_x (or not) gate */ void @@ -104,7 +152,7 @@ quantum_sigma_x(int target, quantum_reg *reg) { for(i=0; isize; i++) { - /* Flip the target bit of each base state */ + /* Flip the target bit of each basis state */ reg->node[i].state ^= ((MAX_UNSIGNED) 1 << target); } @@ -121,7 +169,7 @@ quantum_sigma_y(int target, quantum_reg *reg) for(i=0; isize;i++) { - /* Flip the target bit of each base state and multiply with + /* Flip the target bit of each basis state and multiply with +/- i */ reg->node[i].state ^= ((MAX_UNSIGNED) 1 << target); @@ -221,12 +269,12 @@ quantum_swaptheleads_omuln_controlled(int control, int width, quantum_reg *reg) void quantum_gate1(int target, quantum_matrix m, quantum_reg *reg) { - int i, j, k; + int i, j, k, iset; int addsize=0, decsize=0; COMPLEX_FLOAT t, tnot=0; + float limit; char *done; - quantum_reg out; - quantum_reg_hash *p; + // quantum_reg_hash *p; if((m.cols != 2) || (m.rows != 2)) { @@ -238,19 +286,20 @@ quantum_gate1(int target, quantum_matrix m, quantum_reg *reg) for(i=0; i<(1 << reg->hashw); i++) { - while(reg->hash[i]) + /* while(reg->hash[i]) { p = reg->hash[i]->next; free(reg->hash[i]); quantum_memman(-sizeof(quantum_reg_hash)); reg->hash[i] = p; - } + }*/ + reg->hash[i] = 0; } for(i=0; isize; i++) quantum_add_hash(reg->node[i].state, i, reg); - /* calculate the number of base states to be added */ + /* calculate the number of basis states to be added */ for(i=0; isize; i++) { @@ -267,7 +316,7 @@ quantum_gate1(int target, quantum_matrix m, quantum_reg *reg) } } - /* allocate memory for the new base states */ + /* allocate memory for the new basis states */ reg->node = realloc(reg->node, (reg->size + addsize) * sizeof(quantum_reg_node)); @@ -295,12 +344,18 @@ quantum_gate1(int target, quantum_matrix m, quantum_reg *reg) k = reg->size; + limit = (1.0 / ((MAX_UNSIGNED) 1 << reg->width)) / 1000000; + /* perform the actual matrix multiplication */ for(i=0; isize; i++) { if(!done[i]) { + /* determine if the target of the basis state is set */ + + iset = reg->node[i].state & ((MAX_UNSIGNED) 1 << target); + tnot = 0; j = quantum_get_state(reg->node[i].state ^ ((MAX_UNSIGNED) 1<= 0) tnot = reg->node[j].amplitude; - if(reg->node[i].state & ((MAX_UNSIGNED) 1 << target)) + if(iset) reg->node[i].amplitude = m.t[2] * tnot + m.t[3] * t; else @@ -317,7 +372,7 @@ quantum_gate1(int target, quantum_matrix m, quantum_reg *reg) if(j >= 0) { - if(reg->node[i].state & ((MAX_UNSIGNED) 1 << target)) + if(iset) reg->node[j].amplitude = m.t[0] * tnot + m.t[1] * t; else @@ -325,20 +380,18 @@ quantum_gate1(int target, quantum_matrix m, quantum_reg *reg) } - else /* new base state will be created */ + else /* new basis state will be created */ { - if((m.t[1] == 0) - && (reg->node[i].state & ((MAX_UNSIGNED) 1 << target))) + if((m.t[1] == 0) && (iset)) break; - if((m.t[2] == 0) - && !(reg->node[i].state & ((MAX_UNSIGNED) 1 << target))) + if((m.t[2] == 0) && !(iset)) break; reg->node[k].state = reg->node[i].state ^ ((MAX_UNSIGNED) 1 << target); - if(reg->node[i].state & ((MAX_UNSIGNED) 1 << target)) + if(iset) reg->node[k].amplitude = m.t[1] * t; else @@ -350,14 +403,6 @@ quantum_gate1(int target, quantum_matrix m, quantum_reg *reg) if(j >= 0) done[j] = 1; - if(!reg->node[i].amplitude) - decsize++; - - if(j >= 0) - { - if(!reg->node[j].amplitude) - decsize++; - } } } @@ -366,34 +411,33 @@ quantum_gate1(int target, quantum_matrix m, quantum_reg *reg) free(done); quantum_memman(-reg->size * sizeof(char)); - /* remove base states with zero amplitude */ + /* remove basis states with extremely small amplitude */ + + for(i=0, j=0; isize; i++) + { + if(quantum_prob_inline(reg->node[i].amplitude) < limit) + { + j++; + decsize++; + } + + else if(j) + { + reg->node[i-j].state = reg->node[i].state; + reg->node[i-j].amplitude = reg->node[i].amplitude; + } + } if(decsize) { - out.width = reg->width; - out.size = reg->size - decsize; - out.node = calloc(out.size, sizeof(quantum_reg_node)); - if(!out.node) + reg->size -= decsize; + reg->node = realloc(reg->node, reg->size * sizeof(quantum_reg_node)); + if(!reg->node) { - printf("Not enough memory for %i-sized qubit!\n", out.size); + printf("Not enough memory for %i-sized qubit!\n", + reg->size + addsize); exit(1); } - quantum_memman(out.size * sizeof(quantum_reg_node)); - out.hashw = reg->hashw; - out.hash = reg->hash; - - for(i=0, j=0; isize; i++) - { - if(reg->node[i].amplitude) - { - out.node[j].state = reg->node[i].state; - out.node[j].amplitude = reg->node[i].amplitude; - j++; - } - } - - quantum_delete_qureg_hashpreserve(reg); - *reg = out; } quantum_decohere(reg); @@ -417,21 +461,15 @@ quantum_hadamard(int target, quantum_reg *reg) } -/* Apply a walsh-hadamard gate */ +/* Apply a walsh-hadamard transform */ void -quantum_walsh(int target, quantum_reg *reg) +quantum_walsh(int width, quantum_reg *reg) { - quantum_matrix m; + int i; - m = quantum_new_matrix(2, 2); - - m.t[0] = IMAGINARY*sqrt(1.0/2); m.t[1] = IMAGINARY*sqrt(1.0/2); - m.t[2] = IMAGINARY*sqrt(1.0/2); m.t[3] = -IMAGINARY*sqrt(1.0/2); - - quantum_gate1(target, m, reg); - - quantum_delete_matrix(&m); + for(i=0; isize; i++) { if(reg->node[i].state & ((MAX_UNSIGNED) 1 << target)) - reg->node[i].amplitude *= quantum_cexp(gamma/2); + reg->node[i].amplitude *= z; else - reg->node[i].amplitude *= quantum_cexp(-gamma/2); + reg->node[i].amplitude /= z; } quantum_decohere(reg); @@ -495,10 +536,13 @@ void quantum_phase_scale(int target, float gamma, quantum_reg *reg) { int i; + COMPLEX_FLOAT z; + + z = quantum_cexp(gamma); for(i=0; isize; i++) { - reg->node[i].amplitude *= quantum_cexp(gamma); + reg->node[i].amplitude *= z; } quantum_decohere(reg); @@ -511,11 +555,14 @@ void quantum_phase_kick(int target, float gamma, quantum_reg *reg) { int i; + COMPLEX_FLOAT z; + + z = quantum_cexp(gamma); for(i=0; isize; i++) { if(reg->node[i].state & ((MAX_UNSIGNED) 1 << target)) - reg->node[i].amplitude *= quantum_cexp(gamma); + reg->node[i].amplitude *= z; } quantum_decohere(reg); @@ -527,14 +574,16 @@ void quantum_cond_phase(int control, int target, quantum_reg *reg) { int i; + COMPLEX_FLOAT z; + + z = quantum_cexp(pi / ((MAX_UNSIGNED) 1 << (control - target))); for(i=0; isize; i++) { if(reg->node[i].state & ((MAX_UNSIGNED) 1 << control)) { if(reg->node[i].state & ((MAX_UNSIGNED) 1 << target)) - reg->node[i].amplitude - *= quantum_cexp(pi / ((MAX_UNSIGNED) 1 << (control - target))); + reg->node[i].amplitude *= z; } } @@ -546,14 +595,16 @@ void quantum_cond_phase_inv(int control, int target, quantum_reg *reg) { int i; + COMPLEX_FLOAT z; + + z = quantum_cexp(-pi / ((MAX_UNSIGNED) 1 << (control - target))); for(i=0; isize; i++) { if(reg->node[i].state & ((MAX_UNSIGNED) 1 << control)) { if(reg->node[i].state & ((MAX_UNSIGNED) 1 << target)) - reg->node[i].amplitude - *= quantum_cexp(-pi / ((MAX_UNSIGNED) 1 << (control - target))); + reg->node[i].amplitude *= z; } } @@ -566,13 +617,16 @@ void quantum_cond_phase_kick(int control, int target, float gamma, quantum_reg *reg) { int i; + COMPLEX_FLOAT z; + + z = quantum_cexp(gamma); for(i=0; isize; i++) { if(reg->node[i].state & ((MAX_UNSIGNED) 1 << control)) { if(reg->node[i].state & ((MAX_UNSIGNED) 1 << target)) - reg->node[i].amplitude *= quantum_cexp(gamma); + reg->node[i].amplitude *= z; } } quantum_decohere(reg); diff --git a/gates.h b/gates.h index 68e04d1..b3e719e 100644 --- a/gates.h +++ b/gates.h @@ -31,6 +31,8 @@ extern void quantum_cnot(int control, int target, quantum_reg *reg); extern void quantum_toffoli(int control1, int control2, int target, quantum_reg *reg); +extern void quantum_unbounded_toffoli(int controlling, quantum_reg *reg, ...); + extern void quantum_sigma_x(int target, quantum_reg *reg); extern void quantum_sigma_y(int target, quantum_reg *reg); extern void quantum_sigma_z(int target, quantum_reg *reg); @@ -46,7 +48,7 @@ extern void quantum_r_y(int target, float gamma, quantum_reg *reg); extern void quantum_r_z(int target, float gamma, quantum_reg *reg); extern void quantum_hadamard(int target, quantum_reg *reg); -extern void quantum_walsh(int target, quantum_reg *reg); +extern void quantum_walsh(int width, quantum_reg *reg); extern void quantum_phase_scale(int target, float gamma, quantum_reg *reg); extern void quantum_phase_kick(int target, float gamma, quantum_reg *reg); diff --git a/grover.c b/grover.c index a63c6cc..f5f3ca0 100644 --- a/grover.c +++ b/grover.c @@ -120,14 +120,6 @@ void grover(int target, quantum_reg *reg) } -void print_grover(quantum_reg *reg) -{ - int i; - - for(i=0;isize;i++) - printf("%llu %f\n", reg->node[i].state, __real__ reg->node[i].amplitude); -} - int main(int argc, char **argv) { quantum_reg reg; diff --git a/measure.c b/measure.c index c09fc86..289454f 100644 --- a/measure.c +++ b/measure.c @@ -59,8 +59,8 @@ quantum_measure(quantum_reg reg) given base state - r, return the base state as the result. Otherwise, continue with the next base state. */ - r -= quantum_prob(reg.node[i].amplitude); - if(quantum_prob(reg.node[i].amplitude) >= r) + r -= quantum_prob_inline(reg.node[i].amplitude); + if(quantum_prob_inline(reg.node[i].amplitude) >= r) return reg.node[i].state; } @@ -86,14 +86,14 @@ quantum_bmeasure(int pos, quantum_reg *reg) MAX_UNSIGNED lpat=0, rpat=0, pos2; quantum_reg out; - pos2 = 1 << pos; + pos2 = (MAX_UNSIGNED) 1 << pos; /* Sum up the probability for 0 being the result */ for(i=0; isize; i++) { if(!(reg->node[i].state & pos2)) - pa += quantum_prob(reg->node[i].amplitude); + pa += quantum_prob_inline(reg->node[i].amplitude); } /* Compare the probability for 0 with a random number and determine @@ -115,7 +115,7 @@ quantum_bmeasure(int pos, quantum_reg *reg) reg->node[i].amplitude = 0; else { - d += quantum_prob(reg->node[i].amplitude); + d += quantum_prob_inline(reg->node[i].amplitude); size++; } } @@ -125,7 +125,7 @@ quantum_bmeasure(int pos, quantum_reg *reg) reg->node[i].amplitude = 0; else { - d += quantum_prob(reg->node[i].amplitude); + d += quantum_prob_inline(reg->node[i].amplitude); size++; } } @@ -173,3 +173,93 @@ quantum_bmeasure(int pos, quantum_reg *reg) *reg = out; return result; } + +/* Measure a single bit, but do not remove it from the quantum + register */ + +int +quantum_bmeasure_bitpreserve(int pos, quantum_reg *reg) +{ + int i, j; + int size=0, result=0; + double d=0, pa=0, r; + MAX_UNSIGNED pos2; + quantum_reg out; + + pos2 = (MAX_UNSIGNED) 1 << pos; + + /* Sum up the probability for 0 being the result */ + + for(i=0; isize; i++) + { + if(!(reg->node[i].state & pos2)) + pa += quantum_prob_inline(reg->node[i].amplitude); + } + + /* Compare the probability for 0 with a random number and determine + the result of the measurement */ + + r = quantum_frand(); + + if (r > pa) + result = 1; + + /* Eradicate all amplitudes of base states which have been ruled out + by the measurement and get the absolute of the new register */ + + for(i=0;isize;i++) + { + if(reg->node[i].state & pos2) + { + if(!result) + reg->node[i].amplitude = 0; + else + { + d += quantum_prob_inline(reg->node[i].amplitude); + size++; + } + } + else + { + if(result) + reg->node[i].amplitude = 0; + else + { + d += quantum_prob_inline(reg->node[i].amplitude); + size++; + } + } + } + + /* Build the new quantum register */ + + out.size = size; + out.node = calloc(size, sizeof(quantum_reg_node)); + if(!out.node) + { + printf("Not enough memory for %i-sized qubit!\n", size); + exit(1); + } + quantum_memman(size * sizeof(quantum_reg_node)); + out.hashw = reg->hashw; + out.hash = reg->hash; + out.width = reg->width; + + /* Determine the numbers of the new base states and norm the quantum + register */ + + for(i=0, j=0; isize; i++) + { + if(reg->node[i].amplitude) + { + out.node[j].state = reg->node[i].state; + out.node[j].amplitude = reg->node[i].amplitude * 1 / (float) sqrt(d); + + j++; + } + } + + quantum_delete_qureg_hashpreserve(reg); + *reg = out; + return result; +} diff --git a/measure.h b/measure.h index 774d29e..ff0bf37 100644 --- a/measure.h +++ b/measure.h @@ -33,5 +33,6 @@ extern double quantum_frand(); extern MAX_UNSIGNED quantum_measure(quantum_reg reg); extern int quantum_bmeasure(int pos, quantum_reg *reg); +extern int quantum_bmeasure_bitpreserve(int pos, quantum_reg *reg); #endif diff --git a/qec.c b/qec.c index c56b474..c9f5774 100644 --- a/qec.c +++ b/qec.c @@ -27,6 +27,7 @@ #include "gates.h" #include "config.h" #include "decoherence.h" +#include "measure.h" /* Type of the QEC. Currently implemented versions are: diff --git a/qft.c b/qft.c index 4c1ce60..d801f55 100644 --- a/qft.c +++ b/qft.c @@ -40,10 +40,20 @@ void quantum_qft(int width, quantum_reg *reg) quantum_hadamard(i, reg); } - for(i=0; ihashw); i++) - { - while(reg->hash[i]) - { - p = reg->hash[i]->next; - free(reg->hash[i]); - quantum_memman(-sizeof(quantum_reg_hash)); - reg->hash[i] = p; - } - } - free(reg->hash); - quantum_memman(-(1 << reg->hashw) * sizeof(quantum_reg_hash *)); + quantum_memman(-(1 << reg->hashw) * sizeof(int)); } /* Delete a quantum register */ @@ -205,12 +191,16 @@ quantum_delete_qureg_hashpreserve(quantum_reg *reg) void quantum_print_qureg(quantum_reg reg) { - int i; + int i,j; for(i=0; i\n", quantum_real(reg.node[i].amplitude), - quantum_imag(reg.node[i].amplitude), reg.node[i].state); + printf("%f %+fi|%lli> (%e) (|", quantum_real(reg.node[i].amplitude), + quantum_imag(reg.node[i].amplitude), reg.node[i].state, + quantum_prob_inline(reg.node[i].amplitude)); + for(j=reg.width-1;j>=0;j--) + printf("%i", ((((MAX_UNSIGNED) 1 << j) & reg.node[i].state) > 0)); + printf(">)\n"); } printf("\n"); @@ -249,122 +239,19 @@ quantum_addscratch(int bits, quantum_reg *reg) } } -/* Add an element to the hash table */ - -void -quantum_add_hash(MAX_UNSIGNED a, int pos, quantum_reg *reg) -{ - int i; - quantum_reg_hash *p; - - i = quantum_hash64(a, reg->hashw); - - p = calloc(1, sizeof(quantum_reg_hash)); - if(!p) - { - printf("Not enough memory for hash element!\n"); - exit(1); - } - - quantum_memman(sizeof(quantum_reg_hash)); - - p->i = pos; - p->next = reg->hash[i]; - - reg->hash[i] = p; - -} - -/* Remove an element from the hash table */ - -void -delete_hash(MAX_UNSIGNED a, int pos, quantum_reg *reg) -{ - int i; - quantum_reg_hash *p, *q=0; - - i = quantum_hash64(a, reg->hashw); - - p = reg->hash[i]; - - while(p->i != pos) - { - q = p; - p = p->next; - } - - if(q) - { - q->next = p->next; - free(p); - } - else - { - if(p) - { - reg->hash[i] = p->next; - free(p); - } - else - { - reg->hash[i] = 0; - free(reg->hash[i]); - } - } -} - /* Print the hash table to stdout and test if the hash table is corrupted */ void -print_hash(quantum_reg reg) +quantum_print_hash(quantum_reg reg) { int i; - quantum_reg_hash *p; - char *done; - - done = calloc(reg.size, sizeof(char)); - if(!done) - { - printf("Not enough memory for %i bytes array!\n", - (reg.size)*sizeof(char)); - exit(1); - } for(i=0; i < (1 << reg.hashw); i++) { - printf("%i: ", i); - - if(reg.hash[i]) - { - p = reg.hash[i]; - - while(p->next) - { - printf("%llu ", reg.node[p->i].state); - if(quantum_hash64(reg.node[p->i].state, reg.hashw) != i) - printf(" Corrupted hash table!\n... "); - done[p->i] = 1; - p = p->next; - } - - printf("%llu", reg.node[p->i].state); - if(quantum_hash64(reg.node[p->i].state, reg.hashw) != i) - printf(" Corrupted hash table!"); - done[p->i] = 1; - } - - printf("\n"); + if(i) + printf("%i: %i %llu\n", i, reg.hash[i]-1, + reg.node[reg.hash[i]-1].state); } - /* Test if there are elements in the quantum register which are not - in the hash table */ - - for(i=0; ii].state == a) - return p->i; - if(p->next) - p = p->next; - } while(p->next); - - if(reg.node[p->i].state == a) - return p->i; + if(reg.node[reg.hash[i]-1].state == a) + return reg.hash[i]-1; + i++; + if(i == (1 << reg.hashw)) + i = 0; } - + return -1; + } -/* Update an element of the hash table */ +/* Add an element to the hash table */ static inline void -quantum_change_hash(MAX_UNSIGNED a, int oldpos, MAX_UNSIGNED b, int pos, - quantum_reg *reg) +quantum_add_hash(MAX_UNSIGNED a, int pos, quantum_reg *reg) { - int i, j; - quantum_reg_hash *p, *q=0; + int i; i = quantum_hash64(a, reg->hashw); - p = reg->hash[i]; - q = reg->hash[i]; - j = p->i; + while(reg->hash[i]) + { + i++; + if(i == (1 << reg->hashw)) + i = 0; + } - while(p->i != oldpos) - p = p->next; + reg->hash[i] = pos+1; - p->i = j; - reg->hash[i] = q->next; - - i = quantum_hash64(b, reg->hashw); - - q->next = reg->hash[i]; - reg->hash[i] = q; - q->i = pos; } #endif - diff --git a/shor.c b/shor.c index 280ead8..fc0ba0c 100644 --- a/shor.c +++ b/shor.c @@ -80,7 +80,14 @@ int main(int argc, char **argv) { } quantum_qft(width, &qr); - + + for(i=0; i