added core code, README, and testing scripts
authorLucas K <lkocia@s3miclassical.com>
Tue, 22 Dec 2020 22:54:55 +0000 (14:54 -0800)
committerLucas K <lkocia@s3miclassical.com>
Tue, 22 Dec 2020 22:54:55 +0000 (14:54 -0800)
38 files changed:
Makefile [new file with mode: 0644]
Pd.txt [new file with mode: 0644]
README.txt [new file with mode: 0644]
exponentialsum.c [new file with mode: 0644]
exponentialsum.h [new file with mode: 0644]
extend.c [new file with mode: 0644]
extend.h [new file with mode: 0644]
innerproduct.c [new file with mode: 0644]
innerproduct.h [new file with mode: 0644]
matrix.c [new file with mode: 0644]
matrix.h [new file with mode: 0644]
measurepauli.c [new file with mode: 0644]
measurepauli.h [new file with mode: 0644]
multipauli.c [new file with mode: 0644]
randominputPauli.c [new file with mode: 0644]
randominputcommutingHermitianPauli.c [new file with mode: 0644]
randominputcommutingHermitianPauli2.c [new file with mode: 0644]
randomstabilizerstate.c [new file with mode: 0644]
randomstabilizerstate.h [new file with mode: 0644]
shrink.c [new file with mode: 0644]
shrink.h [new file with mode: 0644]
shrinkstar.c [new file with mode: 0644]
shrinkstar.h [new file with mode: 0644]
strongsim.c [new file with mode: 0644]
strongsim1.c [new file with mode: 0644]
strongsim12.c [new file with mode: 0644]
strongsim12_relerr.c [new file with mode: 0644]
strongsim1_relerr.c [new file with mode: 0644]
strongsim2.c [new file with mode: 0644]
strongsim2_relerr.c [new file with mode: 0644]
strongsim3.c [new file with mode: 0644]
strongsim3_relerr.c [new file with mode: 0644]
strongsim6.c [new file with mode: 0644]
strongsim6_relerr.c [new file with mode: 0644]
strongsim_relerr.c [new file with mode: 0644]
test.bash [new file with mode: 0644]
test2.bash [new file with mode: 0644]
timing.bash [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..19865ad
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,69 @@
+#IDIR =../include
+CC=gcc -std=c99
+CFLAGS=-Wall
+LIBS=-lm libmatrix.so libexponentialsum.so libextend.so libmeasurepauli.so libinnerproduct.so
+
+strongsim_relerr: strongsim_relerr.c matrix exponentialsum shrink shrinkstar extend measurepauli innerproduct randomstabilizerstate
+       $(CC) -o $@ strongsim_relerr.c $(CFLAGS) $(LIBS) libshrink.so libshrinkstar.so librandomstabilizerstate.so
+
+strongsim: strongsim.c matrix exponentialsum shrink extend measurepauli innerproduct
+       $(CC) -o $@ strongsim.c $(CFLAGS) $(LIBS) libshrink.so 
+
+matrix: matrix.h matrix.c
+       $(CC) -c -Werror -Wall -fpic matrix.c
+       $(CC) -shared -o libmatrix.so matrix.o
+
+exponentialsum: exponentialsum.h exponentialsum.c
+       $(CC) -c -Wall -fpic exponentialsum.c
+       $(CC) -shared -o libexponentialsum.so exponentialsum.o -lm libmatrix.so
+
+shrink: shrink.h shrink.c
+       $(CC) -c -Wall -fpic shrink.c
+       $(CC) -shared -o libshrink.so shrink.o -lm libmatrix.so
+
+extend: extend.h extend.c
+       $(CC) -c -Werror -Wall -fpic extend.c
+       $(CC) -shared -o libextend.so extend.o -lm libmatrix.so
+
+measurepauli: measurepauli.h measurepauli.c
+       $(CC) -c -Wall -fpic measurepauli.c
+       $(CC) -shared -o libmeasurepauli.so measurepauli.o -lm libextend.so libshrink.so libmatrix.so
+
+innerproduct: innerproduct.h innerproduct.c
+       $(CC) -c -Wall -fpic innerproduct.c
+       $(CC) -shared -o libinnerproduct.so innerproduct.o -lm libextend.so libshrink.so libexponentialsum.so libmatrix.so
+
+innerproductintersection: innerproductintersection.h innerproductintersection.c
+       $(CC) -c -Wall -fpic innerproductintersection.c
+       $(CC) -shared -o libinnerproductintersection.so innerproductintersection.o -lm libextend.so libshrink.so libexponentialsum.so libmatrix.so
+
+shrinkstar: shrinkstar.h shrinkstar.c
+       $(CC) -c -Wall -fpic shrinkstar.c
+       $(CC) -shared -o libshrinkstar.so shrinkstar.o -lm libmatrix.so
+
+randomstabilizerstate: randomstabilizerstate.h randomstabilizerstate.c
+       $(CC) -c -Wall -fpic randomstabilizerstate.c
+       $(CC) -shared -o librandomstabilizerstate.so randomstabilizerstate.o -lm libmatrix.so libshrinkstar.so -llapacke
+
+randominputcommutingHermitianPauli: randominputcommutingHermitianPauli.c
+       $(CC) -o randominputcommutingHermitianPauli randominputcommutingHermitianPauli.c
+
+randominputPauli: randominputPauli.c
+       $(CC) -o randominputPauli randominputPauli.c
+
+multipauli: multipauli.c
+       $(CC) -o multipauli multipauli.c -lm
+
+.PHONY: clean
+
+clean:
+       rm ./strongsim ./matrix.o ./libmatrix.so ./exponentialsum.o ./libexponentialsum.so ./shrink.o ./libshrink.so ./extend.o ./libextend.so ./measurepauli.o ./libmeasurepauli.so ./libinnerproduct.so
+
+# you might want to update LD_LIBRARY_PATH to see the library:
+# export LD_LIBRARY_PATH=$PWD:$LD_LIBRARY_PATH
+# or if you have root privileges put the library /usr/local/lib or whatever library directory in your path
+# Then, use ldconfig to write the path in the config file:
+# sudo echo "/usr/local/lib" >> /etc/ld.so.conf
+#  sudo ldconfig
+
+
diff --git a/Pd.txt b/Pd.txt
new file mode 100644 (file)
index 0000000..6245c22
--- /dev/null
+++ b/Pd.txt
@@ -0,0 +1,51 @@
+50
+0.666667 0.333333
+0.533333 0.4 0.0666667
+0.474074 0.414815 0.103704 0.00740741
+0.446187 0.418301 0.122004 0.0130719 0.00043573
+0.432667 0.419146 0.130983 0.0163729 0.000818644 0.0000132039
+0.42601 0.419354 0.135416 0.0181361 0.00105794 0.0000255953 2.03137E-7
+0.422708 0.419405 0.137617 0.0190453 0.00119033 0.000033598 3.99976E-7 1.57471E-9
+0.421063 0.419418 0.138714 0.0195066 0.0012598 0.0000380989 5.29151E-7 3.12491E-9 6.12727E-12
+0.420242 0.419421 0.139261 0.019739 0.00129537 0.0000404804 6.02387E-7 4.1503E-9 1.22068E-11 1.1944E-14
+0.419832 0.419422 0.139534 0.0198556 0.00131337 0.0000417047 6.41292E-7 4.73395E-9 1.62439E-11 2.38414E-14 1.16527E-17
+0.419627 0.419422 0.139671 0.019914 0.00132242 0.0000423253 6.61333E-7 5.04461E-9 1.85464E-11 3.17575E-14 2.32826E-17 5.68701E-21
+0.419525 0.419422 0.139739 0.0199432 0.00132695 0.0000426377 6.71502E-7 5.2048E-9 1.97731E-11 3.62766E-14 3.10283E-17 1.13685E-20 1.38809E-24
+0.419474 0.419422 0.139773 0.0199579 0.00132923 0.0000427945 6.76624E-7 5.28613E-9 2.0406E-11 3.86856E-14 3.54523E-17 1.51543E-20 2.7755E-24 1.69424E-28
+0.419448 0.419422 0.13979 0.0199652 0.00133036 0.000042873 6.79195E-7 5.3271E-9 2.07274E-11 3.99286E-14 3.78112E-17 1.7317E-20 3.70022E-24 3.38807E-28 1.03402E-32
+0.419435 0.419422 0.139799 0.0199688 0.00133093 0.0000429123 6.80482E-7 5.34766E-9 2.08893E-11 4.05599E-14 3.90285E-17 1.84704E-20 4.22857E-24 4.51715E-28 2.06791E-32 3.15548E-37
+0.419429 0.419422 0.139803 0.0199707 0.00133122 0.0000429319 6.81127E-7 5.35797E-9 2.09706E-11 4.0878E-14 3.96468E-17 1.90656E-20 4.51033E-24 5.1623E-28 2.75713E-32 6.31077E-37 4.81481E-42
+0.419426 0.419422 0.139805 0.0199716 0.00133136 0.0000429418 6.81449E-7 5.36312E-9 2.10113E-11 4.10377E-14 3.99584E-17 1.93679E-20 4.65576E-24 5.50637E-28 3.15096E-32 8.41423E-37 9.62947E-42 3.67338E-47
+0.419424 0.419422 0.139806 0.019972 0.00133143 0.0000429467 6.8161E-7 5.3657E-9 2.10317E-11 4.11177E-14 4.01148E-17 1.95203E-20 4.72962E-24 5.68395E-28 3.361E-32 9.61619E-37 1.28392E-41 7.3467E-47 1.40128E-52
+0.419423 0.419422 0.139807 0.0199723 0.00133146 0.0000429491 6.81691E-7 5.36699E-9 2.10419E-11 4.11577E-14 4.01931E-17 1.95968E-20 4.76684E-24 5.77415E-28 3.4694E-32 1.02572E-36 1.46733E-41 9.79556E-47 2.80254E-52 2.67272E-58
+0.419423 0.419422 0.139807 0.0199724 0.00133148 0.0000429504 6.81731E-7 5.36763E-9 2.1047E-11 4.11778E-14 4.02323E-17 1.96351E-20 4.78553E-24 5.8196E-28 3.52447E-32 1.05881E-36 1.56515E-41 1.11949E-46 3.73672E-52 5.34543E-58 2.5489E-64
+0.419423 0.419422 0.139807 0.0199724 0.00133149 0.000042951 6.81751E-7 5.36796E-9 2.10495E-11 4.11878E-14 4.02519E-17 1.96543E-20 4.79489E-24 5.84242E-28 3.55222E-32 1.07561E-36 1.61564E-41 1.19412E-46 4.27053E-52 7.12723E-58 5.0978E-64 1.21541E-70
+0.419423 0.419422 0.139807 0.0199725 0.0013315 0.0000429513 6.81761E-7 5.36812E-9 2.10508E-11 4.11928E-14 4.02617E-17 1.96639E-20 4.79957E-24 5.85385E-28 3.56614E-32 1.08408E-36 1.64128E-41 1.23264E-46 4.55523E-52 8.1454E-58 6.79706E-64 2.43082E-70 2.89776E-77
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429515 6.81766E-7 5.3682E-9 2.10514E-11 4.11953E-14 4.02667E-17 1.96687E-20 4.80192E-24 5.85957E-28 3.57312E-32 1.08833E-36 1.6542E-41 1.25221E-46 4.70217E-52 8.68843E-58 7.76807E-64 3.24109E-70 5.79552E-77 3.4544E-84
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429515 6.81769E-7 5.36824E-9 2.10518E-11 4.11966E-14 4.02691E-17 1.96711E-20 4.80309E-24 5.86243E-28 3.57661E-32 1.09046E-36 1.66069E-41 1.26207E-46 4.77681E-52 8.9687E-58 8.28594E-64 3.7041E-70 7.72737E-77 6.9088E-84 2.05898E-91
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.8177E-7 5.36826E-9 2.10519E-11 4.11972E-14 4.02703E-17 1.96723E-20 4.80368E-24 5.86386E-28 3.57836E-32 1.09153E-36 1.66394E-41 1.26702E-46 4.81442E-52 9.11106E-58 8.55322E-64 3.95104E-70 8.83127E-77 9.21174E-84 4.11797E-91 6.13625E-99
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81771E-7 5.36827E-9 2.1052E-11 4.11975E-14 4.02709E-17 1.96729E-20 4.80397E-24 5.86458E-28 3.57924E-32 1.09206E-36 1.66557E-41 1.2695E-46 4.8333E-52 9.1828E-58 8.68899E-64 4.0785E-70 9.42003E-77 1.05277E-83 5.49062E-91 1.22725E-98 9.14373E-107
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81771E-7 5.36827E-9 2.1052E-11 4.11976E-14 4.02713E-17 1.96732E-20 4.80412E-24 5.86494E-28 3.57967E-32 1.09233E-36 1.66638E-41 1.27074E-46 4.84276E-52 9.21881E-58 8.75741E-64 4.14324E-70 9.7239E-77 1.12295E-83 6.275E-91 1.63633E-98 1.82875E-106 6.81261E-115
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81771E-7 5.36828E-9 2.10521E-11 4.11977E-14 4.02714E-17 1.96733E-20 4.80419E-24 5.86511E-28 3.57989E-32 1.09246E-36 1.66679E-41 1.27136E-46 4.84749E-52 9.23685E-58 8.79175E-64 4.17586E-70 9.87824E-77 1.15918E-83 6.69333E-91 1.8701E-98 2.43833E-106 1.36252E-114 2.53789E-123
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81771E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02715E-17 1.96734E-20 4.80423E-24 5.8652E-28 3.58E-32 1.09253E-36 1.66699E-41 1.27167E-46 4.84986E-52 9.24588E-58 8.80895E-64 4.19223E-70 9.95603E-77 1.17758E-83 6.90925E-91 1.99477E-98 2.78666E-106 1.8167E-114 5.07579E-123 4.7272E-132
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81771E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02715E-17 1.96734E-20 4.80424E-24 5.86525E-28 3.58006E-32 1.09256E-36 1.66709E-41 1.27182E-46 4.85105E-52 9.2504E-58 8.81757E-64 4.20044E-70 9.99507E-77 1.18685E-83 7.01892E-91 2.05912E-98 2.97244E-106 2.07622E-114 6.76772E-123 9.45439E-132 4.40254E-141
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02715E-17 1.96734E-20 4.80425E-24 5.86527E-28 3.58008E-32 1.09258E-36 1.66714E-41 1.2719E-46 4.85164E-52 9.25265E-58 8.82187E-64 4.20454E-70 1.00146E-76 1.19151E-83 7.07418E-91 2.0918E-98 3.06832E-106 2.21464E-114 7.73453E-123 1.26059E-131 8.80509E-141 2.05009E-150
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02715E-17 1.96734E-20 4.80426E-24 5.86528E-28 3.5801E-32 1.09259E-36 1.66717E-41 1.27194E-46 4.85193E-52 9.25378E-58 8.82403E-64 4.2066E-70 1.00244E-76 1.19384E-83 7.10193E-91 2.10827E-98 3.11703E-106 2.28608E-114 8.25017E-123 1.44067E-131 1.17401E-140 4.10019E-150 4.77325E-160
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96734E-20 4.80426E-24 5.86529E-28 3.5801E-32 1.09259E-36 1.66718E-41 1.27196E-46 4.85208E-52 9.25435E-58 8.8251E-64 4.20763E-70 1.00293E-76 1.195E-83 7.11582E-91 2.11654E-98 3.14157E-106 2.32236E-114 8.5163E-123 1.53671E-131 1.34173E-140 5.46692E-150 9.54649E-160 5.55679E-170
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96735E-20 4.80426E-24 5.86529E-28 3.58011E-32 1.09259E-36 1.66719E-41 1.27197E-46 4.85216E-52 9.25463E-58 8.82564E-64 4.20814E-70 1.00318E-76 1.19559E-83 7.12278E-91 2.12068E-98 3.15389E-106 2.34065E-114 8.65148E-123 1.58629E-131 1.43118E-140 6.24791E-150 1.27287E-159 1.11136E-169 3.23448E-180
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96735E-20 4.80426E-24 5.86529E-28 3.58011E-32 1.0926E-36 1.66719E-41 1.27197E-46 4.85219E-52 9.25477E-58 8.82591E-64 4.2084E-70 1.0033E-76 1.19588E-83 7.12626E-91 2.12275E-98 3.16006E-106 2.34983E-114 8.7196E-123 1.61146E-131 1.47734E-140 6.66443E-150 1.4547E-159 1.48181E-169 6.46896E-180 9.41357E-191
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96735E-20 4.80426E-24 5.86529E-28 3.58011E-32 1.0926E-36 1.66719E-41 1.27198E-46 4.85221E-52 9.25484E-58 8.82605E-64 4.20853E-70 1.00336E-76 1.19603E-83 7.128E-91 2.12379E-98 3.16315E-106 2.35443E-114 8.7538E-123 1.62415E-131 1.50079E-140 6.87941E-150 1.55168E-159 1.6935E-169 8.62528E-180 1.88271E-190 1.36985E-201
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96735E-20 4.80426E-24 5.86529E-28 3.58011E-32 1.0926E-36 1.66719E-41 1.27198E-46 4.85222E-52 9.25488E-58 8.82611E-64 4.20859E-70 1.00339E-76 1.1961E-83 7.12887E-91 2.12431E-98 3.16469E-106 2.35673E-114 8.77093E-123 1.63052E-131 1.51261E-140 6.98861E-150 1.60174E-159 1.8064E-169 9.85746E-180 2.51029E-190 2.73971E-201 9.96701E-213
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96735E-20 4.80426E-24 5.86529E-28 3.58011E-32 1.0926E-36 1.66719E-41 1.27198E-46 4.85223E-52 9.2549E-58 8.82615E-64 4.20862E-70 1.00341E-76 1.19614E-83 7.1293E-91 2.12457E-98 3.16547E-106 2.35788E-114 8.7795E-123 1.63371E-131 1.51854E-140 7.04364E-150 1.62716E-159 1.86467E-169 1.05146E-179 2.8689E-190 3.65295E-201 1.9934E-212 3.62598E-224
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96735E-20 4.80426E-24 5.86529E-28 3.58011E-32 1.0926E-36 1.66719E-41 1.27198E-46 4.85223E-52 9.2549E-58 8.82617E-64 4.20864E-70 1.00341E-76 1.19615E-83 7.12952E-91 2.1247E-98 3.16585E-106 2.35846E-114 8.78379E-123 1.63531E-131 1.52151E-140 7.07126E-150 1.63998E-159 1.89427E-169 1.08538E-179 3.06016E-190 4.1748E-201 2.65787E-212 7.25195E-224 6.59561E-236
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96735E-20 4.80426E-24 5.86529E-28 3.58011E-32 1.0926E-36 1.66719E-41 1.27198E-46 4.85223E-52 9.25491E-58 8.82617E-64 4.20865E-70 1.00342E-76 1.19616E-83 7.12963E-91 2.12476E-98 3.16605E-106 2.35875E-114 8.78594E-123 1.63611E-131 1.523E-140 7.0851E-150 1.64641E-159 1.90918E-169 1.10261E-179 3.15887E-190 4.45312E-201 3.03756E-212 9.66927E-224 1.31912E-235 5.99867E-248
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96735E-20 4.80426E-24 5.86529E-28 3.58011E-32 1.0926E-36 1.66719E-41 1.27198E-46 4.85223E-52 9.25491E-58 8.82618E-64 4.20865E-70 1.00342E-76 1.19617E-83 7.12968E-91 2.1248E-98 3.16614E-106 2.35889E-114 8.78701E-123 1.63651E-131 1.52375E-140 7.09203E-150 1.64963E-159 1.91667E-169 1.11129E-179 3.20901E-190 4.59676E-201 3.24007E-212 1.10506E-223 1.75883E-235 1.19973E-247 2.72788E-260
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96735E-20 4.80426E-24 5.86529E-28 3.58011E-32 1.0926E-36 1.66719E-41 1.27198E-46 4.85223E-52 9.25491E-58 8.82618E-64 4.20865E-70 1.00342E-76 1.19617E-83 7.12971E-91 2.12481E-98 3.16619E-106 2.35896E-114 8.78755E-123 1.63671E-131 1.52412E-140 7.09549E-150 1.65124E-159 1.92042E-169 1.11565E-179 3.23428E-190 4.66973E-201 3.34459E-212 1.17873E-223 2.01009E-235 1.59965E-247 5.45576E-260 6.20248E-273
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96735E-20 4.80426E-24 5.86529E-28 3.58011E-32 1.0926E-36 1.66719E-41 1.27198E-46 4.85223E-52 9.25491E-58 8.82618E-64 4.20865E-70 1.00342E-76 1.19617E-83 7.12973E-91 2.12482E-98 3.16622E-106 2.359E-114 8.78781E-123 1.63681E-131 1.5243E-140 7.09722E-150 1.65205E-159 1.9223E-169 1.11783E-179 3.24696E-190 4.7065E-201 3.39767E-212 1.21675E-223 2.1441E-235 1.82817E-247 7.27435E-260 1.2405E-272 7.05141E-286
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96735E-20 4.80426E-24 5.86529E-28 3.58011E-32 1.0926E-36 1.66719E-41 1.27198E-46 4.85223E-52 9.25491E-58 8.82618E-64 4.20865E-70 1.00342E-76 1.19617E-83 7.12973E-91 2.12482E-98 3.16623E-106 2.35901E-114 8.78795E-123 1.63686E-131 1.5244E-140 7.09809E-150 1.65245E-159 1.92324E-169 1.11892E-179 3.25332E-190 4.72496E-201 3.42443E-212 1.23607E-223 2.21326E-235 1.95004E-247 8.31354E-260 1.654E-272 1.41028E-285 4.00826E-299
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96735E-20 4.80426E-24 5.86529E-28 3.58011E-32 1.0926E-36 1.66719E-41 1.27198E-46 4.85223E-52 9.25491E-58 8.82618E-64 4.20865E-70 1.00342E-76 1.19617E-83 7.12974E-91 2.12483E-98 3.16623E-106 2.35902E-114 8.78802E-123 1.63688E-131 1.52444E-140 7.09852E-150 1.65265E-159 1.92371E-169 1.11947E-179 3.2565E-190 4.7342E-201 3.43786E-212 1.2458E-223 2.24839E-235 2.01295E-247 8.86778E-260 1.89028E-272 1.88038E-285 8.01652E-299 1.13922E-312
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96735E-20 4.80426E-24 5.86529E-28 3.58011E-32 1.0926E-36 1.66719E-41 1.27198E-46 4.85223E-52 9.25491E-58 8.82618E-64 4.20865E-70 1.00342E-76 1.19617E-83 7.12974E-91 2.12483E-98 3.16624E-106 2.35903E-114 8.78805E-123 1.6369E-131 1.52447E-140 7.09874E-150 1.65275E-159 1.92394E-169 1.11974E-179 3.25809E-190 4.73883E-201 3.44459E-212 1.25069E-223 2.2661E-235 2.0449E-247 9.15384E-260 2.0163E-272 2.149E-285 1.06887E-298 2.27843E-312 0.
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96735E-20 4.80426E-24 5.86529E-28 3.58011E-32 1.0926E-36 1.66719E-41 1.27198E-46 4.85223E-52 9.25491E-58 8.82618E-64 4.20865E-70 1.00342E-76 1.19617E-83 7.12974E-91 2.12483E-98 3.16624E-106 2.35903E-114 8.78807E-123 1.6369E-131 1.52448E-140 7.09885E-150 1.6528E-159 1.92406E-169 1.11988E-179 3.25889E-190 4.74114E-201 3.44795E-212 1.25313E-223 2.27498E-235 2.061E-247 9.29913E-260 2.08134E-272 2.29227E-285 1.22157E-298 3.03791E-312 0. 0.
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96735E-20 4.80426E-24 5.86529E-28 3.58011E-32 1.0926E-36 1.66719E-41 1.27198E-46 4.85223E-52 9.25491E-58 8.82618E-64 4.20865E-70 1.00342E-76 1.19617E-83 7.12974E-91 2.12483E-98 3.16624E-106 2.35903E-114 8.78807E-123 1.6369E-131 1.52448E-140 7.0989E-150 1.65283E-159 1.92412E-169 1.11995E-179 3.25928E-190 4.7423E-201 3.44964E-212 1.25436E-223 2.27944E-235 2.06909E-247 9.37236E-260 2.11438E-272 2.36621E-285 1.303E-298 3.4719E-312 0. 0. 0.
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96735E-20 4.80426E-24 5.86529E-28 3.58011E-32 1.0926E-36 1.66719E-41 1.27198E-46 4.85223E-52 9.25491E-58 8.82618E-64 4.20865E-70 1.00342E-76 1.19617E-83 7.12974E-91 2.12483E-98 3.16624E-106 2.35903E-114 8.78808E-123 1.63691E-131 1.52449E-140 7.09893E-150 1.65284E-159 1.92415E-169 1.11998E-179 3.25948E-190 4.74288E-201 3.45048E-212 1.25497E-223 2.28166E-235 2.07313E-247 9.40911E-260 2.13103E-272 2.40377E-285 1.34504E-298 3.70336E-312 0. 0. 0. 0.
+0.419422 0.419422 0.139807 0.0199725 0.0013315 0.0000429516 6.81772E-7 5.36828E-9 2.10521E-11 4.11978E-14 4.02716E-17 1.96735E-20 4.80426E-24 5.86529E-28 3.58011E-32 1.0926E-36 1.66719E-41 1.27198E-46 4.85223E-52 9.25491E-58 8.82618E-64 4.20865E-70 1.00342E-76 1.19617E-83 7.12974E-91 2.12483E-98 3.16624E-106 2.35903E-114 8.78808E-123 1.63691E-131 1.52449E-140 7.09894E-150 1.65285E-159 1.92416E-169 1.12E-179 3.25958E-190 4.74317E-201 3.4509E-212 1.25528E-223 2.28278E-235 2.07516E-247 9.42752E-260 2.13938E-272 2.4227E-285 1.36638E-298 3.82282E-312 0. 0. 0. 0. 0.
diff --git a/README.txt b/README.txt
new file mode 100644 (file)
index 0000000..6a53e3a
--- /dev/null
@@ -0,0 +1,56 @@
+Strong simulation of multi-Pauli measurements using minimal stabilizer state decompositions
+-------------------------------------------------------------------------------------------
+
+BUILD:
+
+1. We start with the code that scales quadratically with stabilizer rank because it calculates expectation values to zero relative error. Build code for stabilizer rank tensor multiple you'd like to use. Here we choose k=6.
+$ cp strongsim6.c strongsim.c
+$ make strongsim
+
+2. Now we build the code that scales linearly with stabilizer rank because it calculates expectation values to non-zero relative error. Build code for stabilizer rank tensor multiple you'd like to use. Here we choose k=6.
+$ cp strongsim6_relerr.c strongsim_relerr.c
+$ make strongsim_relerr
+
+3. This produces libraries (*.so) of core functions like SHRINK, INNERPRODUCT, EXTEND, etc. since you might want to use them in other code. This means we need to put them somewhere the linker can find them. Follow 3a) for a temporary and easy method that will only be valid for the current shell session and follow 3b) for a persistent method that requires root access.
+3a) Update LD_LIBRARY_PATH to see the library:
+$ export LD_LIBRARY_PATH=$PWD:$LD_LIBRARY_PATH
+or
+3b) If you have root privileges put the *so library /usr/local/lib or whatever library directory in your path. Then, use ldconfig to write the path in the config file:
+$ sudo cp ./*so /usr/local/lib
+$ sudo echo "/usr/local/lib" >> /etc/ld.so.conf
+$ sudo ldconfig
+
+4. Build code for generating random commuting Pauli inputs (necessary for the strongsim[1-12]_relerr.c code since it requires a Hermitian observable to get away with using the square root number of stabilizer states).
+$ make randominputcommutingHermitianPauli2
+
+5. Build code for generating random (non-commuting) Pauli inputs (good enough for the strongsim[1-12].c code).
+$ make randominputFauli
+
+6. Build Hilbert vector space code to check our results.
+$ make multipauli
+
+
+TEST CODE:
+1. Run test diagonositic for strongsim.c (zero relative error).
+$ bash ./test.bash
+
+2. Run test diagonositic for strongsim_relerr.c (non-zero relative error).
+$ bash ./test2.bash
+
+
+
+Details of source code files:
+
+strongsim[1-12]_relerror.c takes one argument of the number of stabilizer states to sample and then takes stdin arguments for the number of qubits, t-gate magic states and then the Paulis
+
+strongsim[1-12]_relerror.c scale linearly with the stabilizer rank and calculate up to finite relative error while strongsim[1-12].c scale quadratically with the stabilizer rank and calculate up to zero relative error.
+
+strongsim*c need Pauli measurement inputs (with the associated phases) which can be randomly generated with randominputPauli.c and the output from strongsim*c can be verified with multipauli.c
+
+strongsim[1-12]_relerror.c need commuting Pauli measurement inputs (with the associated phasese) which can be randomly generated with randominputcommutingHermitianPauli2.c and can be verified with multipauli.c
+
+randominputcommutingHermitianPauli.c uses a brute-force random sampling of the commuting Paulis whereas *2.c uses random Clifford operations on initially separable Paulis to generate the commuting Paulis. *2.c is the only practically viable method for more than 30 Paulis on a desktop computer.
+
+NOTE: current strongsim*c only support the same number of T gates as number of qubits!
+
+Pd.txt is a tabulated list of P(d) values for strongsim[1-12]_relerror.c.
diff --git a/exponentialsum.c b/exponentialsum.c
new file mode 100644 (file)
index 0000000..0e0bd6e
--- /dev/null
@@ -0,0 +1,415 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <complex.h>
+
+#include "matrix.h"
+#include "exponentialsum.h"
+
+// linked list
+struct Node {
+  int data;
+  struct Node* next;
+};
+
+void printLinkedList(struct Node *node);
+void append(struct Node** head_ref, int new_data);
+void append2(struct Node** head_ref, struct Node** last_ref, int new_data);
+void freeList(struct Node** head_ref);
+
+complex double exponentialsum(int *k, int *Q, int *D, int **J) {
+
+  int a, b, c, d;
+
+  int tmp;
+
+  struct Node* setS = NULL;
+  struct Node* setWalker = NULL;
+  struct Node* setWalker2 = NULL;
+
+  struct Node* setDa = NULL; // first element in \mathcal D
+  struct Node* setDb = NULL; // second element in \mathcal D (sets should have the same size)
+
+  int setSleftover = -1;  // -1 means nothing left over
+
+  int** R;  // basis change matrix R and R^T
+  int** RT;
+  R = calloc(*k, sizeof(int*));
+  RT = calloc(*k, sizeof(int*));
+  // initially set it to the k-dimensional identity matrix
+  for(a=0; a<*k; a++) {
+    R[a] = calloc(*k, sizeof(int));
+    R[a][a] = 1;
+    RT[a] = calloc(*k, sizeof(int));
+    RT[a][a] = 1;
+  }
+
+  int* tmpVec; // temporary vector used in Eq. 49 to update D
+  int** tmpMatrix; // temporary matrix used to store intermediate value of J = R times J times R^T
+  tmpMatrix = calloc(*k, sizeof(int*));
+  for(a=0; a<*k; a++)
+    tmpMatrix[a] = calloc(*k, sizeof(int));
+
+  for(a=0; a<*k; a++) {
+    if(D[a] == 2 || D[a] == 6) {
+      append(&setS, a);
+    }
+  }
+
+  // Choose 'a' to be the first element in the linked list setS; a=setS->data
+
+  if(setS != NULL) {
+    setWalker = setS;
+    while(setWalker->next != NULL) {
+      setWalker = setWalker->next;
+      R[setWalker->data][setS->data] += 1;
+    }
+
+    tmpVec = calloc(*k, sizeof(int));
+    for(c=0;c<*k;c++) {
+      tmp = 0;
+      /* //tmpVec[c] = 0; */
+      /* for(a=0;a<*k;a++) // don't confuse this for-loop a with 'a'=setS->data */
+      /*       tmpVec[c] = tmpVec[c] + R[c][a]*D[a]; */
+      /* for(a=0;a<*k;a++) */
+      /*       for(b=a+1;b<*k;b++) */
+      /*         tmpVec[c] = tmpVec[c] + J[a][b]*R[c][a]*R[c][b]; */
+      /* tmpVec[c] = tmpVec[c]%8; */
+      if(c!=setS->data)
+       tmp += R[c][c]*D[c];
+      tmp += R[c][setS->data]*D[setS->data];
+      if(setS->data>c)
+       tmp += J[c][setS->data]*R[c][c]*R[c][setS->data];
+      else if(setS->data<c)
+       tmp += J[setS->data][c]*R[c][setS->data]*R[c][c];
+      tmpVec[c] = tmp%8;
+    }
+    memcpy(D, tmpVec, sizeof(int)*(*k));
+    free(tmpVec);
+
+    // Eq. 50 update of J
+    for(c=0;c<*k;c++) {
+      for(d=0;d<*k; d++) {
+       tmp = 0;
+       if(c!=setS->data) {
+         if(d!=setS->data) {
+           tmp += R[c][c]*J[c][d]*R[d][d];
+           tmp += R[c][c]*J[c][setS->data]*R[d][setS->data];
+           tmp += R[c][setS->data]*J[setS->data][d]*R[d][d];
+         }else {
+           tmp += R[c][c]*J[c][setS->data]*R[d][setS->data];
+         }
+       } else {
+         if(d!=setS->data) {
+           tmp += R[c][setS->data]*J[setS->data][d]*R[d][d];
+         }
+       }
+       tmp += R[c][setS->data]*J[setS->data][setS->data]*R[d][setS->data];
+       tmp %= 8;
+       tmpMatrix[c][d] = tmp;
+      }
+    }
+    for(c=0; c<*k; c++)
+      memcpy(J[c], tmpMatrix[c], sizeof(int)*(*k));
+    /* transp(R,RT,*k,*k); */
+    /* multMatrixMod(J,RT,tmpMatrix,*k,*k,*k,*k,8); */
+    /* multMatrixMod(R,tmpMatrix,J,*k,*k,*k,*k,8); */
+
+    // remove everything but first element from setS
+    //tmp = setS->data;
+    //freeList(&setS);
+    //append(&setS, tmp);
+    //setS->next = NULL;
+    setSleftover = setS->data;
+  }
+
+  struct Node* setE = NULL;
+
+  for(a=0;a<*k;a++) {
+    //if((setS != NULL && a != setS->data) || setS == NULL)
+    if((setSleftover != -1 && a != setSleftover) || setSleftover == -1)
+      append(&setE, a);
+  }
+
+  struct Node* setM = NULL;
+  int setMCount = 0; // number of elements in M
+
+  int r = 0;
+
+  while(setE != NULL) {
+    // let 'a' be setE->data (the first element in setE)
+    struct Node* setK = NULL;
+    setWalker = setE;
+    while(setWalker->next != NULL) {
+      setWalker = setWalker->next;
+      if(J[setE->data][setWalker->data] == 4)
+       append(&setK, setWalker->data);
+    }
+
+    if(setK == NULL) { // Found new monomer {'a'}
+      append(&setM, setE->data);
+      setMCount++;
+
+      if(setE->next != NULL) {
+       setE->data = setE->next->data;
+       setE->next = setE->next->next;
+      }
+      else setE = NULL;
+    } else {
+      // let 'b' be setK->data (the first element in setK)
+      setWalker = setE->next;
+      // reset 'R' to the k-dimensional identity matrix
+      for(a=0; a<*k; a++) {
+       memset(R[a], 0, sizeof(int)*(*k)); 
+       //for(b=0; b<*k; b++)
+       //  R[a][b] = 0;
+       R[a][a] = 1;
+      }
+         
+      while(setWalker != NULL) {
+       if(setWalker->data == setK->data) {
+         setWalker = setWalker->next;
+         continue;  // 'c' \in E minus {'a', 'b'} where 'a'=setE->data, 'b'=setK->data and 'c'=setWalker->data
+       }
+       R[setWalker->data][setK->data] = J[setE->data][setWalker->data]/4; // divide by 4 to get binary matrix \bs J from J
+       R[setWalker->data][setE->data] = J[setK->data][setWalker->data]/4; // divide by 4 to get binary matrix \bs J from J
+       setWalker = setWalker->next;
+      }
+      // update D and J
+      tmpVec = calloc(*k, sizeof(int));
+      for(c=0;c<*k;c++) {
+       tmp = 0;
+       //tmpVec[c] = 0;
+       /* for(a=0;a<*k;a++) {// don't confuse this for-loop a with 'a'=setS->data */
+       /*   tmp+= R[c][a]*D[a]; */
+       /* //for(a=0;a<*k;a++) */
+       /*   for(b=a+1;b<*k;b++) */
+       /*     tmp += J[a][b]*R[c][a]*R[c][b]; */
+       /* } */
+       if(c!=setK->data && c!=setE->data)
+         tmp += R[c][c]*D[c];
+       tmp += R[c][setK->data]*D[setK->data];
+       tmp += R[c][setE->data]*D[setE->data];
+       if(setK->data>setE->data)
+         tmp += J[setE->data][setK->data]*R[c][setE->data]*R[c][setK->data];
+       else if(setE->data>setK->data)
+         tmp += J[setK->data][setE->data]*R[c][setK->data]*R[c][setE->data];
+       if(setK->data>c)
+         tmp += J[c][setK->data]*R[c][c]*R[c][setK->data];
+       else if(setK->data<c)
+         tmp += J[setK->data][c]*R[c][setK->data]*R[c][c];
+       if(setE->data>c)
+         tmp += J[c][setE->data]*R[c][c]*R[c][setE->data];
+       else if(setE->data<c)
+         tmp += J[setE->data][c]*R[c][setE->data]*R[c][c];
+       tmpVec[c] = tmp%8;
+      }
+      memcpy(D, tmpVec, sizeof(int)*(*k));
+      free(tmpVec);
+
+      // Eq. 50 update of J
+      for(c=0;c<*k;c++) {
+       for(d=0;d<*k; d++) {
+         tmp = 0;
+         if(c!=setK->data && c!=setE->data) {
+           if(d!=setK->data && d!=setE->data) {
+             tmp += R[c][c]*J[c][d]*R[d][d];
+             tmp += R[c][c]*J[c][setK->data]*R[d][setK->data];
+             tmp += R[c][c]*J[c][setE->data]*R[d][setE->data];
+             tmp += R[c][setK->data]*J[setK->data][d]*R[d][d];
+             tmp += R[c][setE->data]*J[setE->data][d]*R[d][d];
+           }else {
+             tmp += R[c][c]*J[c][setK->data]*R[d][setK->data];
+             tmp += R[c][c]*J[c][setE->data]*R[d][setE->data];
+           }
+         } else {
+           if(d!=setK->data && d!=setE->data) {
+             tmp += R[c][setK->data]*J[setK->data][d]*R[d][d];
+             tmp += R[c][setE->data]*J[setE->data][d]*R[d][d];
+           }
+         }
+         tmp += R[c][setK->data]*J[setK->data][setK->data]*R[d][setK->data];
+         tmp += R[c][setE->data]*J[setE->data][setK->data]*R[d][setK->data];
+         tmp += R[c][setK->data]*J[setK->data][setE->data]*R[d][setE->data];
+         tmp += R[c][setE->data]*J[setE->data][setE->data]*R[d][setE->data];
+         tmp %= 8;
+         tmpMatrix[c][d] = tmp;
+       }
+      }
+      J = tmpMatrix;
+      /* transp(R,RT,*k,*k); */
+      /* multMatrixMod(J,RT,tmpMatrix,*k,*k,*k,*k,8); */
+      /* multMatrixMod(R,tmpMatrix,J,*k,*k,*k,*k,8); */
+
+      // Now {'a','b'} form a dimer
+      r++;
+      append(&setDa,setE->data);
+      append(&setDb,setK->data);
+
+      // E = E minus {'a', 'b'}
+      setWalker = setE; // 'a'=setE->data
+      while(setWalker != NULL) {
+       if(setWalker->next->data == setK->data) {
+         free(setWalker->next);
+         setWalker->next = setWalker->next->next; // delete 'b'
+         break;
+       }
+       setWalker = setWalker->next;
+      }
+      setWalker = setE;
+      setE = setE->next; // delete 'a'
+      free(setWalker);
+    }
+
+    freeList(&setK);
+  }
+
+  complex double W = 0.0 + 0.0*I;
+  
+//if(setS == NULL) {
+  if(setSleftover == -1) {
+    W = cexp(I*PI*0.25*(*Q));
+    setWalker = setM;
+    for(a=0; a<setMCount; a++) {
+      W *= (1.0 + cexp(I*PI*0.25*D[setWalker->data]));
+      setWalker = setWalker->next;
+    }
+    setWalker = setDa;
+    setWalker2 = setDb;
+    for(a=0; a<r; a++) {
+      W *= (1.0 + cexp(I*PI*0.25*(D[setWalker->data])) + cexp(I*PI*0.25*(D[setWalker2->data])) - cexp(I*PI*0.25*(D[setWalker->data] + D[setWalker2->data])));
+      setWalker = setWalker->next;
+      setWalker2 = setWalker2->next;
+    }
+  } else {
+    complex double W0 = 0.0 + 0.0*I;
+    complex double W1 = 0.0 + 0.0*I;
+    
+    W0 = cexp(I*PI*0.25*(*Q));
+    setWalker = setM;
+    for(a=0; a<setMCount; a++) {
+      W0 *= (1.0 + cexp(I*PI*0.25*D[setWalker->data]));
+      setWalker = setWalker->next;
+    }
+    setWalker = setDa;
+    setWalker2 = setDb;
+    for(a=0; a<r; a++) {
+      W0 *= (1.0 + cexp(I*PI*0.25*(D[setWalker->data])) + cexp(I*PI*0.25*(D[setWalker2->data])) - cexp(I*PI*0.25*(D[setWalker->data] + D[setWalker2->data])));
+      setWalker = setWalker->next;
+      setWalker2 = setWalker2->next;
+    }
+    //    W1 = cexp(I*PI*0.25*(*Q+D[setS->data]));
+    W1 = cexp(I*PI*0.25*(*Q+D[setSleftover]));    
+    setWalker = setM;
+    for(a=0; a<setMCount; a++) {
+      //      W1 *= (1.0 + cexp(I*PI*0.25*(D[setWalker->data] + J[setWalker->data][setS->data])));
+      W1 *= (1.0 + cexp(I*PI*0.25*(D[setWalker->data] + J[setWalker->data][setSleftover])));
+      setWalker = setWalker->next;
+    }
+    setWalker = setDa;
+    setWalker2 = setDb;
+    for(a=0; a<r; a++) {
+      //      W1 *= (1.0 + cexp(I*PI*0.25*(J[setWalker->data][setS->data] + D[setWalker->data])) + cexp(I*PI*0.25*(J[setWalker2->data][setS->data] + D[setWalker2->data])) - cexp(I*PI*0.25*(J[setWalker->data][setS->data] + J[setWalker2->data][setS->data] + D[setWalker->data] + D[setWalker2->data])));
+      W1 *= (1.0 + cexp(I*PI*0.25*(J[setWalker->data][setSleftover] + D[setWalker->data])) + cexp(I*PI*0.25*(J[setWalker2->data][setSleftover] + D[setWalker2->data])) - cexp(I*PI*0.25*(J[setWalker->data][setSleftover] + J[setWalker2->data][setSleftover] + D[setWalker->data] + D[setWalker2->data])));      
+      setWalker = setWalker->next;
+      setWalker2 = setWalker2->next;
+    }
+    W = W0 + W1;
+  }
+
+  deallocate_mem(&tmpMatrix, *k);
+  deallocate_mem(&R, *k);
+  deallocate_mem(&RT, *k);
+
+  freeList(&setDa); freeList(&setDb); freeList(&setM); freeList(&setE); freeList(&setS);
+  
+  return(W);
+  
+}
+
+
+void append(struct Node** head_ref, int new_data) 
+{ 
+    struct Node* new_node = (struct Node*) malloc(sizeof(struct Node)); 
+    struct Node *last = *head_ref;   
+
+    new_node->data = new_data; 
+    new_node->next = NULL;
+
+    // if the linked list is empty, then make the new node as head
+    if (*head_ref == NULL) {
+      *head_ref = new_node; 
+      return; 
+    }   
+       
+    // else traverse till the last node
+    while (last->next != NULL) {
+        last = last->next; 
+    }
+    last->next = new_node;
+    
+    return;     
+} 
+
+/*void freeList(struct Node** head_ref)
+{ 
+       
+  struct Node *second_last_walker = *head_ref;
+  struct Node *walker = *head_ref;   
+
+    // else traverse till the last node
+    if(walker != NULL) {
+      while(walker->next != NULL) {
+       while(walker->next != NULL) {
+         //printf("!%d\n", walker->data);
+         second_last_walker = walker;
+         walker = walker->next;
+         //printf("%d\n", walker->data);
+         //printf("!%d\n", second_last_walker->data);
+       }
+       free(walker);
+       second_last_walker->next = NULL;
+       walker = *head_ref;
+       //printf("!!%d\n", second_last_walker->data);
+      }
+    }
+    free(walker);
+    
+    return;     
+    }*/
+
+void freeList(struct Node** head_ref)
+{ 
+       
+  struct Node *walker = *head_ref;
+  struct Node *walker2;   
+
+    // else traverse till the last node
+    if(walker != NULL) {
+      walker2 = walker->next;
+      while(walker2 != NULL) {
+       free(walker);
+       walker = walker2;
+       walker2 = walker->next;
+      }
+    }
+    free(walker);
+    
+    return;     
+}
+
+void printLinkedList(struct Node *node) 
+{
+  if(node == NULL)
+    printf("NULL\n");
+  else {
+    while (node != NULL) 
+      {
+       printf(" %d ", node->data);
+       node = node->next; 
+      }
+  }
+  printf("\n");
+}
+
diff --git a/exponentialsum.h b/exponentialsum.h
new file mode 100644 (file)
index 0000000..0be116f
--- /dev/null
@@ -0,0 +1,3 @@
+#define PI 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
+
+complex double exponentialsum(int *k, int *Q, int *D, int **J);
diff --git a/extend.c b/extend.c
new file mode 100644 (file)
index 0000000..18b2227
--- /dev/null
+++ b/extend.c
@@ -0,0 +1,177 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <complex.h>
+
+#include "matrix.h"
+#include "extend.h"
+
+// linked list
+struct Node {
+  int data;
+  struct Node* next;
+};
+
+void printLinkedList(struct Node *node);
+void append(struct Node** head_ref, int new_data);
+void freeList(struct Node** head_ref);
+
+/****************************************************************************
+ * Attempts to extend the dimension of the affine space by one dimension.
+ * The affine space is specified by 
+ * the first 'k' columns of the 'n'x'n' matrix 'G', translated by 'h',
+ * that will be extended to include the vector 'xi'. 'GBar' is 'G^(-1)^T'.
+ ****************************************************************************/
+
+void extend(int n, int *k, int *h, int **G, int **GBar, int *xi) {
+
+  int a;
+
+  struct Node* setS = NULL;
+  struct Node* setT = NULL;
+  struct Node* setWalker = NULL;
+
+  int i;
+
+  for(a=0; a<*k; a++) {
+    if(dotProductMod(xi, GBar[a], n, 2) == 1) {
+       append(&setS, a);
+    }
+  }
+  unsigned int firstT = 1; // set initially to true
+  for(a=*k; a<n; a++) {
+    if(dotProductMod(xi, GBar[a], n, 2) == 1) {
+      if(firstT) {
+       append(&setT, a);
+       i = a;
+       firstT = 0;
+      }
+      else {
+       append(&setS, a);
+       append(&setT, a);
+      }
+    }
+  }
+
+  if(setT == NULL) {
+    freeList(&setS);
+    freeList(&setT);
+    return; // xi is in the linear space so do nothing
+  }
+
+  setWalker = setS;
+  while(setWalker != NULL) {
+    // update GBar rows, gbar
+    for(a=0; a<n; a++)
+      GBar[setWalker->data][a] = (GBar[setWalker->data][a] + GBar[i][a])%2;
+    // update G rows, g
+    for(a=0; a<n; a++)
+      G[i][a] = (G[i][a] + G[setWalker->data][a])%2;
+
+    setWalker = setWalker->next;
+  }
+
+  // Swap 'i' and 'k+1'
+  int* tmpVec;
+  tmpVec = G[i];
+  G[i] = G[*k];
+  G[*k] = tmpVec;
+  tmpVec = GBar[i];
+  GBar[i] = GBar[*k];
+  GBar[*k] = tmpVec;
+
+  freeList(&setS);
+  freeList(&setT);
+    
+  // increment 'k'
+  *k = *k + 1;
+
+  return;
+    
+}
+
+
+void append(struct Node** head_ref, int new_data) 
+{ 
+    struct Node* new_node = (struct Node*) malloc(sizeof(struct Node)); 
+    struct Node *last = *head_ref;   
+
+    new_node->data = new_data; 
+    new_node->next = NULL;
+
+    // if the linked list is empty, then make the new node as head
+    if (*head_ref == NULL) {
+      *head_ref = new_node; 
+      return; 
+    }   
+       
+    // else traverse till the last node
+    while (last->next != NULL) {
+        last = last->next; 
+    }
+    last->next = new_node;
+
+    return;     
+}
+
+/*void freeList(struct Node** head_ref)
+{ 
+       
+  struct Node *second_last_walker = *head_ref;
+  struct Node *walker = *head_ref;   
+
+    // else traverse till the last node
+    if(walker != NULL) {
+      while(walker->next != NULL) {
+       while(walker->next != NULL) {
+         //printf("!%d\n", walker->data);
+         second_last_walker = walker;
+         walker = walker->next;
+         //printf("%d\n", walker->data);
+         //printf("!%d\n", second_last_walker->data);
+       }
+       free(walker);
+       second_last_walker->next = NULL;
+       walker = *head_ref;
+       //printf("!!%d\n", second_last_walker->data);
+      }
+    }
+    free(walker);
+    
+    return;     
+    }*/
+
+void freeList(struct Node** head_ref)
+{ 
+       
+  struct Node *walker = *head_ref;
+  struct Node *walker2;   
+
+    // else traverse till the last node
+    if(walker != NULL) {
+      walker2 = walker->next;
+      while(walker2 != NULL) {
+       free(walker);
+       walker = walker2;
+       walker2 = walker->next;
+      }
+    }
+    free(walker);
+    
+    return;     
+}
+
+
+void printLinkedList(struct Node *node) 
+{
+  if(node == NULL)
+    printf("NULL\n");
+  else {
+    while (node != NULL) 
+      {
+       printf(" %d ", node->data);
+       node = node->next; 
+      }
+  }
+  printf("\n");
+}
diff --git a/extend.h b/extend.h
new file mode 100644 (file)
index 0000000..24221c4
--- /dev/null
+++ b/extend.h
@@ -0,0 +1 @@
+void extend(int n, int *k, int *h, int **G, int **GBar, int *xi);
diff --git a/innerproduct.c b/innerproduct.c
new file mode 100644 (file)
index 0000000..5d82cdb
--- /dev/null
@@ -0,0 +1,190 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <complex.h>
+
+#include "matrix.h"
+#include "shrink.h"
+#include "extend.h"
+#include "exponentialsum.h"
+#include "innerproduct.h"
+
+
+/****************************************************************************
+ * Note: Arguments are copied and not modified!
+ ****************************************************************************/
+
+double complex innerproduct(int n1, int k1, int *h1, int **G1, int **GBar1, int Q1, int *D1, int **J1, int n2, int k2, int *h2, int **G2, int **GBar2, int Q2, int *D2, int **J2) {
+  // n1 should equal n2 (we assume this)
+
+  int a, b, c;
+
+  int n = n1;
+  int k = k1;
+  int *h = calloc(n, sizeof(int));
+  int **G = calloc(n, sizeof(int*));
+  int **GBar = calloc(n, sizeof(int*));
+  for(a=0; a<n; a++) {
+    h[a] = h1[a];
+    G[a] = calloc(n, sizeof(int));
+    GBar[a] = calloc(n, sizeof(int));
+    for(b=0; b<n; b++) {
+      G[a][b] = G1[a][b];
+      GBar[a][b] = GBar1[a][b];
+    }
+  }
+
+  int Q1copy = Q1;
+  int *D1copy = calloc(k1, sizeof(int));
+  int **J1copy = calloc(k1, sizeof(int*));
+  for(a=0; a<k1; a++) {
+    D1copy[a] = D1[a];
+    J1copy[a] = calloc(k1, sizeof(int));
+    for(b=0; b<k1; b++) {
+      J1copy[a][b] = J1[a][b];
+    }
+  }
+
+  int Q2copy = Q2;
+  int *D2copy = calloc(k2, sizeof(int));
+  int **J2copy = calloc(k2, sizeof(int*));
+  for(a=0; a<k2; a++) {
+    D2copy[a] = D2[a];
+    J2copy[a] = calloc(k2, sizeof(int));
+    for(b=0; b<k2; b++) {
+      J2copy[a][b] = J2[a][b];
+    }
+  }
+  
+  int alpha;
+  int **R = calloc(k, sizeof(int*));
+  for(a=0; a<k; a++)
+    R[a] = calloc(k2, sizeof(int));
+  int **RT = calloc(k2, sizeof(int*));
+  for(a=0; a<k2; a++)
+    RT[a] = calloc(k, sizeof(int));
+  char shrinkResult;
+
+  for(a=k2; a<n2; a++) {
+    alpha = dotProductMod(h2, GBar2[a], n2, 2);
+
+    shrinkResult = shrink(n, &k, h, G, GBar, &Q1copy, &D1copy, &J1copy, GBar2[a], alpha);
+    if(shrinkResult == 'E') {// if EMPTY
+      free(h);
+      deallocate_mem(&G, n); deallocate_mem(&GBar, n);
+      free(D1copy);
+      deallocate_mem(&J1copy, k);
+      free(D2copy);
+      deallocate_mem(&J2copy, k2);
+      deallocate_mem(&R, k);
+      deallocate_mem(&RT, k2);
+      return(0.0+0.0*I);
+    }
+  }
+
+  // Now K = K1 intersect K2 = (n1, k1, h1, G1, GBar1)
+  int *y = calloc(k2, sizeof(int));
+  int *tmpVec = calloc(n2, sizeof(int));
+  addVectorMod(h,h2,tmpVec,n2,2);
+  for(a=0; a<k2; a++) {
+    y[a] = dotProductMod(tmpVec,GBar2[a],n2,2);
+    for(b=0; b<k; b++) {
+      R[b][a] = dotProductMod(G[b],GBar2[a],n2,2);
+    }
+  }
+
+  // IF YOU UNCOMMENT THIS THEN YOU WILL BE CHANGING h2!!!
+  /* for(a=0; a<k2; a++) { */
+  /*   for(b=0; b<n2; b++) { */
+  /*     h2[b] = (h2[b] + y[a]*G2[a][b])%2; */
+  /*   } */
+  /* } */
+  /* printf("h2 (should now match h):\n"); */
+  /* printVector(h2, n2); */
+  /* printf("h:\n"); */
+  /* printVector(h, n2); */
+
+  free(tmpVec);
+
+  // update Q2 and D2 using Eqs. 52 and 53 with y
+  for(a=0; a<k2; a++) {
+    Q2copy = Q2copy + D2copy[a]*y[a];
+    for(b=a+1; b<k2; b++) {
+      Q2copy = Q2copy + J2copy[a][b]*y[a]*y[b];
+    }
+  }
+  Q2copy = Q2copy%8;
+
+  for(a=0; a<k2; a++) {
+    for(b=0; b<k2; b++)
+      D2copy[a] = D2copy[a] + J2copy[a][b]*y[b];
+    D2copy[a] = D2copy[a]%8;
+  }
+
+  free(y);
+
+  // update D2copy and J2copy using Eqs. 49 and 50 with R
+  // (note that R is a kxk2 matrix so this may reduce the dimension of D2copy and J2copy)
+  y = calloc(k, sizeof(int));
+  for(c=0;c<k;c++) {
+    y[c] = 0;
+    for(a=0;a<k2;a++) {
+      y[c] = y[c] + R[c][a]*D2copy[a];
+      for(b=a+1;b<k2;b++)
+       y[c] = y[c] + J2copy[a][b]*R[c][a]*R[c][b];
+    }
+    y[c] = y[c]%8;
+  }
+  free(D2copy);
+  D2copy = calloc(k, sizeof(int));
+  memcpy(D2copy, y, sizeof(int)*k);
+  free(y);
+
+  transp(R,RT,k,k2);
+  int **tmpMatrix = calloc(k2, sizeof(int*));
+  for(a=0; a<k2; a++)
+    tmpMatrix[a] = calloc(k, sizeof(int));
+  multMatrixMod(J2copy,RT,tmpMatrix,k2,k2,k2,k,8);
+  deallocate_mem(&J2copy, k2);
+  J2copy = calloc(k, sizeof(int*));
+  for(a=0;a<k;a++)
+    J2copy[a] = calloc(k, sizeof(int));
+  multMatrixMod(R,tmpMatrix,J2copy,k,k2,k2,k,8);
+
+  deallocate_mem(&tmpMatrix, k2);
+
+  deallocate_mem(&R, k);
+  deallocate_mem(&RT, k2);
+
+  // Now (Q1, D1, J1) and (Q2, D2, J2) are defined in the same basis
+
+  int Q = (Q1copy - Q2copy)%8 < 0 ? (Q1copy - Q2copy)%8 + 8 : (Q1copy - Q2copy)%8;
+  int *D = calloc(k, sizeof(int));
+  int **J = calloc(k, sizeof(int*));
+
+  for(a=0; a<k; a++) { // again, if k=0 then no need to fill these
+    J[a] = calloc(k, sizeof(int));
+    D[a] = (D1copy[a] - D2copy[a])%8 < 0 ? (D1copy[a] - D2copy[a])%8 + 8 : (D1copy[a] - D2copy[a])%8;
+    for(b=0; b<k; b++)
+      J[a][b] = (J1copy[a][b] - J2copy[a][b])%8 < 0 ? (J1copy[a][b] - J2copy[a][b])%8 + 8 : (J1copy[a][b] - J2copy[a][b])%8;
+
+  }
+  
+  free(h);
+  deallocate_mem(&G, n); deallocate_mem(&GBar, n);
+
+  double complex amplitude = pow(2,-0.5*(k1+k2))*exponentialsum(&k, &Q, D, J);
+
+  free(D);
+  deallocate_mem(&J, k);
+
+  free(D1copy);
+  deallocate_mem(&J1copy, k);
+
+  free(D2copy);
+  deallocate_mem(&J2copy, k);
+  
+  return(amplitude);
+    
+}
diff --git a/innerproduct.h b/innerproduct.h
new file mode 100644 (file)
index 0000000..09dc5aa
--- /dev/null
@@ -0,0 +1 @@
+double complex innerproduct(int n1, int k1, int *h1, int **G1, int **GBar1, int Q1, int *D1, int **J1, int n2, int k2, int *h2, int **G2, int **GBar2, int Q2, int *D2, int **J2);
diff --git a/matrix.c b/matrix.c
new file mode 100644 (file)
index 0000000..b85d027
--- /dev/null
+++ b/matrix.c
@@ -0,0 +1,243 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "matrix.h"
+
+
+int** addMatrix(int **A, int **B, int rows, int cols)
+{
+  int i, j;
+
+  int** C;
+
+  C = calloc(cols, sizeof(int*));
+  for(i=0; i<cols; i++)
+    C[i] = calloc(rows, sizeof(int));
+
+  for(i=0; i<rows; i++)
+    for(j=0; j<cols; j++)
+      C[i][j] = A[i][j] + B[i][j];
+
+  return C;
+}
+
+void addMatrixMod(int **A, int **B, int **C, int rows, int cols, int mod)
+{
+  int i, j;
+
+  for(i=0; i<rows; i++)
+    for(j=0; j<cols; j++)
+      C[i][j] = (A[i][j] + B[i][j])%mod;
+
+  return;
+}
+
+void addVectorMod(int *A, int *B, int *C, int length, int mod)
+{
+  int i;
+
+  for(i=0; i<length; i++)
+    C[i] = (A[i] + B[i])%mod;
+
+  return;
+}
+
+void scalarmultMatrix(int scalar, int **a, int **b, int rows, int cols)
+{
+  int i, j;
+
+  //b = calloc(cols, sizeof(int*));
+  //for(i=0; i<cols; i++)
+  //  b[i] = calloc(rows, sizeof(int));
+
+  for(i=0; i<rows; i++)
+    for(j=0; j<cols; j++)
+      b[i][j] = scalar*a[i][j];
+
+}
+
+int trace(int **a, int rows, int cols)
+{
+  int i;
+  int tr = 0.0;
+
+  for(i=0; i<rows; i++)
+    tr += a[i][i];
+
+  return tr;
+}
+
+// b = a^T
+void transp(int **a, int **b, int rows, int cols)
+{
+  int i, j;
+
+  for(i=0; i<cols; i++) {
+    for(j=0; j<rows; j++)
+      b[i][j] = a[j][i];
+  }    
+
+}
+
+void printVector(int* a, int length)
+{
+  int i;
+  printf("Vector[%d]\n", length);
+  for(i=0; i<length; i++)
+    printf("%d ", a[i]);
+  if(length>0)
+    printf("\n");
+  
+}
+
+void printMatrix(int** a, int rows, int cols)
+{
+  int i, j;
+  printf("Matrix[%d][%d]\n", rows, cols);
+  for(i=0; i<rows; i++) {
+    for(j=0; j<cols; j++) {
+      printf("%d ", a[i][j]);
+    }
+    printf("\n");
+  }
+}
+
+int** multMatrix(int **A, int **B, int ro1, int co1, int ro2, int co2)
+{
+  int i, j, k;
+  int **C;
+  C = calloc(ro1, sizeof(int*));
+  for(i=0; i<ro1; i++)
+    C[i] = calloc(co2, sizeof(int));
+  
+  for(i=0; i<ro1; i++) {
+    for(j=0; j<co2; j++) {
+      C[i][j] = 0;
+      for(k=0; k<co1; k++)
+        C[i][j] += A[i][k] * B[k][j];
+    }
+  }
+
+  return C;
+}
+
+// A times B = C
+void multMatrixMod(int **A, int **B, int **C, int ro1, int co1, int ro2, int co2, int mod)
+{
+  int i, j, k, tmp;
+
+  for(i=0; i<ro1; i++) {
+    for(j=0; j<co2; j++) {
+      tmp = 0;
+      for(k=0; k<co1; k++)
+        tmp += (A[i][k] * B[k][j]);
+      C[i][j] = tmp%mod;
+    }
+  }
+
+}
+
+int** outerMatrix(int **A, int **B, int ro1, int co1, int ro2, int co2)
+{
+  int i, j, k, l;
+  int **C;
+  C = calloc(ro1*ro2, sizeof(int*));
+  for(i=0; i<ro1*ro2; i++)
+    C[i] = calloc(co1*co2, sizeof(int));
+
+  for(i=0; i<ro1; i++)
+    for(j=0; j<ro2; j++)
+      for(k=0; k<co1; k++)
+       for(l=0; l<co2; l++) {
+         C[j+ro2*i][l+co2*k] = A[i][k]* B[j][l];
+       }
+
+  return C;
+}
+
+void outerMatrixMod(int **A, int **B, int **C, int ro1, int co1, int ro2, int co2, int mod)
+{
+  int i, j, k, l;
+  //int **C;
+  //C = calloc(ro1*ro2, sizeof(int*));
+  //for(i=0; i<ro1*ro2; i++)
+  //  C[i] = calloc(co1*co2, sizeof(int));
+
+  for(i=0; i<ro1; i++)
+    for(j=0; j<ro2; j++)
+      for(k=0; k<co1; k++)
+       for(l=0; l<co2; l++) {
+         C[j+ro2*i][l+co2*k] = (A[i][k]* B[j][l])%mod;
+       }
+
+}
+
+void outerVectorMod(int *A, int *B, int *C, int ro1, int ro2, int mod)
+{
+  int i, j;
+
+  for(i=0; i<ro1; i++)
+    for(j=0; j<ro2; j++)
+      C[j+ro2*i]= (A[i]* B[j])%mod;
+
+}
+
+void addSubMatrix(int **A, int **B, int ro1, int co1, int rooff1, int cooff1, int rooff2, int cooff2)
+{
+  // rooff1 is row offset to start range ro1 in first matrix etc.
+  int i, j;
+
+  for(i=0; i<ro1; i++)
+    for(j=0; j<co1; j++)
+      B[rooff2+i][cooff2+j] = A[rooff1+i][cooff1+j];
+
+}
+
+void appendBlockMatrix(int **A, int **B, int **C, int ro1, int co1, int ro2, int co2)
+{
+  // rooff1 is row offset to start range ro1 in first matrix etc.
+  int i, j;
+
+  for(i=0; i<ro1; i++)
+    for(j=0; j<co1; j++)
+      C[i][j] = A[i][j];
+
+  for(i=0; i<ro2; i++)
+    for(j=0; j<co2; j++)
+      C[ro1+i][co1+j] = B[i][j];
+  
+}
+
+
+void appendVector(int *A, int *B, int *C, int ro1, int ro2)
+{
+  int i;
+
+  for(i=0; i<ro1; i++)
+    C[i] = A[i];
+  for(i=0; i<ro2; i++)
+    C[ro1+i] = B[i];
+
+}
+
+
+int dotProductMod(int *a, int *b, int length, int mod)
+{
+  int i;
+  int dotproduct = 0;
+
+  for(i=0; i<length; i++)
+    dotproduct += a[i]*b[i];
+
+  return(dotproduct%mod);
+}
+
+
+void deallocate_mem(int ***arr, int rows)
+{
+  int i;
+  for(i=0; i<rows; i++)
+    free((*arr)[i]);
+  free(*arr);
+}
diff --git a/matrix.h b/matrix.h
new file mode 100644 (file)
index 0000000..6d78d3b
--- /dev/null
+++ b/matrix.h
@@ -0,0 +1,18 @@
+void deallocate_mem(int ***arr, int rows);
+void printMatrix(int** a, int rows, int cols);
+void printVector(int* a, int length);
+int** multMatrix(int **A, int **B, int ro1, int co1, int ro2, int co2);
+void multMatrixMod(int **A, int **B, int **C, int ro1, int co1, int ro2, int co2, int mod);
+int** outerMatrix(int **A, int **B, int ro1, int co1, int ro2, int co2);
+void outerMatrixMod(int **A, int **B, int **C, int ro1, int co1, int ro2, int co2, int mod);
+void outerVectorMod(int *A, int *B, int *C, int ro1, int ro2, int mod);
+void transp(int **a, int **b, int rows, int cols);
+int dotProductMod(int *a, int *b, int length, int mod);
+int trace(int **a, int rows, int cols);
+void scalarmultMatrix(int scalar, int **a, int **b, int rows, int cols);
+int** addMatrix(int **A, int **B, int rows, int cols);
+void addMatrixMod(int **A, int **B, int **C, int rows, int cols, int mod);
+void appendBlockMatrix(int **A, int **B, int **C, int ro1, int co1, int ro2, int co2);
+void addVectorMod(int *A, int *B, int *C, int length, int mod);
+void addSubMatrix(int **A, int **B, int ro1, int co1, int rooff1, int cooff1, int rooff2, int cooff2);
+void appendVector(int *A, int *B, int *C, int ro1, int ro2);
diff --git a/measurepauli.c b/measurepauli.c
new file mode 100644 (file)
index 0000000..202d3fb
--- /dev/null
@@ -0,0 +1,165 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <complex.h>
+
+#include "matrix.h"
+#include "shrink.h"
+#include "extend.h"
+#include "measurepauli.h"
+
+
+/****************************************************************************
+ * Takes a stabilizer state (n, k, h, G, GBar, Q, D, J) and a Pauli operator
+ * (m, X, Z) and returns the norm (abs. value) of the projected state.
+ * If it is non-zero,then it transforms the stabilizer state to the
+ * projected state.
+ ****************************************************************************/
+// This assumes the order Z-first X-second order when operator is read from left-to-right!
+double measurepauli(int n, int *k, int *h, int **G, int **GBar, int *Q, int **D, int ***J, int m, int *X, int *Z) {
+  // Note that X is 'xi' and Z is 'zeta' in Bravyi et al. 'xi' and 'zeta' are instead used for the vectors with elements xi_a and zeta_a.
+  // Note that D and J must be dynamically allocated arrays as they can change size in this function. This is also the reason that we need their base pointer and are greater in pointer depth by one.
+
+  int a, b;
+
+  int omega;
+
+  int *xi, *zeta, *Xprime;
+  xi = calloc(*k, sizeof(int));
+  zeta = calloc(*k, sizeof(int));
+  Xprime = calloc(n, sizeof(int));
+
+  for(a=0; a<*k; a++) {
+    xi[a] = dotProductMod(GBar[a], X, n, 2);
+    zeta[a] = dotProductMod(G[a], Z, n, 2);
+  }
+
+  for(a=0; a<n; a++) {
+    Xprime[a] = 0;
+    for(b=0; b<*k; b++)
+      Xprime[a] = Xprime[a] + xi[b]*G[b][a];
+    Xprime[a] = Xprime[a]%2;
+  }
+
+  omega = 2*m + 4*dotProductMod(Z, h, n, 2);
+  for(a=0; a<*k; a++) {
+    omega += (*D)[a]*xi[a];
+    for(b=a+1; b<*k; b++)
+      omega += (*J)[a][b]*xi[a]*xi[b];
+  }
+  omega = omega%8;
+
+  unsigned int xiEqual = 1; // set to 'true' to begin with
+  for(a=0; a<n; a++)
+    if(Xprime[a] != X[a])
+      xiEqual = 0; // xiEqual is 'false'
+
+  if(xiEqual && (omega%4 == 0)) { // if xiEqual is true and omega in {0, 4}
+    int* eta;
+    eta = calloc(*k, sizeof(int));
+    for(a=0; a<*k; a++) {
+      eta[a] = 4*zeta[a];
+      for(b=0; b<*k; b++)
+       eta[a] = eta[a] + (*J)[a][b]*xi[b];
+      eta[a] = (eta[a]/4)%2;
+    }
+    int* gamma;
+    gamma = calloc(n, sizeof(int));
+    for(a=0; a<n; a++) {
+      gamma[a] = 0;
+      for(b=0; b<*k; b++)
+       gamma[a] = gamma[a] + eta[b]*GBar[b][a];
+      gamma[a] = gamma[a]%2;
+    }
+    int alpha = (omega/4 + dotProductMod(gamma, h, n, 2))%2;
+    char shrinkResult = shrink(n, k, h, G, GBar, Q, D, J, gamma, alpha);
+    if(shrinkResult == 'E') {// empty
+      free(gamma);
+      free(eta);
+      free(xi); free(zeta); free(Xprime);
+      return(0.0); // Gamma = 0.0
+    } else if(shrinkResult == 'A') {//same
+      free(gamma);
+      free(eta);
+      free(xi); free(zeta); free(Xprime);
+      return(1.0); // Gamma = 1.0
+    } else {// success
+      free(gamma);
+      free(eta);
+      free(xi); free(zeta); free(Xprime);
+      return(1.0/sqrt(2.0)); // Gamma = 2^(-1/2)
+    }
+  } else if(xiEqual && (omega+2)%4 == 0) { // if xiEqual is true and omega in {2, 6}
+    int* eta;
+    eta = calloc(*k, sizeof(int));
+    for(a=0; a<*k; a++) {
+      eta[a] = 4*zeta[a];
+      for(b=0; b<*k; b++)
+       eta[a] = eta[a] + (*J)[a][b]*xi[b];
+      eta[a] = (eta[a]/4)%2;
+    }
+    int sigma = 2 - omega/2;
+    *Q = (*Q + sigma)%8 < 0 ? (*Q + sigma)%8 + 8 : (*Q + sigma)%8;
+    for(a=0; a<*k; a++) {
+      (*D)[a] = ((*D)[a] - 2*sigma*eta[a])%8 < 0 ? ((*D)[a] - 2*sigma*eta[a])%8 + 8 : ((*D)[a] - 2*sigma*eta[a])%8;
+      for(b=0; b<*k; b++) {
+       if(a != b)
+         (*J)[a][b] = ((*J)[a][b] + 4*eta[a]*eta[b])%8;
+       else
+         (*J)[a][a] = (2*((*D)[a]))%8;
+      }
+    }
+    free(eta); free(xi); free(zeta); free(Xprime);
+    return(1.0/sqrt(2.0)); // Gamma = 2^(-1/2)
+  } else { // if xiEqual is false
+    extend(n, k, h, G, GBar, X);
+    int *newD = calloc(*k, sizeof(int));
+    for(a=0; a<(*k-1); a++) {
+      newD[a] = (*D)[a];
+    }
+    int *tmpVec = calloc(n, sizeof(int));
+    addVectorMod(h,X,tmpVec,n,2);
+    newD[*k-1] = (2*m + 4*dotProductMod(Z,tmpVec,n,2))%8;
+    free(tmpVec);
+    if(*k-1 > 0)
+      free(*D);
+    *D = calloc(*k, sizeof(int));
+    for(a=0; a<*k; a++) {
+      (*D)[a] = newD[a];
+    }
+    free(newD);
+
+    int **tmpMatrix = calloc(*k, sizeof(int*));
+    for(a=0; a<(*k-1); a++) {
+      tmpMatrix[a] = calloc(*k, sizeof(int));
+      for(b=0; b<(*k-1); b++) {
+       tmpMatrix[a][b] = (*J)[a][b];
+      }
+    }
+    tmpMatrix[*k-1] = calloc(*k, sizeof(int));
+    for(a=0; a<(*k-1); a++) {
+      tmpMatrix[*k-1][a] = 4*zeta[a];
+      tmpMatrix[a][*k-1] = 4*zeta[a];
+    }
+    tmpMatrix[*k-1][*k-1] = (4*m)%8;
+    if(*k-1 > 0)
+      deallocate_mem(J, *k-1);
+    //for(a=0; a<(*k-1); a++)
+    //  free((*J)[a]);
+    //free(*J);
+    *J = calloc(*k, sizeof(int*));
+    for(a=0; a<*k; a++) {
+      (*J)[a] = calloc(*k, sizeof(int));
+      for(b=0; b<*k; b++) {
+       (*J)[a][b] = tmpMatrix[a][b];
+      }
+    }
+    deallocate_mem(&tmpMatrix, *k);
+    
+    free(xi); free(zeta); free(Xprime);
+    return(1.0/sqrt(2.0)); // Gamma = 2^(-1/2)
+  }
+
+  return(0.0);
+    
+}
diff --git a/measurepauli.h b/measurepauli.h
new file mode 100644 (file)
index 0000000..5405627
--- /dev/null
@@ -0,0 +1,2 @@
+
+double measurepauli(int n, int *k, int *h, int **G, int **GBar, int *Q, int **D, int ***J, int m, int *X, int *Z);
diff --git a/multipauli.c b/multipauli.c
new file mode 100644 (file)
index 0000000..2161b72
--- /dev/null
@@ -0,0 +1,301 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <complex.h>
+#include <math.h>
+
+void deallocate_mem(complex double ***arr, int rows);
+void printMatrix(complex double** a, int rows, int cols);
+complex double** multMatrix(complex double **A, complex double **B, int ro1, int co1, int ro2, int co2);
+complex double** outerMatrix(complex double **A, complex double **B, int ro1, int co1, int ro2, int co2);
+complex double** transp(complex double **a, int rows, int cols);
+complex double** conjtransp(complex double **a, int rows, int cols);
+complex double trace(complex double **a, int rows, int cols);
+complex double** scalarmultMatrix(complex double scalar, complex double **a, int rows, int cols);
+complex double** addMatrix(complex double **A, complex double **B, int rows, int cols);
+int readPaulicoeffs(int* omega, int* alpha, int* beta, int* gamma, int* delta, int numqubits);
+  
+// order of matrix elements is [row][column]!!!
+
+static complex double (*(I2[])) = { (double complex[]) {1.0+0.0*I, 0.0+0.0*I}, (double complex[]) {0.0+0.0*I, 1.0+0.0*I} };
+static complex double (*(X[])) = { (double complex[]) {0.0*I, 1.0+0.0*I}, (double complex[]) {1.0+0.0*I, 0.0*I} };
+static complex double (*(Y[])) = { (double complex[]) {0.0*I, 0.0-1.0*I}, (double complex[]) {0.0+1.0*I, 0.0*I} };
+static complex double (*(Z[])) = { (double complex[]) {1.0+0.0*I, 0.0+0.0*I}, (double complex[]) {0.0+0.0*I, -1.0+0.0*I} };
+
+int main()
+{
+
+  int i, j;
+  
+  int N;              // number of qubits
+  scanf("%d", &N);
+
+  int K;              // number of T gate magic states (set to the first 'K' of the 'N' qubits -- the rest are set to the '0' computational basis state)
+  scanf("%d", &K);  
+
+  complex double **IN;  // N-qubit identity matrix
+  IN = I2;
+  for(i=1; i<N; i++) {
+    IN = outerMatrix(IN,I2,pow(2,i),pow(2,i),2,2);
+  }
+
+  complex double (*(psiT[])) = { (double complex[]) {1.0/sqrt(2.0)}, (double complex[]) {0.5*(1.0+1.0*I)}}; // T gate magic state
+  complex double (*(psi0[])) = { (double complex[]) {1.0+0.0*I}, (double complex[]) {0.0*I}}; // T gate magic state
+
+  complex double **psiN;
+  if(K > 0) {
+    psiN = psiT;
+    for(i=1; i<K; i++) 
+      psiN = outerMatrix(psiN, psiT, pow(2,i), 1, 2, 1);
+    for(i=K; i<N; i++) 
+      psiN = outerMatrix(psiN, psi0, pow(2,i), 1, 2, 1);
+  } else {
+    psiN = psi0;
+    for(i=1; i<N; i++) 
+      psiN = outerMatrix(psiN, psi0, pow(2,i), 1, 2, 1);
+  }
+      
+  
+  int omega, alpha[N], beta[N], gamma[N], delta[N];
+
+  int Paulicounter = 0;
+
+  complex double **fullP;  // full product: \prod_i 1/2*(1+P_i)
+  complex double **P;      // P (P_i above) is made up of products of one-qubit Paulis, P1
+  complex double **P1[N];  // one-qubit Paulis
+
+  complex double tr;
+  
+  printf("psiN:\n");
+  for(i=0; i<pow(2,N); i++) {
+    printf("%d: %lf+%lfI\n", i, creal(psiN[i][0]), cimag(psiN[i][0]));
+  }
+
+  
+  while(readPaulicoeffs(&omega, alpha, beta, gamma, delta, N)) { // go over the product of 1/2*(I+Paulis) that makes up the full projector
+
+    Paulicounter++;
+    if(Paulicounter > N) {
+      printf("Error: Number of Paulis is greater than N!\n");
+      return 1;
+    }
+      
+
+    printf("%d\n", omega);
+    for(i=0; i<N; i++) {
+      printf("%d %d %d %d\n", alpha[i], beta[i], gamma[i], delta[i]);
+      P1[i] = addMatrix(addMatrix(addMatrix(scalarmultMatrix(alpha[i],I2,2,2),scalarmultMatrix(beta[i],Z,2,2),2,2),scalarmultMatrix(gamma[i],X,2,2),2,2),scalarmultMatrix(delta[i],Y,2,2),2,2);
+    }
+    
+    P = P1[0];
+    for(i=1; i<N; i++)
+      P = outerMatrix(P,P1[i],pow(2,i),pow(2,i),2,2);
+    P = scalarmultMatrix(cpow(I,omega),P,pow(2,N),pow(2,N));
+    
+    if(Paulicounter == 1)
+      fullP = scalarmultMatrix(0.5,addMatrix(IN,P,pow(2,N),pow(2,N)),pow(2,N),pow(2,N));
+    else {
+      fullP = multMatrix(scalarmultMatrix(0.5,addMatrix(IN,P,pow(2,N),pow(2,N)),pow(2,N),pow(2,N)),fullP,pow(2,N),pow(2,N),pow(2,N),pow(2,N));
+    }
+    deallocate_mem(&P, pow(2,N));
+
+  }
+
+  complex double **psiNfinal = multMatrix(fullP,psiN,pow(2,N),pow(2,N),pow(2,N),1);
+
+  printf("fullP:\n");
+  for(i=0; i<pow(2,N); i++) {
+    for(j=0; j<pow(2,N); j++) {
+      printf("%lf+%lfI ", creal(fullP[i][j]), cimag(fullP[i][j]));
+    }
+    printf("\n");
+  }
+  printf("psiNfinal:\n");
+  for(i=0; i<pow(2,N); i++) {
+    printf("%d: %lf+%lfI\n", i, creal(psiNfinal[i][0]), cimag(psiNfinal[i][0]));
+  }
+  
+  tr = 0.0 + 0.0*I;
+  //printf("tr:\n");
+  for(i=0; i<pow(2,N); i++) {
+    tr += conj(psiN[i][0])*psiNfinal[i][0];
+    //printf("%d: %lf+%lfI\n", i, creal(tr), cimag(tr));
+  }
+
+  if(creal(tr+0.00000001)>0)
+    printf("%.10lf %c %.10lf I\n", cabs(creal(tr)), cimag(tr+0.00000001)>0?'+':'-' , cabs(cimag(tr)));
+  else
+    printf("%.10lf %c %.10lf I\n", creal(tr), cimag(tr+0.00000001)>0?'+':'-' , cabs(cimag(tr)));
+  //printf("%lf %c %lf I\n", creal(tr), cimag(tr)>0?'+':'-' , cabs(cimag(tr)));
+  //printf("%lf\n", cabs(creal(tr)));
+  /* cabs the creal part because it's always positive, but sometimes the 0.0 gets a minus sign which is annoying to see when comparing outputs */
+  
+  deallocate_mem(&psiNfinal, pow(2,N));
+  
+
+  //  deallocate_mem(&psiN, pow(2,N));
+  
+  return 0;
+}
+
+
+complex double** addMatrix(complex double **A, complex double **B, int rows, int cols)
+{
+  int i, j;
+
+  complex double** C;
+
+  C = calloc(cols, sizeof(complex double*));
+  for(i=0; i<cols; i++)
+    C[i] = calloc(rows, sizeof(complex double));
+
+  for(i=0; i<rows; i++)
+    for(j=0; j<cols; j++)
+      C[i][j] = A[i][j] + B[i][j];
+
+  return C;
+}
+
+complex double** scalarmultMatrix(complex double scalar, complex double **a, int rows, int cols)
+{
+  int i, j;
+
+  complex double** C;
+
+  C = calloc(cols, sizeof(complex double*));
+  for(i=0; i<cols; i++)
+    C[i] = calloc(rows, sizeof(complex double));
+
+  for(i=0; i<rows; i++)
+    for(j=0; j<cols; j++)
+      C[i][j] = scalar*a[i][j];
+
+  return C;
+}
+
+complex double trace(complex double **a, int rows, int cols)
+{
+  int i;
+  complex double tr = 0.0*I;
+
+  for(i=0; i<rows; i++)
+    tr += a[i][i];
+
+  return tr;
+}
+
+complex double** transp(complex double **a, int rows, int cols)
+{
+  int i, j;
+  complex double** C;
+
+  C = calloc(cols, sizeof(complex double*));
+  for(i=0; i<cols; i++)
+    C[i] = calloc(rows, sizeof(complex double));
+  
+  for(i=0; i<cols; i++)
+    for(j=0; j<rows; j++) {
+      C[i][j] = a[j][i];
+    }
+
+  return C;
+}
+
+complex double** conjtransp(complex double **a, int rows, int cols)
+{
+  int i, j;
+  complex double** C;
+
+  C = calloc(cols, sizeof(complex double*));
+  for(i=0; i<cols; i++)
+    C[i] = calloc(rows, sizeof(complex double));
+  
+  for(i=0; i<cols; i++)
+    for(j=0; j<rows; j++) {
+      C[i][j] = conj(a[j][i]);
+    }
+
+  return C;
+}
+
+void printMatrix(complex double** a, int rows, int cols)
+{
+  int i, j;
+  printf("Matrix[%d][%d]\n", rows, cols);
+  for(i=0; i<rows; i++) {
+    for(j=0; j<cols; j++) {
+      printf("%lf+%lfI ", creal(a[i][j]), cimag(a[i][j]));
+    }
+    printf("\n");
+  }
+}
+
+complex double** multMatrix(complex double **A, complex double **B, int ro1, int co1, int ro2, int co2)
+{
+  int i, j, k;
+  complex double **C;
+  C = calloc(ro1, sizeof(complex double*));
+  for(i=0; i<ro1; i++)
+    C[i] = calloc(co2, sizeof(complex double));
+  
+  for(i=0; i<ro1; i++) {
+    for(j=0; j<co2; j++) {
+      C[i][j] = 0;
+      for(k=0; k<co1; k++)
+        C[i][j] += A[i][k] * B[k][j];
+    }
+  }
+
+  return C;
+}
+
+complex double** outerMatrix(complex double **A, complex double **B, int ro1, int co1, int ro2, int co2)
+{
+  int i, j, k, l;
+  complex double **C;
+  C = calloc(ro1*ro2, sizeof(complex double*));
+  for(i=0; i<ro1*ro2; i++)
+    C[i] = calloc(co1*co2, sizeof(complex double));
+
+  for(i=0; i<ro1; i++)
+    for(j=0; j<ro2; j++)
+      for(k=0; k<co1; k++)
+       for(l=0; l<co2; l++)
+         C[j+ro2*i][l+co2*k] = A[i][k]* B[j][l];
+
+  return C;
+}
+
+
+
+void deallocate_mem(complex double ***arr, int rows)
+{
+  int i;
+  for(i=0; i<rows; i++)
+    free((*arr)[i]);
+  free(*arr);
+}
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits)
+{
+
+  int i;
+
+  if(scanf("%d", omega) != EOF) {
+    for(i=0; i<numqubits; i++) {
+      if(scanf("%d %d %d %d", &alpha[i], &beta[i], &gamma[i], &delta[i]) == EOF) {
+       printf("Error: Too few input coeffs!\n");
+       exit(0);
+      }
+      if(alpha[i]+beta[i]+gamma[i]+delta[i] > 1) {
+       printf("Error: Too many coefficients are non-zero at Pauli %d!\n", i);
+       exit(0);
+      }
+    }
+    return 1;
+  } else
+    return 0;
+
+}
+
+
+
diff --git a/randominputPauli.c b/randominputPauli.c
new file mode 100644 (file)
index 0000000..da17abe
--- /dev/null
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+// order of matrix elements is [row][column]!!!
+
+int main( int argc, char *argv[])
+{
+
+  if(argc != 3) {
+    printf("randominputPauli arguments: \"number of qubits\" \"number of T gates\"\n");
+    exit(0);
+  }
+  
+  int N = atoi(argv[1]);              // number of qubits
+  int T = atoi(argv[2]);              // number of T gate magic states (set to the first 'K' of the 'N' qubits -- the rest are set to the '0' computational basis state)
+
+  printf("%d\n", N);
+  printf("%d\n", T);
+
+  int r;
+  srand((unsigned)time(NULL));
+
+
+  int i, j;
+  
+  for(i=0; i<N; i++) {
+    
+    r = rand()%4; printf("%d\n",r); // omega
+    
+    for(j=0; j<N; j++) {
+      r = rand()%4;
+      printf("%d %d %d %d\n", r==0, r==1, r==2, r==3);
+    }
+  }
+
+}
diff --git a/randominputcommutingHermitianPauli.c b/randominputcommutingHermitianPauli.c
new file mode 100644 (file)
index 0000000..348a9c1
--- /dev/null
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+
+// order of matrix elements is [row][column]!!!
+
+/*********************************************************/
+/* Generates random Hermitian Paulis that are commuting! */
+/*********************************************************/
+int main( int argc, char *argv[])
+{
+
+  if(argc != 3) {
+    printf("randominputPauli arguments: \"number of qubits\" \"number of T gates\"\n");
+    exit(0);
+  }
+  
+  int N = atoi(argv[1]);              // number of qubits
+  int T = atoi(argv[2]);              // number of T gate magic states (set to the first 'K' of the 'N' qubits -- the rest are set to the '0' computational basis state)
+
+  printf("%d\n", N);
+  printf("%d\n", T);
+
+  int Pauli[N][N];
+  srand((unsigned)time(NULL));
+
+
+  int i, j, k;
+
+  int sign = 1;
+  
+  for(i=0; i<N; i++) {
+    
+    for(j=0; j<N; j++) {
+      Pauli[i][j] = rand()%3; // don't generate Y's (which is represented by '3'; I=0, Z=1, X=2, Y=3)
+    }
+    // see if the new Paulis commute with all the previous ones
+    for(j=0; j<i; j++) {
+      sign = 1;
+      for(k=0; k<N; k++) {
+       if(Pauli[j][k] != Pauli[i][k] && Pauli[j][k] != 0 && Pauli[i][k] != 0) // if the Paulis are different and neither is equal to the identity then they anticommute
+         sign *= -1;
+      }
+      if(sign == -1) {
+       i--; // try generating the ith set of Paulis again to get a commuting one
+       break; // break out of the loop over j
+      }
+    }
+    if(sign == 1) { // found a commuting set!
+      printf("%d\n", (rand()%2)*2); // omega must be 0 or 2 (since it is the power of i: i^omega)
+      for(j=0; j<N; j++) {
+       printf("%d %d %d %d\n", Pauli[i][j]==0, Pauli[i][j]==1, Pauli[i][j]==2, Pauli[i][j]==3);
+      }
+    }
+  }
+
+}
diff --git a/randominputcommutingHermitianPauli2.c b/randominputcommutingHermitianPauli2.c
new file mode 100644 (file)
index 0000000..1c79fbb
--- /dev/null
@@ -0,0 +1,109 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+
+// order of matrix elements is [row][column]!!!
+
+/*********************************************************/
+/* Generates random Hermitian Paulis that are commuting! */
+/*********************************************************/
+int main( int argc, char *argv[])
+{
+
+  if(argc != 4) {
+    printf("randominputPauli arguments: \"number of qubits\" \"number of T gates\" \"number of random Clifford steps\"\n");
+    exit(0);
+  }
+  
+  int N = atoi(argv[1]);              // number of qubits
+  int T = atoi(argv[2]);              // number of T gate magic states (set to the first 'K' of the 'N' qubits -- the rest are set to the '0' computational basis state)
+  int randsteps = atoi(argv[3]);              // number of random Clifford steps
+
+  printf("%d\n", N);
+  printf("%d\n", T);
+
+  int omega[N];
+  int Pauli[N][N];
+  srand((unsigned)time(NULL));
+
+
+  int i, j, k;
+
+  int sign = 1;
+
+  // don't initially generate Y's (which is represented by '3'; I=0, Z=1, X=2, Y=3)
+  for(i=0; i<N; i++) {
+    omega[i] = (rand()%2)*2; // omega must be 0 or 2 (since it is a power of i: i^omega)
+    for(j=0; j<i; j++)
+      Pauli[i][j] = 0; 
+    for(j=i; j<N; j++)
+      Pauli[i][j] = 1; 
+  }
+
+  int qubita, qubitb; // indices of qubits that are Hadamarded or CNOTed.
+  int gate;
+  for(i=0; i<randsteps; i++) {
+    //printf("i=%d\n", i);
+    gate = rand()%3;
+    //printf("gate=%d\n", gate);
+    if(gate==0) { // Hadamard
+      qubita = rand()%N;
+      for(j=0; j<N; j++) {
+       if(Pauli[j][qubita] ==1)
+         Pauli[j][qubita] = 2; // 1->2 and 2->1 (i.e. Z->X and X->Z)
+       else if(Pauli[j][qubita] ==2)
+         Pauli[j][qubita] = 1; // 1->2 and 2->1 (i.e. Z->X and X->Z)
+      }
+    } else if(gate==1) { // phaseshift
+      qubita = rand()%N;
+      //printf("qubita=%d", qubita);
+      for(j=0; j<N; j++) {
+       if(Pauli[j][qubita] == 2)
+         Pauli[j][qubita] = 3; // X->Y
+       else if(Pauli[j][qubita] == 3) {
+         Pauli[j][qubita] = 2; // Y->-X
+         omega[j] = (2*omega[j])%2;
+       }
+      }
+    } else { // CNOT
+      qubita = rand()%N;
+      qubitb = qubita;
+      while(qubitb == qubita)
+       qubitb = rand()%N;
+      for(j=0; j<N; j++) {
+       if((Pauli[j][qubita] == 1) && (Pauli[j][qubitb] == 1)) // ZZ ->ZI
+         Pauli[j][qubitb] == 0;
+       else if((Pauli[j][qubita] == 1) && (Pauli[j][qubitb] == 0)) // ZI ->ZZ
+         Pauli[j][qubitb] == 1;
+       else if((Pauli[j][qubita] == 2) && (Pauli[j][qubitb] == 2)) // XX ->IX
+         Pauli[j][qubita] == 1;
+       else if((Pauli[j][qubita] == 0) && (Pauli[j][qubitb] == 2)) // IX ->XX
+         Pauli[j][qubita] == 2;
+       else if((Pauli[j][qubita] == 1) && (Pauli[j][qubitb] == 2)) {// ZX ->YY
+         Pauli[j][qubita] == 3;
+         Pauli[j][qubitb] == 3;
+       } else if((Pauli[j][qubita] == 0) && (Pauli[j][qubitb] == 2)) {// YY ->ZX
+         Pauli[j][qubita] == 1;
+         Pauli[j][qubitb] == 2;
+       } else if((Pauli[j][qubita] == 3) && (Pauli[j][qubitb] == 2)) {// YX ->-ZY
+         Pauli[j][qubita] == 1;
+         Pauli[j][qubitb] == 3;
+         omega[j] = -omega[j];
+       } else if((Pauli[j][qubita] == 1) && (Pauli[j][qubitb] == 3)) {// ZY ->-YX
+         Pauli[j][qubita] == 3;
+         Pauli[j][qubitb] == 2;
+         omega[j] = -omega[j];
+       }
+      }
+    }
+  }
+
+  for(i=0; i<N; i++) {
+    printf("%d\n", omega[i]); 
+    for(j=0; j<N; j++) {
+      printf("%d %d %d %d\n", Pauli[i][j]==0, Pauli[i][j]==1, Pauli[i][j]==2, Pauli[i][j]==3);
+    }
+  }
+
+}
diff --git a/randomstabilizerstate.c b/randomstabilizerstate.c
new file mode 100644 (file)
index 0000000..605affd
--- /dev/null
@@ -0,0 +1,131 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <math.h>
+
+#include "lapacke.h"
+#include "matrix.h"
+#include "shrinkstar.h"
+
+#include "randomstabilizerstate.h"
+
+#define ZEROTHRESHOLD (0.00000001)
+
+// Note: Make sure you seed the random number generator before calling this!
+// i.e. srand((unsigned)time(NULL));
+void randomstabilizerstate(int n, int* k, int** h, int*** G, int*** GBar, int* Q, int** D, int*** J, double** Pd)
+{
+  // vector and matrix pointers should all be passed unallocated! (no freeing of memory performed)
+  
+  float *randomX, *randomXcopy; // d*n matrix that is in array-form for LAPACKE
+  float *randomXsingvals; // singular values of randomX
+  float *U, *VT, *superb;
+  int d;
+
+  int i, j;
+
+  //srand((unsigned)time(NULL));
+
+  double randPd = (double)rand()/(double)(RAND_MAX);
+
+  double cumprob = 0.0;
+  for(i=0;i<n+1;i++) {
+    cumprob += Pd[n-1][i]; // cumprob goes up to 1.0 once you count all Pd[n][0:n+1]
+    if(cumprob > randPd) {
+      d = i;
+      break;
+    }
+    d=i;
+  }
+  //d = rand()%(n+1);
+  //printf("d=%d total=%f randPd=%f\n", d, total, randPd);
+  //printf("!!!d=%d\n", d);
+  
+  *k = n; // we will get it to be k=n-d by caling shrinkstar d times below
+  
+  randomX = calloc(n*d,sizeof(float));
+  randomXcopy = calloc(n*d,sizeof(float));
+  randomXsingvals = calloc(d,sizeof(float));
+  superb = calloc((d),sizeof(float));
+  U = calloc((d*d),sizeof(float));
+  VT = calloc((n*n),sizeof(float));
+
+  int info;
+  int numsingvals = -1;
+
+  while(numsingvals != d) {
+    for(i=0; i<d; i++) {
+      for(j=0; j<n; j++) {
+       randomX[i*n+j] = (float)(rand()%2);
+       randomXcopy[i*n+j] = randomX[i*n+j];
+       //printf("%1.0f ", randomX[i*n+j]);
+      }
+      //printf("\n");
+    }
+
+    info = LAPACKE_sgesvd( LAPACK_ROW_MAJOR, 'N', 'N', d, n, randomXcopy, n, randomXsingvals, U, n, VT, n, superb );
+
+    numsingvals = 0;
+  
+    for(i=0; i<d; i++) {
+      if(fabs(randomXsingvals[i]) >= ZEROTHRESHOLD)
+       numsingvals++;
+    }
+
+    //printf("Number of singular values: %d\n", numsingvals);
+  }
+
+  *G = calloc(n, sizeof(int*)); *GBar = calloc(n, sizeof(int*));
+  
+  *h = calloc(n, sizeof(int));
+
+  for(i=0; i<n; i++) {
+    (*G)[i] = calloc(n, sizeof(int));
+    (*GBar)[i] = calloc(n, sizeof(int));
+
+    (*G)[i][i] = 1;
+    (*GBar)[i][i] = 1;
+  }
+
+  int* xi = calloc(n, sizeof(int));
+  for(i=0; i<d; i++) {
+    for(j=0; j<n; j++){
+      xi[j] = (int)randomX[i*n+j];
+      //printf("%1.0f ", randomX[i*n+j]);
+    }
+    //printf("\n");
+    //printVector(xi, n);
+    shrinkstar(n, k, *h, *G, *GBar, xi, 0);
+  }
+  free(xi);
+  //printf("n-d=%d\n", n-d);
+  //printf("k=%d\n", *k);
+  //printMatrix(*G, n, n);
+
+  for(i=0; i<n; i++)
+    (*h)[i] = rand()%2;
+
+  *Q = (rand()%8); // Q \in Z/8Z
+  
+  *D = calloc(*k, sizeof(int));
+  for(i=0; i<*k; i++)
+    (*D)[i] = (rand()%4)*2; // D_a \in {0, 2, 4, 6}
+
+  *J = calloc(*k, sizeof(int*));
+  for(i=0; i<*k; i++) {
+    (*J)[i] = calloc(*k, sizeof(int));
+    for(j=(i+1); j<*k; j++)
+      (*J)[i][j] = (rand()%2)*4; // J_{a,b} \in {0, 4} for a!=b
+    (*J)[i][i] = (2*(*D)[i])%8;
+  }
+  for(i=0; i<*k; i++) {
+    for(j=(i+1); j<*k; j++) {
+      (*J)[j][i] = (*J)[i][j];
+    }
+  }
+
+  free(randomX); free(randomXcopy); free(randomXsingvals); free(superb); free(U); free(VT);
+  return;
+
+}
diff --git a/randomstabilizerstate.h b/randomstabilizerstate.h
new file mode 100644 (file)
index 0000000..50491ec
--- /dev/null
@@ -0,0 +1 @@
+void randomstabilizerstate(int n, int* k, int** h, int*** G, int*** GBar, int* Q, int** D, int*** J, double** Pd);
diff --git a/shrink.c b/shrink.c
new file mode 100644 (file)
index 0000000..91e7544
--- /dev/null
+++ b/shrink.c
@@ -0,0 +1,380 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <complex.h>
+
+#include "matrix.h"
+#include "shrink.h"
+
+// linked list
+struct Node {
+  int data;
+  struct Node* next;
+};
+
+void printLinkedList(struct Node *node);
+void append(struct Node** head_ref, int new_data);
+void freeList(struct Node** head_ref);
+
+/****************************************************************************
+ * Attempts to shrinks the dimension of the affine space by one dimension.
+ * The affine space is specified by 
+ * the first 'k' columns of the 'n'x'n' matrix 'G', translated by 'h',
+ * that have an inner product with 'xi' of 'alpha'. 'GBar' is 'G^(-1)^T',
+ * and ('Q', 'D', 'J') specify the quadratic form on this affine space.
+ * ---
+ * If result is an EMPTY affine space then return value is 'E'.
+ * If result is the SAME affine space then return value is 'A'.
+ * If result is a SUCCESSfully shrunk affine space then return value is 'U'.
+ * ***
+ * Note that D, and J are assumed to be nx1 and nxn even though they are
+ * actually kx1 and kxk (extra elements are ignored).
+ ****************************************************************************/
+
+char shrink(int n, int *k, int *h, int **G, int **GBar, int *Q, int **D, int ***J, int *xi, int alpha) {
+  // Note that D and J must be dynamically allocated arrays as they can change size in this function. This is also the reason that we need their base pointer and are greater in pointer depth by one.
+
+  int a, b, c, d;
+  int beta;
+
+  struct Node* setS = NULL;
+  struct Node* setWalker = NULL;
+
+  for(a=0; a<*k; a++) {
+    if(dotProductMod(xi, G[a], n, 2) == 1)
+      append(&setS, a);
+  }
+
+  beta = (alpha + dotProductMod(xi, h, n, 2))%2;
+
+  if(setS == NULL) {
+    if(beta == 1) {
+      freeList(&setS);
+      return 'E'; // EMPTY
+    }
+    else {// beta = 0
+      freeList(&setS);
+      return 'A'; // SAME
+    }
+  }
+
+  // we define tmpVec, tmpMatrix, R and RT now for later use since we are sure that *k!=0 (since otherwise setS==NULL) and so they will be finite-sized
+  int* tmpVec; // temporary vector used in swapping G and GBar rows and in Eq. 49 for updating D
+  int** tmpMatrix; // temporary matrix used to store intermediate value of J = R times J times R^T
+  tmpMatrix = calloc(*k, sizeof(int*));
+  for(a=0; a<*k; a++)
+    tmpMatrix[a] = calloc(*k, sizeof(int));
+  
+  int** R;  // basis change matrix R and R^T
+  int** RT;
+  R = calloc(*k, sizeof(int*));
+  RT = calloc(*k, sizeof(int*));
+  // initially set it to the k-dimensional identity matrix
+  for(a=0; a<*k; a++) {
+    R[a] = calloc(*k, sizeof(int));
+    R[a][a] = 1;
+    RT[a] = calloc(*k, sizeof(int));
+    RT[a][a] = 1;
+  }
+
+  int i = setS->data; // pick first element in setS to be added to the new space's shift vector
+  // remove from setS
+  if(setS->next != NULL) {
+    setWalker = setS->next;
+    setS->data = setS->next->data;
+    setS->next = setS->next->next;
+    free(setWalker);
+  } else
+    setS = NULL;
+
+  int tmp;
+  setWalker = setS;
+  while(setWalker != NULL) {
+    // update G rows, g
+    for(a=0; a<n; a++)
+      G[setWalker->data][a] = (G[setWalker->data][a] + G[i][a])%2;
+
+    // update D and J
+    R[setWalker->data][i] = 1;
+    RT[i][setWalker->data] = 1;
+
+    tmpVec = calloc(*k, sizeof(int));
+    for(c=0;c<*k;c++) {
+      tmp = 0;
+    /*   tmpVec[c] = 0; */
+    /*   for(a=0;a<*k;a++) */
+    /*         tmpVec[c] = tmpVec[c] + R[c][a]*((*D)[a]); */
+    /*   for(a=0;a<*k;a++) */
+    /*         for(b=a+1;b<*k;b++) */
+    /*           tmpVec[c] = tmpVec[c] + (*J)[a][b]*R[c][a]*R[c][b]; */
+    /*   tmpVec[c] = tmpVec[c]%8; */
+      if(c!=i)
+       tmp += R[c][c]*((*D)[c]);
+      tmp += R[c][i]*((*D)[i]);
+      if(i>c)
+       tmp += ((*J)[c][i])*R[c][c]*R[c][i];
+      else if(i<c)
+       tmp += ((*J)[i][c])*R[c][i]*R[c][c];
+      tmpVec[c] = tmp%8;
+    }
+    memcpy(*D, tmpVec, sizeof(int)*(*k));
+    free(tmpVec);
+    
+    // Eq. 50 update of J
+    for(c=0;c<*k;c++) {
+      for(d=0;d<*k; d++) {
+       tmp = 0;
+       if(c!=i) {
+         if(d!=i) {
+           tmp += R[c][c]*((*J)[c][d])*R[d][d];
+           tmp += R[c][c]*((*J)[c][i])*R[d][i];
+           tmp += R[c][i]*((*J)[i][d])*R[d][d];
+         }else {
+           tmp += R[c][c]*((*J)[c][i])*R[d][i];
+         }
+       } else {
+         if(d!=i) {
+           tmp += R[c][i]*((*J)[i][d])*R[d][d];
+         }
+       }
+       tmp += R[c][i]*((*J)[i][i])*R[d][i];
+       tmp %= 8;
+       tmpMatrix[c][d] = tmp;
+      }
+    }
+    for(c=0; c<*k; c++)
+      memcpy(((*J)[c]), tmpMatrix[c], sizeof(int)*(*k));
+    /* multMatrixMod(*J,RT,tmpMatrix,*k,*k,*k,*k,8); */
+    /* multMatrixMod(R,tmpMatrix,*J,*k,*k,*k,*k,8); */
+
+    if(setWalker->data != i) {
+      R[setWalker->data][i] = 0; // reset R
+      RT[i][setWalker->data] = 0;
+    }
+
+    // update GBar rows, gbar
+    for(a=0; a<n; a++)
+      GBar[i][a] = (GBar[i][a] + GBar[setWalker->data][a])%2;
+
+    setWalker = setWalker->next;
+  }
+
+  // Swap 'i' and 'k'
+  R[*k-1][*k-1] = 0; R[i][i] = 0;
+  R[i][*k-1] = 1; R[*k-1][i] = 1;
+  RT[*k-1][*k-1] = 0; RT[i][i] = 0;
+  RT[i][*k-1] = 1; RT[*k-1][i] = 1;
+
+  tmpVec = G[i];
+  G[i] = G[*k-1];
+  G[*k-1] = tmpVec;
+  tmpVec = GBar[i];
+  GBar[i] = GBar[*k-1];
+  GBar[*k-1] = tmpVec;
+  
+  // update D and J
+  //(Note: can't quite directly use previous faster algorithm since R[c][c]!=1 forall c. However, this can still be brought down by a factor of N by the same algorithm appropriately tweaked.)
+  if(i!=(*k-1)) {
+    tmpVec = calloc(*k, sizeof(int));
+    for(c=0;c<*k;c++) {
+      tmp = 0;
+    /* tmpVec[c] = 0; */
+    /* for(a=0;a<*k;a++) */
+    /*   tmpVec[c] = tmpVec[c] + R[c][a]*((*D)[a]); */
+    /* for(a=0;a<*k;a++) { */
+    /*   for(b=a+1;b<*k;b++) */
+    /*         tmpVec[c] = tmpVec[c] + (*J)[a][b]*R[c][a]*R[c][b]; */
+    /* } */
+    /* tmpVec[c] = tmpVec[c]%8; */
+      tmp += R[c][c]*((*D)[c]); // iff c!=i and c!=(*k-1) this can be non-zero
+      tmp += R[c][*k-1]*((*D)[*k-1]); // iff c=i this can be non-zero
+      tmp += R[c][i]*((*D)[i]); // iff c=*k-1 this can be non-zero
+       
+    /* if(i>c) */
+    /*   tmp += ((*J)[c][i])*R[c][c]*R[c][i]; */
+    /* else if(i<c) */
+    /*   tmp += ((*J)[i][c])*R[c][i]*R[c][c]; */
+    /* if((*k-1)>c) */
+    /*   tmp += ((*J)[c][*k-1])*R[c][c]*R[c][*k-1]; */
+    /* else if((*k-1)<c) // pretty sure this can't happen */
+    /*   tmp += ((*J)[*k-1][c])*R[c][*k-1]*R[c][c]; */
+    /* if((*k-1)>i) */
+    /*   tmp += ((*J)[i][*k-1])*R[c][i]*R[c][*k-1]; */
+    /* else if((*k-1)<i) */
+    /*   tmp += ((*J)[*k-1][i])*R[c][*k-1]*R[c][i]; */
+      tmpVec[c] = tmp%8;
+    }
+    memcpy(*D, tmpVec, sizeof(int)*(*k));
+    free(tmpVec);
+    
+    // Eq. 50 update of J
+    for(c=0;c<*k;c++) {
+      for(d=0;d<*k; d++) {
+       tmp = 0;
+       if(c!=(*k-1) && c!=i) {
+         if(d!=(*k-1) && d!=i) {
+           tmp += R[c][c]*((*J)[c][d])*R[d][d];
+         }else {
+           tmp += R[c][c]*((*J)[c][i])*R[d][i];
+           tmp += R[c][c]*((*J)[c][*k-1])*R[d][*k-1];
+         }
+       } else {
+         if(d!=(*k-1) && d !=i) {
+           tmp += R[c][i]*((*J)[i][d])*R[d][d];
+           tmp += R[c][*k-1]*((*J)[*k-1][d])*R[d][d];
+         } else {
+           tmp += R[c][i]*((*J)[i][*k-1])*R[d][*k-1];
+           tmp += R[c][*k-1]*((*J)[*k-1][i])*R[d][i];
+           tmp += R[c][i]*((*J)[i][i])*R[d][i];
+           tmp += R[c][*k-1]*((*J)[*k-1][*k-1])*R[d][*k-1];
+         }
+       }
+       tmpMatrix[c][d] = tmp%8;
+      }
+    }
+    for(c=0; c<*k; c++)
+      memcpy(((*J)[c]), tmpMatrix[c], sizeof(int)*(*k));
+  /* multMatrixMod(*J,RT,tmpMatrix,*k,*k,*k,*k,8); */
+  /* multMatrixMod(R,tmpMatrix,*J,*k,*k,*k,*k,8); */
+  }
+  // reset R & RT
+  R[*k-1][*k-1] = 1; R[i][i] = 1;
+  R[i][*k-1] = 0; R[*k-1][i] = 0;
+  RT[*k-1][*k-1] = 1; RT[i][i] = 1;
+  RT[i][*k-1] = 0; RT[*k-1][i] = 0;
+
+  for(a=0; a<n; a++)
+    h[a] = (h[a] + beta*G[*k-1][a])%2;
+
+  // update Q & D using Eqs. 52 & 53 with y = beta*G[*k-1][:]
+  // since h is expressed in F_2^n, in F_2^n, y_i = beta*delta_{i,*k-1}
+  // (and so the second sum of Eq. 52 is always over zero terms)
+  *Q = (*Q + ((*D)[*k-1])*beta)%8;
+
+  for(a=0; a<*k; a++) {
+    (*D)[a] = ((*D)[a] + (*J)[a][*k-1]*beta)%8;
+  }
+  
+  // remove the kth row & column from J
+  // remove the ith element from D
+
+  // we only need tmpMatrix to be (k-1)x(k-1) and it is kxk
+  for(a=0; a<(*k-1); a++) {
+    //tmpMatrix[a] = calloc(*k-1, sizeof(int));  // no need!
+    for(b=0; b<(*k-1); b++)
+      tmpMatrix[a][b] = (*J)[a][b];
+  }
+  deallocate_mem(J, *k);
+  *J = calloc(*k-1, sizeof(int*));
+  for(a=0; a<(*k-1); a++) {
+    (*J)[a] = calloc(*k-1, sizeof(int));
+    for(b=0; b<(*k-1); b++)
+      (*J)[a][b] = tmpMatrix[a][b];
+  }
+  deallocate_mem(&tmpMatrix, *k);
+
+  tmpVec = calloc(*k-1, sizeof(int));
+  for(a=0; a<(*k-1); a++)
+    tmpVec[a] = (*D)[a];
+  free(*D);
+  *D = calloc(*k-1, sizeof(int));
+  memcpy(*D, tmpVec, sizeof(int)*(*k-1));
+  free(tmpVec);
+
+  deallocate_mem(&R, *k);
+  deallocate_mem(&RT, *k);
+
+  // decrement 'k'
+  *k = *k - 1;
+
+  freeList(&setS);
+  
+  return 'U'; // SUCCESS
+    
+}
+
+
+void append(struct Node** head_ref, int new_data) 
+{ 
+    struct Node* new_node = (struct Node*) malloc(sizeof(struct Node)); 
+    struct Node *last = *head_ref;   
+
+    new_node->data = new_data; 
+    new_node->next = NULL;
+
+    // if the linked list is empty, then make the new node as head
+    if (*head_ref == NULL) {
+      *head_ref = new_node; 
+      return; 
+    }   
+       
+    // else traverse till the last node
+    while (last->next != NULL) {
+        last = last->next; 
+    }
+    last->next = new_node;
+    
+    return;     
+} 
+
+/*void freeList(struct Node** head_ref)
+{ 
+       
+  struct Node *second_last_walker = *head_ref;
+  struct Node *walker = *head_ref;   
+
+    // else traverse till the last node
+    if(walker != NULL) {
+      while(walker->next != NULL) {
+       while(walker->next != NULL) {
+         //printf("!%d\n", walker->data);
+         second_last_walker = walker;
+         walker = walker->next;
+         //printf("%d\n", walker->data);
+         //printf("!%d\n", second_last_walker->data);
+       }
+       free(walker);
+       second_last_walker->next = NULL;
+       walker = *head_ref;
+       //printf("!!%d\n", second_last_walker->data);
+      }
+    }
+    free(walker);
+    
+    return;     
+    }*/
+
+void freeList(struct Node** head_ref)
+{ 
+       
+  struct Node *walker = *head_ref;
+  struct Node *walker2;   
+
+    // else traverse till the last node
+    if(walker != NULL) {
+      walker2 = walker->next;
+      while(walker2 != NULL) {
+       free(walker);
+       walker = walker2;
+       walker2 = walker->next;
+      }
+    }
+    free(walker);
+    
+    return;     
+}
+
+void printLinkedList(struct Node *node) 
+{
+  if(node == NULL)
+    printf("NULL\n");
+  else {
+    while (node != NULL) 
+      {
+       printf(" %d ", node->data);
+       node = node->next; 
+      }
+  }
+  printf("\n");
+}
diff --git a/shrink.h b/shrink.h
new file mode 100644 (file)
index 0000000..543b20c
--- /dev/null
+++ b/shrink.h
@@ -0,0 +1 @@
+char shrink(int n, int *k, int *h, int **G, int **GBar, int *Q, int **D, int ***J, int *xi, int alpha);
diff --git a/shrinkstar.c b/shrinkstar.c
new file mode 100644 (file)
index 0000000..ea202f8
--- /dev/null
@@ -0,0 +1,380 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <complex.h>
+
+#include "matrix.h"
+#include "shrinkstar.h"
+
+// linked list
+struct Node {
+  int data;
+  struct Node* next;
+};
+
+void printLinkedList(struct Node *node);
+void append(struct Node** head_ref, int new_data);
+void freeList(struct Node** head_ref);
+
+/****************************************************************************
+ * Attempts to shrinks the dimension of the affine space by one dimension.
+ * The affine space is specified by 
+ * the first 'k' columns of the 'n'x'n' matrix 'G', translated by 'h',
+ * that have an inner product with 'xi' of 'alpha'. 'GBar' is 'G^(-1)^T',
+ * and ('Q', 'D', 'J') specify the quadratic form on this affine space.
+ * ---
+ * If result is an EMPTY affine space then return value is 'E'.
+ * If result is the SAME affine space then return value is 'A'.
+ * If result is a SUCCESSfully shrunk affine space then return value is 'U'.
+ * ***
+ * Note that D, and J are assumed to be nx1 and nxn even though they are
+ * actually kx1 and kxk (extra elements are ignored).
+ ****************************************************************************/
+
+char shrinkstar(int n, int *k, int *h, int **G, int **GBar, int *xi, int alpha) {
+  // Note that D and J must be dynamically allocated arrays as they can change size in this function. This is also the reason that we need their base pointer and are greater in pointer depth by one.
+
+  int a, b, c, d;
+  int beta;
+
+  struct Node* setS = NULL;
+  struct Node* setWalker = NULL;
+
+  for(a=0; a<*k; a++) {
+    if(dotProductMod(xi, G[a], n, 2) == 1)
+      append(&setS, a);
+  }
+
+  beta = (alpha + dotProductMod(xi, h, n, 2))%2;
+
+  if(setS == NULL) {
+    if(beta == 1) {
+      freeList(&setS);
+      return 'E'; // EMPTY
+    }
+    else {// beta = 0
+      freeList(&setS);
+      return 'A'; // SAME
+    }
+  }
+
+  // we define tmpVec, tmpMatrix, R and RT now for later use since we are sure that *k!=0 (since otherwise setS==NULL) and so they will be finite-sized
+  int* tmpVec; // temporary vector used in swapping G and GBar rows and in Eq. 49 for updating D
+  /*int** tmpMatrix; // temporary matrix used to store intermediate value of J = R times J times R^T
+  tmpMatrix = calloc(*k, sizeof(int*));
+  for(a=0; a<*k; a++)
+  tmpMatrix[a] = calloc(*k, sizeof(int));*/
+  
+  int** R;  // basis change matrix R and R^T
+  int** RT;
+  R = calloc(*k, sizeof(int*));
+  RT = calloc(*k, sizeof(int*));
+  // initially set it to the k-dimensional identity matrix
+  for(a=0; a<*k; a++) {
+    R[a] = calloc(*k, sizeof(int));
+    R[a][a] = 1;
+    RT[a] = calloc(*k, sizeof(int));
+    RT[a][a] = 1;
+  }
+
+  int i = setS->data; // pick first element in setS to be added to the new space's shift vector
+  // remove from setS
+  if(setS->next != NULL) {
+    setWalker = setS->next;
+    setS->data = setS->next->data;
+    setS->next = setS->next->next;
+    free(setWalker);
+  } else
+    setS = NULL;
+
+  int tmp;
+  setWalker = setS;
+  while(setWalker != NULL) {
+    // update G rows, g
+    for(a=0; a<n; a++)
+      G[setWalker->data][a] = (G[setWalker->data][a] + G[i][a])%2;
+
+    // update D and J
+    /*R[setWalker->data][i] = 1;
+    RT[i][setWalker->data] = 1;
+
+    tmpVec = calloc(*k, sizeof(int));
+    for(c=0;c<*k;c++) {
+    tmp = 0;*/
+    /*   tmpVec[c] = 0; */
+    /*   for(a=0;a<*k;a++) */
+    /*         tmpVec[c] = tmpVec[c] + R[c][a]*((*D)[a]); */
+    /*   for(a=0;a<*k;a++) */
+    /*         for(b=a+1;b<*k;b++) */
+    /*           tmpVec[c] = tmpVec[c] + (*J)[a][b]*R[c][a]*R[c][b]; */
+    /*   tmpVec[c] = tmpVec[c]%8; */
+    /*  if(c!=i)
+       tmp += R[c][c]*((*D)[c]);
+      tmp += R[c][i]*((*D)[i]);
+      if(i>c)
+       tmp += ((*J)[c][i])*R[c][c]*R[c][i];
+      else if(i<c)
+       tmp += ((*J)[i][c])*R[c][i]*R[c][c];
+      tmpVec[c] = tmp%8;
+    }
+    memcpy(*D, tmpVec, sizeof(int)*(*k));
+    free(tmpVec);
+    
+    // Eq. 50 update of J
+    for(c=0;c<*k;c++) {
+      for(d=0;d<*k; d++) {
+       tmp = 0;
+       if(c!=i) {
+         if(d!=i) {
+           tmp += R[c][c]*((*J)[c][d])*R[d][d];
+           tmp += R[c][c]*((*J)[c][i])*R[d][i];
+           tmp += R[c][i]*((*J)[i][d])*R[d][d];
+         }else {
+           tmp += R[c][c]*((*J)[c][i])*R[d][i];
+         }
+       } else {
+         if(d!=i) {
+           tmp += R[c][i]*((*J)[i][d])*R[d][d];
+         }
+       }
+       tmp += R[c][i]*((*J)[i][i])*R[d][i];
+       tmp %= 8;
+       tmpMatrix[c][d] = tmp;
+      }
+    }
+    for(c=0; c<*k; c++)
+    memcpy(((*J)[c]), tmpMatrix[c], sizeof(int)*(*k));*/
+    /* multMatrixMod(*J,RT,tmpMatrix,*k,*k,*k,*k,8); */
+    /* multMatrixMod(R,tmpMatrix,*J,*k,*k,*k,*k,8); */
+
+    if(setWalker->data != i) {
+      R[setWalker->data][i] = 0; // reset R
+      RT[i][setWalker->data] = 0;
+    }
+
+    // update GBar rows, gbar
+    for(a=0; a<n; a++)
+      GBar[i][a] = (GBar[i][a] + GBar[setWalker->data][a])%2;
+
+    setWalker = setWalker->next;
+  }
+
+  // Swap 'i' and 'k'
+  R[*k-1][*k-1] = 0; R[i][i] = 0;
+  R[i][*k-1] = 1; R[*k-1][i] = 1;
+  RT[*k-1][*k-1] = 0; RT[i][i] = 0;
+  RT[i][*k-1] = 1; RT[*k-1][i] = 1;
+
+  tmpVec = G[i];
+  G[i] = G[*k-1];
+  G[*k-1] = tmpVec;
+  tmpVec = GBar[i];
+  GBar[i] = GBar[*k-1];
+  GBar[*k-1] = tmpVec;
+  
+  // update D and J
+  //(Note: can't quite directly use previous faster algorithm since R[c][c]!=1 forall c. However, this can still be brought down by a factor of N by the same algorithm appropriately tweaked.)
+  /*  if(i!=(*k-1)) {
+    tmpVec = calloc(*k, sizeof(int));
+    for(c=0;c<*k;c++) {
+    tmp = 0;*/
+    /* tmpVec[c] = 0; */
+    /* for(a=0;a<*k;a++) */
+    /*   tmpVec[c] = tmpVec[c] + R[c][a]*((*D)[a]); */
+    /* for(a=0;a<*k;a++) { */
+    /*   for(b=a+1;b<*k;b++) */
+    /*         tmpVec[c] = tmpVec[c] + (*J)[a][b]*R[c][a]*R[c][b]; */
+    /* } */
+    /* tmpVec[c] = tmpVec[c]%8; */
+  /*      tmp += R[c][c]*((*D)[c]); // iff c!=i and c!=(*k-1) this can be non-zero
+      tmp += R[c][*k-1]*((*D)[*k-1]); // iff c=i this can be non-zero
+      tmp += R[c][i]*((*D)[i]); // iff c=*k-1 this can be non-zero
+  */
+    /* if(i>c) */
+    /*   tmp += ((*J)[c][i])*R[c][c]*R[c][i]; */
+    /* else if(i<c) */
+    /*   tmp += ((*J)[i][c])*R[c][i]*R[c][c]; */
+    /* if((*k-1)>c) */
+    /*   tmp += ((*J)[c][*k-1])*R[c][c]*R[c][*k-1]; */
+    /* else if((*k-1)<c) // pretty sure this can't happen */
+    /*   tmp += ((*J)[*k-1][c])*R[c][*k-1]*R[c][c]; */
+    /* if((*k-1)>i) */
+    /*   tmp += ((*J)[i][*k-1])*R[c][i]*R[c][*k-1]; */
+    /* else if((*k-1)<i) */
+    /*   tmp += ((*J)[*k-1][i])*R[c][*k-1]*R[c][i]; */
+  /*      tmpVec[c] = tmp%8;
+    }
+    memcpy(*D, tmpVec, sizeof(int)*(*k));
+    free(tmpVec);
+    
+    // Eq. 50 update of J
+    for(c=0;c<*k;c++) {
+      for(d=0;d<*k; d++) {
+       tmp = 0;
+       if(c!=(*k-1) && c!=i) {
+         if(d!=(*k-1) && d!=i) {
+           tmp += R[c][c]*((*J)[c][d])*R[d][d];
+         }else {
+           tmp += R[c][c]*((*J)[c][i])*R[d][i];
+           tmp += R[c][c]*((*J)[c][*k-1])*R[d][*k-1];
+         }
+       } else {
+         if(d!=(*k-1) && d !=i) {
+           tmp += R[c][i]*((*J)[i][d])*R[d][d];
+           tmp += R[c][*k-1]*((*J)[*k-1][d])*R[d][d];
+         } else {
+           tmp += R[c][i]*((*J)[i][*k-1])*R[d][*k-1];
+           tmp += R[c][*k-1]*((*J)[*k-1][i])*R[d][i];
+           tmp += R[c][i]*((*J)[i][i])*R[d][i];
+           tmp += R[c][*k-1]*((*J)[*k-1][*k-1])*R[d][*k-1];
+         }
+       }
+       tmpMatrix[c][d] = tmp%8;
+      }
+    }
+    for(c=0; c<*k; c++)
+    memcpy(((*J)[c]), tmpMatrix[c], sizeof(int)*(*k));*/
+  /* multMatrixMod(*J,RT,tmpMatrix,*k,*k,*k,*k,8); */
+  /* multMatrixMod(R,tmpMatrix,*J,*k,*k,*k,*k,8); */
+  /*}*/
+  // reset R & RT
+  R[*k-1][*k-1] = 1; R[i][i] = 1;
+  R[i][*k-1] = 0; R[*k-1][i] = 0;
+  RT[*k-1][*k-1] = 1; RT[i][i] = 1;
+  RT[i][*k-1] = 0; RT[*k-1][i] = 0;
+
+  for(a=0; a<n; a++)
+    h[a] = (h[a] + beta*G[*k-1][a])%2;
+
+  // update Q & D using Eqs. 52 & 53 with y = beta*G[*k-1][:]
+  // since h is expressed in F_2^n, in F_2^n, y_i = beta*delta_{i,*k-1}
+  // (and so the second sum of Eq. 52 is always over zero terms)
+  /**Q = (*Q + ((*D)[*k-1])*beta)%8;
+
+  for(a=0; a<*k; a++) {
+    (*D)[a] = ((*D)[a] + (*J)[a][*k-1]*beta)%8;
+    }*/
+  
+  // remove the kth row & column from J
+  // remove the ith element from D
+
+  // we only need tmpMatrix to be (k-1)x(k-1) and it is kxk
+  /*for(a=0; a<(*k-1); a++) {
+    //tmpMatrix[a] = calloc(*k-1, sizeof(int));  // no need!
+    for(b=0; b<(*k-1); b++)
+      tmpMatrix[a][b] = (*J)[a][b];
+  }
+  deallocate_mem(J, *k);
+  *J = calloc(*k-1, sizeof(int*));
+  for(a=0; a<(*k-1); a++) {
+    (*J)[a] = calloc(*k-1, sizeof(int));
+    for(b=0; b<(*k-1); b++)
+      (*J)[a][b] = tmpMatrix[a][b];
+      }
+      deallocate_mem(&tmpMatrix, *k);*/
+
+  /*tmpVec = calloc(*k-1, sizeof(int));
+  for(a=0; a<(*k-1); a++)
+    tmpVec[a] = (*D)[a];
+  free(*D);
+  *D = calloc(*k-1, sizeof(int));
+  memcpy(*D, tmpVec, sizeof(int)*(*k-1));
+  free(tmpVec);*/
+
+  deallocate_mem(&R, *k);
+  deallocate_mem(&RT, *k);
+
+  // decrement 'k'
+  *k = *k - 1;
+
+  freeList(&setS);
+  
+  return 'U'; // SUCCESS
+    
+}
+
+
+void append(struct Node** head_ref, int new_data) 
+{ 
+    struct Node* new_node = (struct Node*) malloc(sizeof(struct Node)); 
+    struct Node *last = *head_ref;   
+
+    new_node->data = new_data; 
+    new_node->next = NULL;
+
+    // if the linked list is empty, then make the new node as head
+    if (*head_ref == NULL) {
+      *head_ref = new_node; 
+      return; 
+    }   
+       
+    // else traverse till the last node
+    while (last->next != NULL) {
+        last = last->next; 
+    }
+    last->next = new_node;
+    
+    return;     
+} 
+
+/*void freeList(struct Node** head_ref)
+{ 
+       
+  struct Node *second_last_walker = *head_ref;
+  struct Node *walker = *head_ref;   
+
+    // else traverse till the last node
+    if(walker != NULL) {
+      while(walker->next != NULL) {
+       while(walker->next != NULL) {
+         //printf("!%d\n", walker->data);
+         second_last_walker = walker;
+         walker = walker->next;
+         //printf("%d\n", walker->data);
+         //printf("!%d\n", second_last_walker->data);
+       }
+       free(walker);
+       second_last_walker->next = NULL;
+       walker = *head_ref;
+       //printf("!!%d\n", second_last_walker->data);
+      }
+    }
+    free(walker);
+    
+    return;     
+    }*/
+
+void freeList(struct Node** head_ref)
+{ 
+       
+  struct Node *walker = *head_ref;
+  struct Node *walker2;   
+
+    // else traverse till the last node
+    if(walker != NULL) {
+      walker2 = walker->next;
+      while(walker2 != NULL) {
+       free(walker);
+       walker = walker2;
+       walker2 = walker->next;
+      }
+    }
+    free(walker);
+    
+    return;     
+}
+
+void printLinkedList(struct Node *node) 
+{
+  if(node == NULL)
+    printf("NULL\n");
+  else {
+    while (node != NULL) 
+      {
+       printf(" %d ", node->data);
+       node = node->next; 
+      }
+  }
+  printf("\n");
+}
diff --git a/shrinkstar.h b/shrinkstar.h
new file mode 100644 (file)
index 0000000..88aba74
--- /dev/null
@@ -0,0 +1 @@
+char shrinkstar(int n, int *k, int *h, int **G, int **GBar, int *xi, int alpha);
diff --git a/strongsim.c b/strongsim.c
new file mode 100644 (file)
index 0000000..389a737
--- /dev/null
@@ -0,0 +1,286 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <complex.h>
+#include "matrix.h"
+#include "exponentialsum.h"
+#include "shrink.h"
+#include "extend.h"
+#include "measurepauli.h"
+#include "innerproduct.h"
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits);
+
+// order of matrix elements is [row][column]!!!
+
+int main()
+{
+
+  int N;              // number of qubits
+  scanf("%d", &N);
+
+  if(N%3 != 0) {
+    printf("'N' needs to be a multiple of 3 for a k=3 tensor factor decomposition!\n");
+    return 1;
+  }
+
+  int T;              // number of T gate magic states (set to the first 'K' of the 'N' qubits -- the rest are set to the '0' computational basis state)
+  scanf("%d", &T);  
+
+  int omega;
+  int alpha[N], beta[N], gamma[N], delta[N];
+  int Paulicounter = 0;
+
+  int i, j, k, l, m;
+
+  double complex coeffa = -0.25*(1.0-I)*(-1.0-I+sqrt(2.0))*csqrt(-I);
+  double complex coeffb = 0.25*(-1.0-I)*(1.0-I+sqrt(2.0))*csqrt(I);
+  double complex coeffc = 0.25*(-1.0-I)*(-1.0+I+sqrt(2.0))*csqrt(I);
+
+  int n1 = 3; int k1 = 1; int (*(G1[])) = { (int[]) {1, 1, 1}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1}}; int (*(GBar1[])) = { (int[]) {1, 0, 0}, (int[]) {1, 1, 0}, (int[]) {1, 0, 1}}; int h1[] = {1, 1, 0}; int Q1 = 0; int D1[] = {2}; int (*(J1[])) = { (int[]) {4} };
+  int n2 = 3; int k2 = 3; int (*(G2[])) = { (int[]) {1, 0, 0}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1} }; int (*(GBar2[])) = { (int[]) {1, 0, 0}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1} }; int h2[] = {0, 0, 0}; int Q2 = 2; int D2[] = {2, 2, 0}; int (*(J2[])) = { (int[]) {4, 0, 0}, (int[]) {0, 4, 0}, (int[]) {0, 0, 0} };
+  int n3 = 3; int k3 = 3; int (*(G3[])) = { (int[]) {1, 0, 0}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1} }; int (*(GBar3[])) = { (int[]) {1, 0, 0}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1} }; int h3[] = {0, 0, 0}; int Q3 = 2; int D3[] = {6, 6, 0}; int (*(J3[])) = { (int[]) {4, 4, 4}, (int[]) {4, 4, 4}, (int[]) {4, 4, 0} };
+
+  int *K; int ***G; int ***GBar; int **h; int *Q; int **D; int ***J;
+  double complex Gamma[(int)pow(3,N/3)]; // prefactor in front of resultant state
+  G = calloc(pow(3,N/3),sizeof(int*)); GBar = calloc(pow(3,N/3),sizeof(int*));
+  h = calloc(pow(3,N/3),sizeof(int*));
+  
+  J = calloc(pow(3,N/3),sizeof(int*)); D = calloc(pow(3,N/3),sizeof(int*)); Q = calloc(pow(3,N/3),sizeof(int));
+
+  K = calloc(pow(3,N/3), sizeof(int));
+
+  double complex origGamma[(int)pow(3,N/3)];
+  int *origK, *origQ, **origD, ***origJ;
+  int ***origG, ***origGBar, **origh;
+
+  origG = calloc(pow(3,N/3),sizeof(int*)); origGBar = calloc(pow(3,N/3),sizeof(int*));
+  origh = calloc(pow(3,N/3),sizeof(int*));
+  
+  origJ = calloc(pow(3,N/3),sizeof(int*)); origD = calloc(pow(3,N/3),sizeof(int*)); origQ = calloc(pow(3,N/3),sizeof(int));
+
+  origK = calloc(pow(3,N/3), sizeof(int));
+
+  int combination; // a particular combination from the linear combo of stabilizer states making up the tensor factors multiplied together
+  
+
+  for(j=0; j<pow(3,N/3); j++) { // there will be 3^(N/3) combinations when using k=3 tensor factors
+
+    combination = j;
+
+    K[j] = 0.0;
+    
+    for(k=0; k<N/3; k++) {
+      K[j] += (((combination%3)==2)*k3 + ((combination%3)==1)*k2 + ((combination%3)==0)*k1);
+      combination /= 3;
+    }
+    combination = j;
+    origK[j] = K[j];
+
+    Gamma[j] = 1.0;
+
+    G[j] = calloc(N, sizeof(int*)); GBar[j] = calloc(N, sizeof(int*));
+    h[j] = calloc(N, sizeof(int));
+
+    if(K[j] > 0) {
+      J[j] = calloc(K[j], sizeof(int*)); D[j] = calloc(K[j], sizeof(int));
+      for(k=0; k<K[j]; k++)
+       J[j][k] = calloc(K[j], sizeof(int));
+    }
+
+    origG[j] = calloc(N, sizeof(int*)); origGBar[j] = calloc(N, sizeof(int*));
+    origh[j] = calloc(N, sizeof(int));
+
+    if(K[j] > 0) {
+      origJ[j] = calloc(K[j], sizeof(int*)); origD[j] = calloc(K[j], sizeof(int));
+      for(k=0; k<K[j]; k++)
+       origJ[j][k] = calloc(K[j], sizeof(int));
+    }
+
+    for(k=0; k<N; k++) {
+      G[j][k] = calloc(N, sizeof(int)); GBar[j][k] = calloc(N, sizeof(int));
+      origG[j][k] = calloc(N, sizeof(int)); origGBar[j][k] = calloc(N, sizeof(int));
+    }
+
+    int Kcounter = 0; // Kcounter keeps track of the K<=N that we have added already to the G rows etc. for each combination that is indexed by the digits (base 3) of 'j' in that we go through with 'k'
+    int Kcombo; // Kcombo stores the k<(n1=n2=n3) dimension of the member of the combination that we are currently adding
+    for(k=0; k<N/3; k++) {
+
+      Q[j] += ((combination%3)==2)*Q3 + ((combination%3)==1)*Q2 + ((combination%3)==0)*Q1;
+      
+      Gamma[j] *= (((combination%3)==2)*coeffc + ((combination%3)==1)*coeffb + ((combination%3)==0)*coeffa);
+
+      Kcombo = (((combination%3)==2)*k3 + ((combination%3)==1)*k2 + ((combination%3)==0)*k1);
+      for(l=0; l<Kcombo; l++) {
+         // D1 has a different number of rows 'l' than D2 and D3 so you need to use something like 'switch' to check combination%3 without going out of bound of J1
+         switch(combination%3) {
+         case 0:
+           D[j][Kcounter+l] = D1[l];
+           break;
+         case 1:
+           D[j][Kcounter+l] = D2[l];
+           break;
+         case 2:
+           D[j][Kcounter+l] = D3[l];
+           break;
+         default:
+           printf("error");
+           return 1;
+         }
+       for(m=0; m<Kcombo; m++) {
+         // J1 has a different number of rows 'l' than J2 and J3 so you need to use something like 'switch' to check combination%3 without going out of bound of J1
+         switch(combination%3) {
+         case 0:
+           J[j][Kcounter+l][Kcounter+m] = J1[l][m];
+           break;
+         case 1:
+           J[j][Kcounter+l][Kcounter+m] = J2[l][m];
+           break;
+         case 2:
+           J[j][Kcounter+l][Kcounter+m] = J3[l][m];
+           break;
+         default:
+           printf("error");
+           return 1;
+         }
+       }
+      }
+
+      for(l=0; l<n1; l++) { // assuming n1=n2=n3
+       h[j][k*n1+l] = ((combination%3)==2)*h3[l] + ((combination%3)==1)*h2[l] + ((combination%3)==0)*h1[l];
+      }
+      // only filling the K[j] first rows of G and GBar here corresponding to the basis for D and J
+      for(l=0; l<Kcombo; l++) {
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         G[j][Kcounter+l][k*n1+m] = ((combination%3)==2)*G3[l][m] + ((combination%3)==1)*G2[l][m] + ((combination%3)==0)*G1[l][m];
+         GBar[j][Kcounter+l][k*n1+m] = ((combination%3)==2)*GBar3[l][m] + ((combination%3)==1)*GBar2[l][m] + ((combination%3)==0)*GBar1[l][m];
+       }
+      }
+      Kcounter = Kcounter + Kcombo;
+      
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      //memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
+
+      //memcpy(origJ[j][k], J[j][k], K[j]*sizeof(int));
+      
+      combination /= 3; // shift to the right by one (in base-3 arithmetic)
+    }
+    //printf("!\n");
+
+    // now need to fill the N-Kcounter remaining rows of G and GBar that are outside the spanning basis states of D and J
+    combination = j;
+    for(k=0; k<(N/3); k++) {
+      Kcombo = (((combination%3)==2)*k3 + ((combination%3)==1)*k2 + ((combination%3)==0)*k1);
+      //printf("Kcounter=%d\n", Kcounter);
+      // G and GBar rows that are outside the first 'k' spanning basis states
+      for(l=Kcombo; l<n1; l++) { // assuming n1=n2=n3
+       //printf("l=%d\n", l);
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         /* printf("m=%d\n", m); */
+         /* printf("Kcounter+l=%d\n", Kcounter+l); */
+         /* printf("k*n1+m=%d\n", k*n1+m); */
+         G[j][Kcounter+l-Kcombo][k*n1+m] = ((combination%3)==2)*G3[l][m] + ((combination%3)==1)*G2[l][m] + ((combination%3)==0)*G1[l][m];
+         GBar[j][Kcounter+l-Kcombo][k*n1+m] = ((combination%3)==2)*GBar3[l][m] + ((combination%3)==1)*GBar2[l][m] + ((combination%3)==0)*GBar1[l][m];
+       }
+      }
+      Kcounter = Kcounter + (n1-Kcombo);
+
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      
+      combination /= 3;
+    }
+    for(k=0; k<N; k++) {
+      memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
+    }
+    for(k=0; k<K[j]; k++) {
+      memcpy(origJ[j][k], J[j][k], K[j]*sizeof(int));      
+    }
+
+    memcpy(origh[j], h[j], N*sizeof(int));
+    memcpy(origD[j], D[j], K[j]*sizeof(int));
+
+  }
+  //exit(0);
+  memcpy(origGamma, Gamma, pow(3,N/3)*sizeof(double complex));
+
+  memcpy(origQ, Q, pow(3,N/3)*sizeof(int));
+
+  while(readPaulicoeffs(&omega, alpha, beta, gamma, delta, N)) {
+  
+    Paulicounter++;
+    if(Paulicounter > N) {
+      printf("Error: Number of Paulis is greater than N!\n");
+      return 1;
+    }
+    
+    // Let's break up the Ys into Xs and Zs in the order Z X, as required to pass to measurepauli()
+    // Y_i = -I*Z*X
+    for(i=0; i<N; i++) {
+      if(delta[i]){
+       omega += 3; // -I = I^3
+       beta[i] = delta[i];
+       gamma[i] = delta[i];
+      }
+    }
+
+
+    for(j=0; j<pow(3,N/3); j++) { // the kets
+
+      Gamma[j] *= measurepauli(N, &K[j], h[j], G[j], GBar[j], &Q[j], &D[j], &J[j], omega, gamma, beta);
+
+    }
+
+  }
+
+  double complex amplitude = 0.0 + 0.0*I;
+  for(i=0; i<pow(3,N/3); i++) { // the bras
+    for(j=0; j<pow(3,N/3); j++) {
+      double complex newamplitude = innerproduct(N, K[j], h[j], G[j], GBar[j], Q[j], D[j], J[j], N, origK[i], origh[i], origG[i], origGBar[i], origQ[i], origD[i], origJ[i]);
+      amplitude = amplitude + conj(origGamma[i])*Gamma[j]*newamplitude;
+    }
+  }
+
+  printf("amplitude:\n");
+  if(creal(amplitude+0.00000001)>0)
+    printf("%lf %c %lf I\n", cabs(creal(amplitude)), cimag(amplitude+0.00000001)>0?'+':'-' , cabs(cimag(amplitude)));
+  else
+    printf("%lf %c %lf I\n", creal(amplitude), cimag(amplitude+0.00000001)>0?'+':'-' , cabs(cimag(amplitude)));
+  //printf("%lf %c %lf I\n", creal(amplitude), cimag(amplitude)>0?'+':'-' , cabs(cimag(amplitude)));
+
+  return 0;
+
+}
+
+
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits)
+{
+    
+  int newomega, newalpha, newbeta, newgamma, newdelta;
+  int i;
+
+  if(scanf("%d", &newomega) != EOF) {
+    *omega = newomega;
+    for(i=0; i<numqubits; i++) {
+      if(scanf("%d %d %d %d", &newalpha, &newbeta, &newgamma, &newdelta) == EOF) {
+       printf("Error: Too few input coeffs!\n");
+       exit(0);
+      }
+      if(newalpha+newbeta+newgamma+newdelta > 1) {
+       printf("Error: Too many coefficients are non-zero at Pauli %d!\n", i);
+       exit(0);
+      }
+      alpha[i] = newalpha; beta[i] = newbeta; gamma[i] = newgamma; delta[i] = newdelta;
+    }
+    return 1;
+  } else
+    return 0;
+    
+}
diff --git a/strongsim1.c b/strongsim1.c
new file mode 100644 (file)
index 0000000..2277799
--- /dev/null
@@ -0,0 +1,186 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <complex.h>
+#include "matrix.h"
+#include "exponentialsum.h"
+#include "shrink.h"
+#include "extend.h"
+#include "measurepauli.h"
+#include "innerproduct.h"
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits);
+
+// order of matrix elements is [row][column]!!!
+
+int main()
+{
+
+  int N;              // number of qubits
+  scanf("%d", &N);
+
+  int T;              // number of T gate magic states (set to the first 'K' of the 'N' qubits -- the rest are set to the '0' computational basis state)
+  scanf("%d", &T);
+
+  int omega;
+  int alpha[N], beta[N], gamma[N], delta[N];
+  int Paulicounter = 0;
+
+  int i, j, k, l;
+
+
+  int n1 = 1; int k1 = 0; int (*(G1[])) = { (int[]) {1} }; int (*(GBar1[])) = { (int[]) {1} }; int h1[] = {0}; int Q1 = 0; int D1[] = {0}; int (*(J1[])) = { (int[]) {0} };
+  int n2 = 1; int k2 = 0; int (*(G2[])) = { (int[]) {1} }; int (*(GBar2[])) = { (int[]) {1} }; int h2[] = {1}; int Q2 = 0; int D2[] = {0}; int (*(J2[])) = { (int[]) {0} };
+
+  int *K; int ***G; int ***GBar; int **h; int *Q; int **D; int ***J;
+  double complex Gamma[(int)pow(2,N)]; // prefactor in front of resultant state
+  G = calloc(pow(2,N),sizeof(int*)); GBar = calloc(pow(2,N),sizeof(int*));
+  h = calloc(pow(2,N),sizeof(int*));
+  
+  J = calloc(pow(2,N),sizeof(int*)); D = calloc(pow(2,N),sizeof(int*)); Q = calloc(pow(2,N),sizeof(int));
+
+  K = calloc(pow(2,N), sizeof(int));
+
+  double complex origGamma[(int)pow(2,N)];
+  int *origK, *origQ, **origD, ***origJ;
+  int ***origG, ***origGBar, **origh;
+
+  origG = calloc(pow(2,N),sizeof(int*)); origGBar = calloc(pow(2,N),sizeof(int*));
+  origh = calloc(pow(2,N),sizeof(int*));
+  
+  origJ = calloc(pow(2,N),sizeof(int*)); origD = calloc(pow(2,N),sizeof(int*)); origQ = calloc(pow(2,N),sizeof(int));
+
+  origK = calloc(pow(2,N), sizeof(int));
+
+  int combination; // a particular combination from the linear combo of stabilizer states making up the tensor factors multiplied together
+  
+
+  for(j=0; j<pow(2,N); j++) { // there will be 2^N combinations when using k=1 tensor factors
+    combination = j;
+
+    Gamma[j] = 1.0;
+    
+    G[j] = calloc(N, sizeof(int*)); GBar[j] = calloc(N, sizeof(int*));
+    h[j] = calloc(N, sizeof(int));
+
+    if(K[j] > 0) {
+
+      J[j] = calloc(K[j], sizeof(int*)); D[j] = calloc(K[j], sizeof(int));
+    }
+
+    origG[j] = calloc(N, sizeof(int*)); origGBar[j] = calloc(N, sizeof(int*));
+    origh[j] = calloc(N, sizeof(int));
+    
+    if(K[j] > 0) {
+      origJ[j] = calloc(K[j], sizeof(int*)); origD[j] = calloc(K[j], sizeof(int));
+    }
+
+    for(k=0; k<N; k++) {
+
+      Gamma[j] *= (1.0/sqrt(2.0))*((combination & 0x1)*cexp(0.25*PI*I) + (~combination & 0x1)*cexp(0.0*PI*I));
+      
+      G[j][k] = calloc(N, sizeof(int*)); GBar[j][k] = calloc(N, sizeof(int*));
+
+      if(K[j] > 0)
+       J[j] = calloc(K[j], sizeof(int*));
+
+      origG[j][k] = calloc(N, sizeof(int*)); origGBar[j][k] = calloc(N, sizeof(int*));
+      
+      if(K[j] > 0)
+       origJ[j] = calloc(K[j], sizeof(int*));
+      
+      h[j][k] = (combination & 0x1)*h2[0] + (~combination & 0x1)*h1[0];
+      for(l=0; l<n1; l++) { // assuming n1=n2
+       G[j][k][k*n1+l] = (combination & 0x1)*G2[0][l] + (~combination & 0x1)*G1[0][l];
+       GBar[j][k][k*n1+l] = (combination & 0x1)*GBar2[0][l] + (~combination & 0x1)*GBar1[0][l];
+      }
+      memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
+      
+      combination /= 2; // shift to the right by one (in base-2 arithmetic)
+    }
+
+    memcpy(origh[j], h[j], N*sizeof(int));
+
+  }
+
+  memcpy(origGamma, Gamma, pow(2,N)*sizeof(double complex));
+
+  while(readPaulicoeffs(&omega, alpha, beta, gamma, delta, N)) {
+
+    Paulicounter++;
+    if(Paulicounter > N) {
+      printf("Error: Number of Paulis is greater than N!\n");
+      return 1;
+    }
+    
+    // Let's break up the Ys into Xs and Zs in the order Z X, as required to pass to measurepauli()
+    // Y_i = -I*Z*X
+    for(i=0; i<N; i++) {
+      if(delta[i]){
+       omega += 3; // -I = I^3
+       beta[i] = delta[i];
+       gamma[i] = delta[i];
+      }
+    }
+
+    for(j=0; j<pow(2,N); j++) { // the kets
+
+      Gamma[j] *= measurepauli(N, &K[j], h[j], G[j], GBar[j], &Q[j], &D[j], &J[j], omega, gamma, beta);
+
+    }
+
+  }
+
+  double complex amplitude = 0.0 + 0.0*I;
+  for(i=0; i<pow(2,N); i++) { // the bras
+    for(j=0; j<pow(2,N); j++) {
+      // check to see if second arguments are modified!!! They shouldn't be!
+      double complex newamplitude = conj(origGamma[i])*Gamma[j]*innerproduct(N, K[j], h[j], G[j], GBar[j], Q[j], D[j], J[j], N, origK[i], origh[i], origG[i], origGBar[i], origQ[i], origD[i], origJ[i]);
+      amplitude = amplitude + newamplitude;
+    }
+  }
+
+  printf("amplitude:\n");
+  if(creal(amplitude+0.00000001)>0)
+    printf("%lf %c %lf I\n", cabs(creal(amplitude)), cimag(amplitude)>0?'+':'-' , cabs(cimag(amplitude)));
+  else
+    printf("%lf %c %lf I\n", creal(amplitude), cimag(amplitude)>0?'+':'-' , cabs(cimag(amplitude)));
+
+  return 0;
+
+}
+
+
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits)
+{
+    
+  int newomega, newalpha, newbeta, newgamma, newdelta;
+  int i;
+
+  if(scanf("%d", &newomega) != EOF) {
+    *omega = newomega;
+    for(i=0; i<numqubits; i++) {
+      if(scanf("%d %d %d %d", &newalpha, &newbeta, &newgamma, &newdelta) == EOF) {
+       printf("Error: Too few input coeffs!\n");
+       exit(0);
+      }
+      if(newalpha+newbeta+newgamma+newdelta > 1) {
+       printf("Error: Too many coefficients are non-zero at Pauli %d!\n", i);
+       exit(0);
+      }
+      alpha[i] = newalpha; beta[i] = newbeta; gamma[i] = newgamma; delta[i] = newdelta;
+    }
+    return 1;
+  } else
+    return 0;
+    
+}
+
+
+
+
+
+
+
diff --git a/strongsim12.c b/strongsim12.c
new file mode 100644 (file)
index 0000000..1db1250
--- /dev/null
@@ -0,0 +1,2013 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <complex.h>
+#include "matrix.h"
+#include "exponentialsum.h"
+#include "shrink.h"
+#include "extend.h"
+#include "measurepauli.h"
+#include "innerproduct.h"
+
+#define ZEROTHRESHOLD (0.00000001)
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits);
+
+void outerProductMod(int **A, int **B, int **C, int ro1, int co1, int ro2, int co2, int mod);
+
+// order of matrix elements is [row][column]!!!
+
+int main()
+{
+
+  int N;              // number of qubits
+  scanf("%d", &N);
+
+  if(N%12 != 0) {
+    printf("'N' needs to be a multiple of 12 for a k=12 tensor factor decomposition!\n");
+    return 1;
+  }
+
+  int T;              // number of T gate magic states (set to the first 'K' of the 'N' qubits -- the rest are set to the '0' computational basis state)
+  scanf("%d", &T);  
+
+  int omega;
+  int alpha[N], beta[N], gamma[N], delta[N];
+  int Paulicounter = 0;
+
+  int i, j, k, l, m;
+
+  double complex coeffb60 = (-16.0+12.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(6.0*PI*I/8.0)/8.0*cpow(2.0,3.0);
+  double complex coeffb66 = (96.0-68.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(6.0*PI*I/8.0)/8.0*cpow(2.0,3.0);
+  double complex coeffe6 = (10.0-7.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(6.0*PI*I/8.0)*cpow(2.0,2.5);
+  double complex coeffo6 = (-14.0+10.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(-14.0*PI*I/8.0)*cpow(2.0,2.5);
+  double complex coeffk6 = (7.0-5.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(-8.0*PI*I/8.0)*4.0*csqrt(2.0)*cpow(2.0,0.5);
+  double complex coeffphiprime = (10.0-7.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(2.0*PI*I/8.0)*cpow(2.0,2.5);
+  double complex coeffphidprime = (10.0-7.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(2.0*PI*I/8.0)*cpow(2.0,2.5);
+
+  // b60
+  int nn1 = 6; int kk1 = 6; int (*(GG1[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}}; int (*(GGBar1[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}}; int hh1[] = {0, 0, 0, 0, 0, 0}; int QQ1 = 0; int DD1[] = {0, 0, 0, 0, 0, 0}; int (*(JJ1[])) = { (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0} };
+  // b66
+  int nn2 = 6; int kk2 = 6; int (*(GG2[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}}; int (*(GGBar2[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}}; int hh2[] = {0, 0, 0, 0, 0, 0}; int QQ2 = 4; int DD2[] = {4, 4, 4, 4, 4, 4}; int (*(JJ2[])) = { (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0} };
+  // e6
+  int nn3 = 6; int kk3 = 5; int (*(GG3[])) = { (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0} }; int (*(GGBar3[])) = { (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1} }; int hh3[] = {1, 0, 0, 0, 0, 0}; int QQ3 = 4; int DD3[] = {0, 0, 0, 0, 0}; int (*(JJ3[])) = { (int[]) {0, 4, 4, 4, 4}, (int[]) {4, 0, 4, 4, 4}, (int[]) {4, 4, 0, 4, 4}, (int[]) {4, 4, 4, 0, 4}, (int[]) {4, 4, 4, 4, 0}  };
+  // o6
+  int nn4 = 6; int kk4 = 5; int (*(GG4[])) = { (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0} }; int (*(GGBar4[])) = { (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1} }; int hh4[] = {0, 0, 0, 0, 0, 0}; int QQ4 = 4; int DD4[] = {4, 4, 4, 4, 4}; int (*(JJ4[])) = { (int[]) {0, 4, 4, 4, 4}, (int[]) {4, 0, 4, 4, 4}, (int[]) {4, 4, 0, 4, 4}, (int[]) {4, 4, 4, 0, 4}, (int[]) {4, 4, 4, 4, 0}  };
+  // k6
+  int nn5 = 6; int kk5 = 1; int (*(GG5[])) = { (int[]) {1, 1, 1, 1, 1, 1}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1} }; int (*(GGBar5[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1} }; int hh5[] = {1, 1, 1, 1, 1, 1}; int QQ5 = 6; int DD5[] = {2}; int (*(JJ5[])) = { (int[]) {4} };
+  // phiprime
+  int nn6 = 6; int kk6 = 5; int (*(GG6[])) = { (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0} }; int (*(GGBar6[])) = { (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1} }; int hh6[] = {1, 0, 0, 0, 0, 0}; int QQ6 = 0; int DD6[] = {0, 0, 0, 0, 0}; int (*(JJ6[])) = { (int[]) {0, 4, 0, 0, 4}, (int[]) {4, 0, 4, 0, 0}, (int[]) {0, 4, 0, 4, 0}, (int[]) {0, 0, 4, 0, 4}, (int[]) {4, 0, 0, 4, 0}  };
+  // phidoubleprime
+  int nn7 = 6; int kk7 = 5; int (*(GG7[])) = { (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0} }; int (*(GGBar7[])) = { (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1} }; int hh7[] = {1, 0, 0, 0, 0, 0}; int QQ7 = 0; int DD7[] = {0, 0, 0, 0, 0}; int (*(JJ7[])) = { (int[]) {0, 0, 4, 4, 0}, (int[]) {0, 0, 0, 4, 4}, (int[]) {4, 0, 0, 0, 4}, (int[]) {4, 4, 0, 0, 0}, (int[]) {0, 4, 4, 0, 0}  };
+
+  // b60 * b60
+  int n1 = nn1+nn1; int k1 = kk1+kk1; int **G1; int **GBar1; int *h1; int Q1; int *D1; int **J1;
+  G1 = calloc(nn1+nn1,sizeof(int*));
+  GBar1 = calloc(nn1+nn1,sizeof(int*));
+  h1 = calloc(nn1+nn1,sizeof(int));
+  D1 = calloc(kk1+kk1,sizeof(int));
+  J1 = calloc(kk1+kk1,sizeof(int*));
+  for(i=0; i<nn1+nn1; i++) {
+    G1[i] = calloc(nn1+nn1, sizeof(int)); GBar1[i] = calloc(nn1+nn1, sizeof(int));
+  }
+  for(i=0; i<kk1+kk1; i++)
+     J1[i] = calloc(kk1+kk1, sizeof(int));
+  //appendBlockMatrix(GG1, GG1, G1, nn1, nn1, nn1, nn1);
+  addSubMatrix(GG1, G1, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GG1, G1, kk1, nn1, 0, 0, kk1, nn1);
+  addSubMatrix(GG1, G1, nn1-kk1, nn1, kk1, 0, kk1+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG1, G1, nn1-kk1, nn1, kk1, 0, kk1+kk1+nn1-kk1, nn1);
+  //appendBlockMatrix(GGBar1, GGBar1, GBar1, nn1, nn1, nn1, nn1);
+  addSubMatrix(GGBar1, GBar1, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GGBar1, GBar1, kk1, nn1, 0, 0, kk1, nn1);
+  addSubMatrix(GGBar1, GBar1, nn1-kk1, nn1, kk1, 0, kk1+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar1, GBar1, nn1-kk1, nn1, kk1, 0, kk1+kk1+nn1-kk1, nn1);
+  appendVector(hh1, hh1, h1, nn1, nn1);
+  Q1 = (QQ1+QQ1);
+  appendVector(DD1, DD1, D1, kk1, kk1);
+  appendBlockMatrix(JJ1, JJ1, J1, kk1, kk1, kk1, kk1);
+  //addSubMatrix(JJ1, J1, kk1, kk1, 0, 0, 0, 0);
+  //addSubMatrix(JJ1, J1, kk1, kk1, 0, 0, kk1, kk1);
+
+  // b66 * b60
+  /*int n2 = nn1+nn2; int k2 = kk1+kk2; int **G2; int **GBar2; int *h2; int Q2; int *D2; int **J2;
+  G2 = calloc(nn1+nn2,sizeof(int*));
+  GBar2 = calloc(nn1+nn2,sizeof(int*));
+  h2 = calloc(nn1+nn2,sizeof(int));
+  D2 = calloc(kk1+kk2,sizeof(int));
+  J2 = calloc(kk1+kk2,sizeof(int*));
+  for(i=0; i<nn1+nn2; i++) {
+    G2[i] = calloc(nn1+nn2, sizeof(int)); GBar2[i] = calloc(nn1+nn2, sizeof(int));
+  }
+  for(i=0; i<kk1+kk2; i++)
+     J2[i] = calloc(kk1+kk2, sizeof(int));
+  //appendBlockMatrix(GG2, GG1, G2, nn2, nn2, nn1, nn1);
+  addSubMatrix(GG2, G2, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GG1, G2, kk1, nn1, 0, 0, kk2, nn2);
+  addSubMatrix(GG2, G2, nn2-kk2, nn2, kk2, 0, kk2+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG1, G2, nn1-kk1, nn1, kk1, 0, kk2+kk1+nn2-kk2, nn1);
+  //appendBlockMatrix(GGBar2, GGBar1, GBar2, nn2, nn2, nn1, nn1);
+  addSubMatrix(GGBar2, GBar2, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GGBar1, GBar2, kk1, nn1, 0, 0, kk2, nn2);
+  addSubMatrix(GGBar2, GBar2, nn2-kk2, nn2, kk2, 0, kk2+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar1, GBar2, nn1-kk1, nn1, kk1, 0, kk2+kk1+nn2-kk2, nn1);
+  appendVector(hh2, hh1, h2, nn2, nn1);
+  Q2 = (QQ1+QQ2);
+  appendVector(DD2, DD1, D2, kk2, kk1);
+  appendBlockMatrix(JJ2, JJ1, J2, kk2, kk2, kk1, kk1);*/
+
+  // e6 * b60
+  int n2 = nn1+nn3; int k2 = kk1+kk3; int **G2; int **GBar2; int *h2; int Q2; int *D2; int **J2;
+  G2 = calloc(nn1+nn3,sizeof(int*));
+  GBar2 = calloc(nn1+nn3,sizeof(int*));
+  h2 = calloc(nn1+nn3,sizeof(int));
+  D2 = calloc(kk1+kk3,sizeof(int));
+  J2 = calloc(kk1+kk3,sizeof(int*));
+  for(i=0; i<nn1+nn3; i++) {
+    G2[i] = calloc(nn1+nn3, sizeof(int)); GBar2[i] = calloc(nn1+nn3, sizeof(int));
+  }
+  for(i=0; i<kk1+kk3; i++)
+     J2[i] = calloc(kk1+kk3, sizeof(int));
+  //appendBlockMatrix(GG3, GG1, G3, nn3, nn3, nn1, nn1);
+  addSubMatrix(GG3, G2, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GG1, G2, kk1, nn1, 0, 0, kk3, nn3);
+  addSubMatrix(GG3, G2, nn3-kk3, nn3, kk3, 0, kk3+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG1, G2, nn1-kk1, nn1, kk1, 0, kk3+kk1+nn3-kk3, nn1);
+  //appendBlockMatrix(GGBar3, GGBar1, GBar3, nn3, nn3, nn1, nn1);
+  addSubMatrix(GGBar3, GBar2, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GGBar1, GBar2, kk1, nn1, 0, 0, kk3, nn3);
+  addSubMatrix(GGBar3, GBar2, nn3-kk3, nn3, kk3, 0, kk3+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar1, GBar2, nn1-kk1, nn1, kk1, 0, kk3+kk1+nn3-kk3, nn1);
+  appendVector(hh3, hh1, h2, nn3, nn1);
+  Q2 = (QQ1+QQ3);
+  appendVector(DD3, DD1, D2, kk3, kk1);
+  appendBlockMatrix(JJ3, JJ1, J2, kk3, kk3, kk1, kk1);
+  
+  // o6 * b60
+  int n3 = nn1+nn4; int k3 = kk1+kk4; int **G3; int **GBar3; int *h3; int Q3; int *D3; int **J3;
+  G3 = calloc(nn1+nn4,sizeof(int*));
+  GBar3 = calloc(nn1+nn4,sizeof(int*));
+  h3 = calloc(nn1+nn4,sizeof(int));
+  D3 = calloc(kk1+kk4,sizeof(int));
+  J3 = calloc(kk1+kk4,sizeof(int*));
+  for(i=0; i<nn1+nn4; i++) {
+    G3[i] = calloc(nn1+nn4, sizeof(int)); GBar3[i] = calloc(nn1+nn4, sizeof(int));
+  }
+  for(i=0; i<kk1+kk4; i++)
+     J3[i] = calloc(kk1+kk4, sizeof(int));
+  //appendBlockMatrix(GG4, GG1, G4, nn4, nn4, nn1, nn1);
+  addSubMatrix(GG4, G3, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GG1, G3, kk1, nn1, 0, 0, kk4, nn4);
+  addSubMatrix(GG4, G3, nn4-kk4, nn4, kk4, 0, kk4+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG1, G3, nn1-kk1, nn1, kk1, 0, kk4+kk1+nn4-kk4, nn1);
+  //appendBlockMatrix(GGBar4, GGBar1, GBar4, nn4, nn4, nn1, nn1);
+  addSubMatrix(GGBar4, GBar3, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GGBar1, GBar3, kk1, nn1, 0, 0, kk4, nn4);
+  addSubMatrix(GGBar4, GBar3, nn4-kk4, nn4, kk4, 0, kk4+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar1, GBar3, nn1-kk1, nn1, kk1, 0, kk4+kk1+nn4-kk4, nn1);
+  appendVector(hh4, hh1, h3, nn4, nn1);
+  Q3 = (QQ1+QQ4);
+  appendVector(DD4, DD1, D3, kk4, kk1);
+  appendBlockMatrix(JJ4, JJ1, J3, kk4, kk4, kk1, kk1);
+
+  // k6 * b60
+  int n4 = nn1+nn5; int k4 = kk1+kk5; int **G4; int **GBar4; int *h4; int Q4; int *D4; int **J4;
+  G4 = calloc(nn1+nn5,sizeof(int*));
+  GBar4 = calloc(nn1+nn5,sizeof(int*));
+  h4 = calloc(nn1+nn5,sizeof(int));
+  D4 = calloc(kk1+kk5,sizeof(int));
+  J4 = calloc(kk1+kk5,sizeof(int*));
+  for(i=0; i<nn1+nn5; i++) {
+    G4[i] = calloc(nn1+nn5, sizeof(int)); GBar4[i] = calloc(nn1+nn5, sizeof(int));
+  }
+  for(i=0; i<kk1+kk5; i++)
+     J4[i] = calloc(kk1+kk5, sizeof(int));
+  //appendBlockMatrix(GG5, GG1, G5, nn5, nn5, nn1, nn1);
+  addSubMatrix(GG5, G4, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GG1, G4, kk1, nn1, 0, 0, kk5, nn5);
+  addSubMatrix(GG5, G4, nn5-kk5, nn5, kk5, 0, kk5+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG1, G4, nn1-kk1, nn1, kk1, 0, kk5+kk1+nn5-kk5, nn1);
+  //appendBlockMatrix(GGBar5, GGBar1, GBar5, nn5, nn5, nn1, nn1);
+  addSubMatrix(GGBar5, GBar4, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GGBar1, GBar4, kk1, nn1, 0, 0, kk5, nn5);
+  addSubMatrix(GGBar5, GBar4, nn5-kk5, nn5, kk5, 0, kk5+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar1, GBar4, nn1-kk1, nn1, kk1, 0, kk5+kk1+nn5-kk5, nn1);
+  appendVector(hh5, hh1, h4, nn5, nn1);
+  Q4 = (QQ1+QQ5);
+  appendVector(DD5, DD1, D4, kk5, kk1);
+  appendBlockMatrix(JJ5, JJ1, J4, kk5, kk5, kk1, kk1);
+
+  // phiprime * b60 
+  int n5 = nn1+nn6; int k5 = kk1+kk6; int **G5; int **GBar5; int *h5; int Q5; int *D5; int **J5;
+  G5 = calloc(nn1+nn6,sizeof(int*));
+  GBar5 = calloc(nn1+nn6,sizeof(int*));
+  h5 = calloc(nn1+nn6,sizeof(int));
+  D5 = calloc(kk1+kk6,sizeof(int));
+  J5 = calloc(kk1+kk6,sizeof(int*));
+  for(i=0; i<nn1+nn6; i++) {
+    G5[i] = calloc(nn1+nn6, sizeof(int)); GBar5[i] = calloc(nn1+nn6, sizeof(int));
+  }
+  for(i=0; i<kk1+kk6; i++)
+     J5[i] = calloc(kk1+kk6, sizeof(int));
+  //appendBlockMatrix(GG6, GG1, G6, nn6, nn6, nn1, nn1);
+  addSubMatrix(GG6, G5, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GG1, G5, kk1, nn1, 0, 0, kk6, nn6);
+  addSubMatrix(GG6, G5, nn6-kk6, nn6, kk6, 0, kk6+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG1, G5, nn1-kk1, nn1, kk1, 0, kk6+kk1+nn6-kk6, nn1);
+  //appendBlockMatrix(GGBar6, GGBar1, GBar6, nn6, nn6, nn1, nn1);
+  addSubMatrix(GGBar6, GBar5, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GGBar1, GBar5, kk1, nn1, 0, 0, kk6, nn6);
+  addSubMatrix(GGBar6, GBar5, nn6-kk6, nn6, kk6, 0, kk6+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar1, GBar5, nn1-kk1, nn1, kk1, 0, kk6+kk1+nn6-kk6, nn1);
+  appendVector(hh6, hh1, h5, nn6, nn1);
+  Q5 = (QQ1+QQ6);
+  appendVector(DD6, DD1, D5, kk6, kk1);
+  appendBlockMatrix(JJ6, JJ1, J5, kk6, kk6, kk1, kk1);
+  
+  // phidprime * b60
+  int n6 = nn1+nn7; int k6 = kk1+kk7; int **G6; int **GBar6; int *h6; int Q6; int *D6; int **J6;
+  G6 = calloc(nn1+nn7,sizeof(int*));
+  GBar6 = calloc(nn1+nn7,sizeof(int*));
+  h6 = calloc(nn1+nn7,sizeof(int));
+  D6 = calloc(kk1+kk7,sizeof(int));
+  J6 = calloc(kk1+kk7,sizeof(int*));
+  for(i=0; i<nn1+nn7; i++) {
+    G6[i] = calloc(nn1+nn7, sizeof(int)); GBar6[i] = calloc(nn1+nn7, sizeof(int));
+  }
+  for(i=0; i<kk1+kk7; i++)
+     J6[i] = calloc(kk1+kk7, sizeof(int));
+  //appendBlockMatrix(GG7, GG1, G7, nn7, nn7, nn1, nn1);
+  addSubMatrix(GG7, G6, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GG1, G6, kk1, nn1, 0, 0, kk7, nn7);
+  addSubMatrix(GG7, G6, nn7-kk7, nn7, kk7, 0, kk7+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG1, G6, nn1-kk1, nn1, kk1, 0, kk7+kk1+nn7-kk7, nn1);
+  //appendBlockMatrix(GGBar7, GGBar1, GBar7, nn7, nn7, nn1, nn1);
+  addSubMatrix(GGBar7, GBar6, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GGBar1, GBar6, kk1, nn1, 0, 0, kk7, nn7);
+  addSubMatrix(GGBar7, GBar6, nn7-kk7, nn7, kk7, 0, kk7+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar1, GBar6, nn1-kk1, nn1, kk1, 0, kk7+kk1+nn7-kk7, nn1);
+  appendVector(hh7, hh1, h6, nn7, nn1);
+  Q6 = (QQ1+QQ7);
+  appendVector(DD7, DD1, D6, kk7, kk1);
+  appendBlockMatrix(JJ7, JJ1, J6, kk7, kk7, kk1, kk1);
+
+  // b60 * b66
+  /*int n8 = nn2+nn1; int k8 = kk2+kk1; int **G8; int **GBar8; int *h8; int Q8; int *D8; int **J8;
+  G8 = calloc(nn2+nn1,sizeof(int*));
+  GBar8 = calloc(nn2+nn1,sizeof(int*));
+  h8 = calloc(nn2+nn1,sizeof(int));
+  D8 = calloc(kk2+kk1,sizeof(int));
+  J8 = calloc(kk2+kk1,sizeof(int*));
+  for(i=0; i<nn2+nn1; i++) {
+    G8[i] = calloc(nn2+nn1, sizeof(int)); GBar8[i] = calloc(nn2+nn1, sizeof(int));
+  }
+  for(i=0; i<kk2+kk1; i++)
+     J8[i] = calloc(kk2+kk1, sizeof(int));
+  //appendBlockMatrix(GG1, GG2, G8, nn1, nn1, nn2, nn2);
+  addSubMatrix(GG1, G8, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GG2, G8, kk2, nn2, 0, 0, kk1, nn1);
+  addSubMatrix(GG1, G8, nn1-kk1, nn1, kk1, 0, kk1+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG2, G8, nn2-kk2, nn2, kk2, 0, kk1+kk2+nn1-kk1, nn2);
+  //appendBlockMatrix(GGBar1, GGBar2, GBar8, nn1, nn1, nn2, nn2);
+  addSubMatrix(GGBar1, GBar8, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GGBar2, GBar8, kk2, nn2, 0, 0, kk1, nn1);
+  addSubMatrix(GGBar1, GBar8, nn1-kk1, nn1, kk1, 0, kk1+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar2, GBar8, nn2-kk2, nn2, kk2, 0, kk1+kk2+nn1-kk1, nn2);
+  appendVector(hh1, hh2, h8, nn1, nn2);
+  Q8 = (QQ2+QQ1);
+  appendVector(DD1, DD2, D8, kk1, kk2);
+  appendBlockMatrix(JJ1, JJ2, J8, kk1, kk1, kk2, kk2);*/
+
+  // b66 * b66
+  int n7 = nn2+nn2; int k7 = kk2+kk2; int **G7; int **GBar7; int *h7; int Q7; int *D7; int **J7;
+  G7 = calloc(nn2+nn2,sizeof(int*));
+  GBar7 = calloc(nn2+nn2,sizeof(int*));
+  h7 = calloc(nn2+nn2,sizeof(int));
+  D7 = calloc(kk2+kk2,sizeof(int));
+  J7 = calloc(kk2+kk2,sizeof(int*));
+  for(i=0; i<nn2+nn2; i++) {
+    G7[i] = calloc(nn2+nn2, sizeof(int)); GBar7[i] = calloc(nn2+nn2, sizeof(int));
+  }
+  for(i=0; i<kk2+kk2; i++)
+     J7[i] = calloc(kk2+kk2, sizeof(int));
+  //appendBlockMatrix(GG2, GG2, G9, nn2, nn2, nn2, nn2);
+  addSubMatrix(GG2, G7, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GG2, G7, kk2, nn2, 0, 0, kk2, nn2);
+  addSubMatrix(GG2, G7, nn2-kk2, nn2, kk2, 0, kk2+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG2, G7, nn2-kk2, nn2, kk2, 0, kk2+kk2+nn2-kk2, nn2);
+  //appendBlockMatrix(GGBar2, GGBar2, GBar9, nn2, nn2, nn2, nn2);
+  addSubMatrix(GGBar2, GBar7, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GGBar2, GBar7, kk2, nn2, 0, 0, kk2, nn2);
+  addSubMatrix(GGBar2, GBar7, nn2-kk2, nn2, kk2, 0, kk2+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar2, GBar7, nn2-kk2, nn2, kk2, 0, kk2+kk2+nn2-kk2, nn2);
+  appendVector(hh2, hh2, h7, nn2, nn2);
+  Q7 = (QQ2+QQ2);
+  appendVector(DD2, DD2, D7, kk2, kk2);
+  appendBlockMatrix(JJ2, JJ2, J7, kk2, kk2, kk2, kk2);
+
+  // e6 * b66
+  int n8 = nn2+nn3; int k8 = kk2+kk3; int **G8; int **GBar8; int *h8; int Q8; int *D8; int **J8;
+  G8 = calloc(nn2+nn3,sizeof(int*));
+  GBar8 = calloc(nn2+nn3,sizeof(int*));
+  h8 = calloc(nn2+nn3,sizeof(int));
+  D8 = calloc(kk2+kk3,sizeof(int));
+  J8 = calloc(kk2+kk3,sizeof(int*));
+  for(i=0; i<nn2+nn3; i++) {
+    G8[i] = calloc(nn2+nn3, sizeof(int)); GBar8[i] = calloc(nn2+nn3, sizeof(int));
+  }
+  for(i=0; i<kk2+kk3; i++)
+     J8[i] = calloc(kk2+kk3, sizeof(int));
+  //appendBlockMatrix(GG3, GG2, G10, nn3, nn3, nn2, nn2);
+  addSubMatrix(GG3, G8, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GG2, G8, kk2, nn2, 0, 0, kk3, nn3);
+  addSubMatrix(GG3, G8, nn3-kk3, nn3, kk3, 0, kk3+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG2, G8, nn2-kk2, nn2, kk2, 0, kk3+kk2+nn3-kk3, nn2);
+  //appendBlockMatrix(GGBar3, GGBar2, GBar10, nn3, nn3, nn2, nn2);
+  addSubMatrix(GGBar3, GBar8, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GGBar2, GBar8, kk2, nn2, 0, 0, kk3, nn3);
+  addSubMatrix(GGBar3, GBar8, nn3-kk3, nn3, kk3, 0, kk3+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar2, GBar8, nn2-kk2, nn2, kk2, 0, kk3+kk2+nn3-kk3, nn2);
+  appendVector(hh3, hh2, h8, nn3, nn2);
+  Q8 = (QQ2+QQ3);
+  appendVector(DD3, DD2, D8, kk3, kk2);
+  appendBlockMatrix(JJ3, JJ2, J8, kk3, kk3, kk2, kk2);
+
+  // o6 * b66
+  int n9 = nn2+nn4; int k9 = kk2+kk4; int **G9; int **GBar9; int *h9; int Q9; int *D9; int **J9;
+  G9 = calloc(nn2+nn4,sizeof(int*));
+  GBar9 = calloc(nn2+nn4,sizeof(int*));
+  h9 = calloc(nn2+nn4,sizeof(int));
+  D9 = calloc(kk2+kk4,sizeof(int));
+  J9 = calloc(kk2+kk4,sizeof(int*));
+  for(i=0; i<nn2+nn4; i++) {
+    G9[i] = calloc(nn2+nn4, sizeof(int)); GBar9[i] = calloc(nn2+nn4, sizeof(int));
+  }
+  for(i=0; i<kk2+kk4; i++)
+     J9[i] = calloc(kk2+kk4, sizeof(int));
+  //appendBlockMatrix(GG4, GG2, G11, nn4, nn4, nn2, nn2);
+  addSubMatrix(GG4, G9, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GG2, G9, kk2, nn2, 0, 0, kk4, nn4);
+  addSubMatrix(GG4, G9, nn4-kk4, nn4, kk4, 0, kk4+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG2, G9, nn2-kk2, nn2, kk2, 0, kk4+kk2+nn4-kk4, nn2);
+  //appendBlockMatrix(GGBar4, GGBar2, GBar11, nn4, nn4, nn2, nn2);
+  addSubMatrix(GGBar4, GBar9, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GGBar2, GBar9, kk2, nn2, 0, 0, kk4, nn4);
+  addSubMatrix(GGBar4, GBar9, nn4-kk4, nn4, kk4, 0, kk4+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar2, GBar9, nn2-kk2, nn2, kk2, 0, kk4+kk2+nn4-kk4, nn2);
+  appendVector(hh4, hh2, h9, nn4, nn2);
+  Q9 = (QQ2+QQ4);
+  appendVector(DD4, DD2, D9, kk4, kk2);
+  appendBlockMatrix(JJ4, JJ2, J9, kk4, kk4, kk2, kk2);
+
+  // k6 * b66
+  int n10 = nn2+nn5; int k10 = kk2+kk5; int **G10; int **GBar10; int *h10; int Q10; int *D10; int **J10;
+  G10 = calloc(nn2+nn5,sizeof(int*));
+  GBar10 = calloc(nn2+nn5,sizeof(int*));
+  h10 = calloc(nn2+nn5,sizeof(int));
+  D10 = calloc(kk2+kk5,sizeof(int));
+  J10 = calloc(kk2+kk5,sizeof(int*));
+  for(i=0; i<nn2+nn5; i++) {
+    G10[i] = calloc(nn2+nn5, sizeof(int)); GBar10[i] = calloc(nn2+nn5, sizeof(int));
+  }
+  for(i=0; i<kk2+kk5; i++)
+     J10[i] = calloc(kk2+kk5, sizeof(int));
+  //appendBlockMatrix(GG5, GG2, G12, nn5, nn5, nn2, nn2);
+  addSubMatrix(GG5, G10, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GG2, G10, kk2, nn2, 0, 0, kk5, nn5);
+  addSubMatrix(GG5, G10, nn5-kk5, nn5, kk5, 0, kk5+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG2, G10, nn2-kk2, nn2, kk2, 0, kk5+kk2+nn5-kk5, nn2);
+  //appendBlockMatrix(GGBar5, GGBar2, GBar12, nn5, nn5, nn2, nn2);
+  addSubMatrix(GGBar5, GBar10, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GGBar2, GBar10, kk2, nn2, 0, 0, kk5, nn5);
+  addSubMatrix(GGBar5, GBar10, nn5-kk5, nn5, kk5, 0, kk5+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar2, GBar10, nn2-kk2, nn2, kk2, 0, kk5+kk2+nn5-kk5, nn2);
+  appendVector(hh5, hh2, h10, nn5, nn2);
+  Q10 = (QQ2+QQ5);
+  appendVector(DD5, DD2, D10, kk5, kk2);
+  appendBlockMatrix(JJ5, JJ2, J10, kk5, kk5, kk2, kk2);
+  
+  // phiprime * b66
+  int n11 = nn2+nn6; int k11 = kk2+kk6; int **G11; int **GBar11; int *h11; int Q11; int *D11; int **J11;
+  G11 = calloc(nn2+nn6,sizeof(int*));
+  GBar11 = calloc(nn2+nn6,sizeof(int*));
+  h11 = calloc(nn2+nn6,sizeof(int));
+  D11 = calloc(kk2+kk6,sizeof(int));
+  J11 = calloc(kk2+kk6,sizeof(int*));
+  for(i=0; i<nn2+nn6; i++) {
+    G11[i] = calloc(nn2+nn6, sizeof(int)); GBar11[i] = calloc(nn2+nn6, sizeof(int));
+  }
+  for(i=0; i<kk2+kk6; i++)
+     J11[i] = calloc(kk2+kk6, sizeof(int));
+  //appendBlockMatrix(GG6, GG2, G13, nn6, nn6, nn2, nn2);
+  addSubMatrix(GG6, G11, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GG2, G11, kk2, nn2, 0, 0, kk6, nn6);
+  addSubMatrix(GG6, G11, nn6-kk6, nn6, kk6, 0, kk6+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG2, G11, nn2-kk2, nn2, kk2, 0, kk6+kk2+nn6-kk6, nn2);
+  //appendBlockMatrix(GGBar6, GGBar2, GBar13, nn6, nn6, nn2, nn2);
+  addSubMatrix(GGBar6, GBar11, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GGBar2, GBar11, kk2, nn2, 0, 0, kk6, nn6);
+  addSubMatrix(GGBar6, GBar11, nn6-kk6, nn6, kk6, 0, kk6+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar2, GBar11, nn2-kk2, nn2, kk2, 0, kk6+kk2+nn6-kk6, nn2);
+  appendVector(hh6, hh2, h11, nn6, nn2);
+  Q11 = (QQ2+QQ6);
+  appendVector(DD6, DD2, D11, kk6, kk2);
+  appendBlockMatrix(JJ6, JJ2, J11, kk6, kk6, kk2, kk2);
+
+  // phidprime * b66
+  int n12 = nn2+nn7; int k12 = kk2+kk7; int **G12; int **GBar12; int *h12; int Q12; int *D12; int **J12;
+  G12 = calloc(nn2+nn7,sizeof(int*));
+  GBar12 = calloc(nn2+nn7,sizeof(int*));
+  h12 = calloc(nn2+nn7,sizeof(int));
+  D12 = calloc(kk2+kk7,sizeof(int));
+  J12 = calloc(kk2+kk7,sizeof(int*));
+  for(i=0; i<nn2+nn7; i++) {
+    G12[i] = calloc(nn2+nn7, sizeof(int)); GBar12[i] = calloc(nn2+nn7, sizeof(int));
+  }
+  for(i=0; i<kk2+kk7; i++)
+     J12[i] = calloc(kk2+kk7, sizeof(int));
+  //appendBlockMatrix(GG7, GG2, G14, nn7, nn7, nn2, nn2);
+  addSubMatrix(GG7, G12, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GG2, G12, kk2, nn2, 0, 0, kk7, nn7);
+  addSubMatrix(GG7, G12, nn7-kk7, nn7, kk7, 0, kk7+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG2, G12, nn2-kk2, nn2, kk2, 0, kk7+kk2+nn7-kk7, nn2);
+  //appendBlockMatrix(GGBar7, GGBar2, GBar14, nn7, nn7, nn2, nn2);
+  addSubMatrix(GGBar7, GBar12, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GGBar2, GBar12, kk2, nn2, 0, 0, kk7, nn7);
+  addSubMatrix(GGBar7, GBar12, nn7-kk7, nn7, kk7, 0, kk7+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar2, GBar12, nn2-kk2, nn2, kk2, 0, kk7+kk2+nn7-kk7, nn2);
+  appendVector(hh7, hh2, h12, nn7, nn2);
+  Q12 = (QQ2+QQ7);
+  appendVector(DD7, DD2, D12, kk7, kk2);
+  appendBlockMatrix(JJ7, JJ2, J12, kk7, kk7, kk2, kk2);
+
+  // b60 * e6
+  int n13 = nn3+nn1; int k13 = kk3+kk1; int **G13; int **GBar13; int *h13; int Q13; int *D13; int **J13;
+  G13 = calloc(nn3+nn1,sizeof(int*));
+  GBar13 = calloc(nn3+nn1,sizeof(int*));
+  h13 = calloc(nn3+nn1,sizeof(int));
+  D13 = calloc(kk3+kk1,sizeof(int));
+  J13 = calloc(kk3+kk1,sizeof(int*));
+  for(i=0; i<nn3+nn1; i++) {
+    G13[i] = calloc(nn3+nn1, sizeof(int)); GBar13[i] = calloc(nn3+nn1, sizeof(int));
+  }
+  for(i=0; i<kk3+kk1; i++)
+     J13[i] = calloc(kk3+kk1, sizeof(int));
+  //appendBlockMatrix(GG1, GG3, G15, nn1, nn1, nn3, nn3);
+  addSubMatrix(GG1, G13, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GG3, G13, kk3, nn3, 0, 0, kk1, nn1);
+  addSubMatrix(GG1, G13, nn1-kk1, nn1, kk1, 0, kk1+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG3, G13, nn3-kk3, nn3, kk3, 0, kk1+kk3+nn1-kk1, nn3);
+  //appendBlockMatrix(GGBar1, GGBar3, GBar15, nn1, nn1, nn3, nn3);
+  addSubMatrix(GGBar1, GBar13, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GGBar3, GBar13, kk3, nn3, 0, 0, kk1, nn1);
+  addSubMatrix(GGBar1, GBar13, nn1-kk1, nn1, kk1, 0, kk1+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar3, GBar13, nn3-kk3, nn3, kk3, 0, kk1+kk3+nn1-kk1, nn3);
+  appendVector(hh1, hh3, h13, nn1, nn3);
+  Q13 = (QQ3+QQ1);
+  appendVector(DD1, DD3, D13, kk1, kk3);
+  appendBlockMatrix(JJ1, JJ3, J13, kk1, kk1, kk3, kk3);
+
+  // b66 * e6
+  int n14 = nn3+nn2; int k14 = kk3+kk2; int **G14; int **GBar14; int *h14; int Q14; int *D14; int **J14;
+  G14 = calloc(nn3+nn2,sizeof(int*));
+  GBar14 = calloc(nn3+nn2,sizeof(int*));
+  h14 = calloc(nn3+nn2,sizeof(int));
+  D14 = calloc(kk3+kk2,sizeof(int));
+  J14 = calloc(kk3+kk2,sizeof(int*));
+  for(i=0; i<nn3+nn2; i++) {
+    G14[i] = calloc(nn3+nn2, sizeof(int)); GBar14[i] = calloc(nn3+nn2, sizeof(int));
+  }
+  for(i=0; i<kk3+kk2; i++)
+     J14[i] = calloc(kk3+kk2, sizeof(int));
+  //appendBlockMatrix(GG2, GG3, G16, nn2, nn2, nn3, nn3);
+  addSubMatrix(GG2, G14, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GG3, G14, kk3, nn3, 0, 0, kk2, nn2);
+  addSubMatrix(GG2, G14, nn2-kk2, nn2, kk2, 0, kk2+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG3, G14, nn3-kk3, nn3, kk3, 0, kk2+kk3+nn2-kk2, nn3);
+  //appendBlockMatrix(GGBar2, GGBar3, GBar16, nn2, nn2, nn3, nn3);
+  addSubMatrix(GGBar2, GBar14, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GGBar3, GBar14, kk3, nn3, 0, 0, kk2, nn2);
+  addSubMatrix(GGBar2, GBar14, nn2-kk2, nn2, kk2, 0, kk2+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar3, GBar14, nn3-kk3, nn3, kk3, 0, kk2+kk3+nn2-kk2, nn3);
+  appendVector(hh2, hh3, h14, nn2, nn3);
+  Q14 = (QQ3+QQ2);
+  appendVector(DD2, DD3, D14, kk2, kk3);
+  appendBlockMatrix(JJ2, JJ3, J14, kk2, kk2, kk3, kk3);
+
+  // e6 * e6
+  int n15 = nn3+nn3; int k15 = kk3+kk3; int **G15; int **GBar15; int *h15; int Q15; int *D15; int **J15;
+  G15 = calloc(nn3+nn3,sizeof(int*));
+  GBar15 = calloc(nn3+nn3,sizeof(int*));
+  h15 = calloc(nn3+nn3,sizeof(int));
+  D15 = calloc(kk3+kk3,sizeof(int));
+  J15 = calloc(kk3+kk3,sizeof(int*));
+  for(i=0; i<nn3+nn3; i++) {
+    G15[i] = calloc(nn3+nn3, sizeof(int)); GBar15[i] = calloc(nn3+nn3, sizeof(int));
+  }
+  for(i=0; i<kk3+kk3; i++)
+     J15[i] = calloc(kk3+kk3, sizeof(int));
+  //appendBlockMatrix(GG3, GG3, G17, nn3, nn3, nn3, nn3);
+  addSubMatrix(GG3, G15, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GG3, G15, kk3, nn3, 0, 0, kk3, nn3);
+  addSubMatrix(GG3, G15, nn3-kk3, nn3, kk3, 0, kk3+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG3, G15, nn3-kk3, nn3, kk3, 0, kk3+kk3+nn3-kk3, nn3);
+  //appendBlockMatrix(GGBar3, GGBar3, GBar17, nn3, nn3, nn3, nn3);
+  addSubMatrix(GGBar3, GBar15, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GGBar3, GBar15, kk3, nn3, 0, 0, kk3, nn3);
+  addSubMatrix(GGBar3, GBar15, nn3-kk3, nn3, kk3, 0, kk3+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar3, GBar15, nn3-kk3, nn3, kk3, 0, kk3+kk3+nn3-kk3, nn3);
+  appendVector(hh3, hh3, h15, nn3, nn3);
+  Q15 = (QQ3+QQ3);
+  appendVector(DD3, DD3, D15, kk3, kk3);
+  appendBlockMatrix(JJ3, JJ3, J15, kk3, kk3, kk3, kk3);
+
+  // o6 * e6
+  /*int n18 = nn3+nn4; int k18 = kk3+kk4; int **G18; int **GBar18; int *h18; int Q18; int *D18; int **J18;
+  G18 = calloc(nn3+nn4,sizeof(int*));
+  GBar18 = calloc(nn3+nn4,sizeof(int*));
+  h18 = calloc(nn3+nn4,sizeof(int));
+  D18 = calloc(kk3+kk4,sizeof(int));
+  J18 = calloc(kk3+kk4,sizeof(int*));
+  for(i=0; i<nn3+nn4; i++) {
+    G18[i] = calloc(nn3+nn4, sizeof(int)); GBar18[i] = calloc(nn3+nn4, sizeof(int));
+  }
+  for(i=0; i<kk3+kk4; i++)
+     J18[i] = calloc(kk3+kk4, sizeof(int));
+  //appendBlockMatrix(GG4, GG3, G18, nn4, nn4, nn3, nn3);
+  addSubMatrix(GG4, G18, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GG3, G18, kk3, nn3, 0, 0, kk4, nn4);
+  addSubMatrix(GG4, G18, nn4-kk4, nn4, kk4, 0, kk4+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG3, G18, nn3-kk3, nn3, kk3, 0, kk4+kk3+nn4-kk4, nn3);
+  //appendBlockMatrix(GGBar4, GGBar3, GBar18, nn4, nn4, nn3, nn3);
+  addSubMatrix(GGBar4, GBar18, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GGBar3, GBar18, kk3, nn3, 0, 0, kk4, nn4);
+  addSubMatrix(GGBar4, GBar18, nn4-kk4, nn4, kk4, 0, kk4+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar3, GBar18, nn3-kk3, nn3, kk3, 0, kk4+kk3+nn4-kk4, nn3);
+  appendVector(hh4, hh3, h18, nn4, nn3);
+  Q18 = (QQ3+QQ4);
+  appendVector(DD4, DD3, D18, kk4, kk3);
+  appendBlockMatrix(JJ4, JJ3, J18, kk4, kk4, kk3, kk3);*/
+
+  // k6 * e6
+  int n16 = nn3+nn5; int k16 = kk3+kk5; int **G16; int **GBar16; int *h16; int Q16; int *D16; int **J16;
+  G16 = calloc(nn3+nn5,sizeof(int*));
+  GBar16 = calloc(nn3+nn5,sizeof(int*));
+  h16 = calloc(nn3+nn5,sizeof(int));
+  D16 = calloc(kk3+kk5,sizeof(int));
+  J16 = calloc(kk3+kk5,sizeof(int*));
+  for(i=0; i<nn3+nn5; i++) {
+    G16[i] = calloc(nn3+nn5, sizeof(int)); GBar16[i] = calloc(nn3+nn5, sizeof(int));
+  }
+  for(i=0; i<kk3+kk5; i++)
+     J16[i] = calloc(kk3+kk5, sizeof(int));
+  //appendBlockMatrix(GG5, GG3, G19, nn5, nn5, nn3, nn3);
+  addSubMatrix(GG5, G16, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GG3, G16, kk3, nn3, 0, 0, kk5, nn5);
+  addSubMatrix(GG5, G16, nn5-kk5, nn5, kk5, 0, kk5+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG3, G16, nn3-kk3, nn3, kk3, 0, kk5+kk3+nn5-kk5, nn3);
+  //appendBlockMatrix(GGBar5, GGBar3, GBar19, nn5, nn5, nn3, nn3);
+  addSubMatrix(GGBar5, GBar16, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GGBar3, GBar16, kk3, nn3, 0, 0, kk5, nn5);
+  addSubMatrix(GGBar5, GBar16, nn5-kk5, nn5, kk5, 0, kk5+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar3, GBar16, nn3-kk3, nn3, kk3, 0, kk5+kk3+nn5-kk5, nn3);
+  appendVector(hh5, hh3, h16, nn5, nn3);
+  Q16 = (QQ3+QQ5);
+  appendVector(DD5, DD3, D16, kk5, kk3);
+  appendBlockMatrix(JJ5, JJ3, J16, kk5, kk5, kk3, kk3);
+  
+  // phiprime * e6
+  int n17 = nn3+nn6; int k17 = kk3+kk6; int **G17; int **GBar17; int *h17; int Q17; int *D17; int **J17;
+  G17 = calloc(nn3+nn6,sizeof(int*));
+  GBar17 = calloc(nn3+nn6,sizeof(int*));
+  h17 = calloc(nn3+nn6,sizeof(int));
+  D17 = calloc(kk3+kk6,sizeof(int));
+  J17 = calloc(kk3+kk6,sizeof(int*));
+  for(i=0; i<nn3+nn6; i++) {
+    G17[i] = calloc(nn3+nn6, sizeof(int)); GBar17[i] = calloc(nn3+nn6, sizeof(int));
+  }
+  for(i=0; i<kk3+kk6; i++)
+     J17[i] = calloc(kk3+kk6, sizeof(int));
+  //appendBlockMatrix(GG6, GG3, G20, nn6, nn6, nn3, nn3);
+  addSubMatrix(GG6, G17, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GG3, G17, kk3, nn3, 0, 0, kk6, nn6);
+  addSubMatrix(GG6, G17, nn6-kk6, nn6, kk6, 0, kk6+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG3, G17, nn3-kk3, nn3, kk3, 0, kk6+kk3+nn6-kk6, nn3);
+  //appendBlockMatrix(GGBar6, GGBar3, GBar20, nn6, nn6, nn3, nn3);
+  addSubMatrix(GGBar6, GBar17, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GGBar3, GBar17, kk3, nn3, 0, 0, kk6, nn6);
+  addSubMatrix(GGBar6, GBar17, nn6-kk6, nn6, kk6, 0, kk6+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar3, GBar17, nn3-kk3, nn3, kk3, 0, kk6+kk3+nn6-kk6, nn3);
+  appendVector(hh6, hh3, h17, nn6, nn3);
+  Q17 = (QQ3+QQ6);
+  appendVector(DD6, DD3, D17, kk6, kk3);
+  appendBlockMatrix(JJ6, JJ3, J17, kk6, kk6, kk3, kk3);
+
+  // phidprime * e6
+  int n18 = nn3+nn7; int k18 = kk3+kk7; int **G18; int **GBar18; int *h18; int Q18; int *D18; int **J18;
+  G18 = calloc(nn3+nn7,sizeof(int*));
+  GBar18 = calloc(nn3+nn7,sizeof(int*));
+  h18 = calloc(nn3+nn7,sizeof(int));
+  D18 = calloc(kk3+kk7,sizeof(int));
+  J18 = calloc(kk3+kk7,sizeof(int*));
+  for(i=0; i<nn3+nn7; i++) {
+    G18[i] = calloc(nn3+nn7, sizeof(int)); GBar18[i] = calloc(nn3+nn7, sizeof(int));
+  }
+  for(i=0; i<kk3+kk7; i++)
+     J18[i] = calloc(kk3+kk7, sizeof(int));
+  //appendBlockMatrix(GG7, GG3, G21, nn7, nn7, nn3, nn3);
+  addSubMatrix(GG7, G18, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GG3, G18, kk3, nn3, 0, 0, kk7, nn7);
+  addSubMatrix(GG7, G18, nn7-kk7, nn7, kk7, 0, kk7+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG3, G18, nn3-kk3, nn3, kk3, 0, kk7+kk3+nn7-kk7, nn3);
+  //appendBlockMatrix(GGBar7, GGBar3, GBar21, nn7, nn7, nn3, nn3);
+  addSubMatrix(GGBar7, GBar18, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GGBar3, GBar18, kk3, nn3, 0, 0, kk7, nn7);
+  addSubMatrix(GGBar7, GBar18, nn7-kk7, nn7, kk7, 0, kk7+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar3, GBar18, nn3-kk3, nn3, kk3, 0, kk7+kk3+nn7-kk7, nn3);
+  appendVector(hh7, hh3, h18, nn7, nn3);
+  Q18 = (QQ3+QQ7);
+  appendVector(DD7, DD3, D18, kk7, kk3);
+  appendBlockMatrix(JJ7, JJ3, J18, kk7, kk7, kk3, kk3);
+
+  // b60 * o6
+  int n19 = nn4+nn1; int k19 = kk4+kk1; int **G19; int **GBar19; int *h19; int Q19; int *D19; int **J19;
+  G19 = calloc(nn4+nn1,sizeof(int*));
+  GBar19 = calloc(nn4+nn1,sizeof(int*));
+  h19 = calloc(nn4+nn1,sizeof(int));
+  D19 = calloc(kk4+kk1,sizeof(int));
+  J19 = calloc(kk4+kk1,sizeof(int*));
+  for(i=0; i<nn4+nn1; i++) {
+    G19[i] = calloc(nn4+nn1, sizeof(int)); GBar19[i] = calloc(nn4+nn1, sizeof(int));
+  }
+  for(i=0; i<kk4+kk1; i++)
+     J19[i] = calloc(kk4+kk1, sizeof(int));
+  //appendBlockMatrix(GG1, GG4, G22, nn1, nn1, nn4, nn4);
+  addSubMatrix(GG1, G19, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GG4, G19, kk4, nn4, 0, 0, kk1, nn1);
+  addSubMatrix(GG1, G19, nn1-kk1, nn1, kk1, 0, kk1+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG4, G19, nn4-kk4, nn4, kk4, 0, kk1+kk4+nn1-kk1, nn4);
+  //appendBlockMatrix(GGBar1, GGBar4, GBar22, nn1, nn1, nn4, nn4);
+  addSubMatrix(GGBar1, GBar19, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GGBar4, GBar19, kk4, nn4, 0, 0, kk1, nn1);
+  addSubMatrix(GGBar1, GBar19, nn1-kk1, nn1, kk1, 0, kk1+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar4, GBar19, nn4-kk4, nn4, kk4, 0, kk1+kk4+nn1-kk1, nn4);
+  appendVector(hh1, hh4, h19, nn1, nn4);
+  Q19 = (QQ4+QQ1);
+  appendVector(DD1, DD4, D19, kk1, kk4);
+  appendBlockMatrix(JJ1, JJ4, J19, kk1, kk1, kk4, kk4);
+
+  // b66 * o6
+  int n20 = nn4+nn2; int k20 = kk4+kk2; int **G20; int **GBar20; int *h20; int Q20; int *D20; int **J20;
+  G20 = calloc(nn4+nn2,sizeof(int*));
+  GBar20 = calloc(nn4+nn2,sizeof(int*));
+  h20 = calloc(nn4+nn2,sizeof(int));
+  D20 = calloc(kk4+kk2,sizeof(int));
+  J20 = calloc(kk4+kk2,sizeof(int*));
+  for(i=0; i<nn4+nn2; i++) {
+    G20[i] = calloc(nn4+nn2, sizeof(int)); GBar20[i] = calloc(nn4+nn2, sizeof(int));
+  }
+  for(i=0; i<kk4+kk2; i++)
+     J20[i] = calloc(kk4+kk2, sizeof(int));
+  //appendBlockMatrix(GG2, GG4, G23, nn2, nn2, nn4, nn4);
+  addSubMatrix(GG2, G20, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GG4, G20, kk4, nn4, 0, 0, kk2, nn2);
+  addSubMatrix(GG2, G20, nn2-kk2, nn2, kk2, 0, kk2+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG4, G20, nn4-kk4, nn4, kk4, 0, kk2+kk4+nn2-kk2, nn4);
+  //appendBlockMatrix(GGBar2, GGBar4, GBar23, nn2, nn2, nn4, nn4);
+  addSubMatrix(GGBar2, GBar20, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GGBar4, GBar20, kk4, nn4, 0, 0, kk2, nn2);
+  addSubMatrix(GGBar2, GBar20, nn2-kk2, nn2, kk2, 0, kk2+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar4, GBar20, nn4-kk4, nn4, kk4, 0, kk2+kk4+nn2-kk2, nn4);
+  appendVector(hh2, hh4, h20, nn2, nn4);
+  Q20 = (QQ4+QQ2);
+  appendVector(DD2, DD4, D20, kk2, kk4);
+  appendBlockMatrix(JJ2, JJ4, J20, kk2, kk2, kk4, kk4);
+  
+  // e6 * o6
+  /*int n24 = nn4+nn3; int k24 = kk4+kk3; int **G24; int **GBar24; int *h24; int Q24; int *D24; int **J24;
+  G24 = calloc(nn4+nn3,sizeof(int*));
+  GBar24 = calloc(nn4+nn3,sizeof(int*));
+  h24 = calloc(nn4+nn3,sizeof(int));
+  D24 = calloc(kk4+kk3,sizeof(int));
+  J24 = calloc(kk4+kk3,sizeof(int*));
+  for(i=0; i<nn4+nn3; i++) {
+    G24[i] = calloc(nn4+nn3, sizeof(int)); GBar24[i] = calloc(nn4+nn3, sizeof(int));
+  }
+  for(i=0; i<kk4+kk3; i++)
+     J24[i] = calloc(kk4+kk3, sizeof(int));
+  //appendBlockMatrix(GG3, GG4, G24, nn3, nn3, nn4, nn4);
+  addSubMatrix(GG3, G24, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GG4, G24, kk4, nn4, 0, 0, kk3, nn3);
+  addSubMatrix(GG3, G24, nn3-kk3, nn3, kk3, 0, kk3+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG4, G24, nn4-kk4, nn4, kk4, 0, kk3+kk4+nn3-kk3, nn4);
+  //appendBlockMatrix(GGBar3, GGBar4, GBar24, nn3, nn3, nn4, nn4);
+  addSubMatrix(GGBar3, GBar24, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GGBar4, GBar24, kk4, nn4, 0, 0, kk3, nn3);
+  addSubMatrix(GGBar3, GBar24, nn3-kk3, nn3, kk3, 0, kk3+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar4, GBar24, nn4-kk4, nn4, kk4, 0, kk3+kk4+nn3-kk3, nn4);
+  appendVector(hh3, hh4, h24, nn3, nn4);
+  Q24 = (QQ4+QQ3);
+  appendVector(DD3, DD4, D24, kk3, kk4);
+  appendBlockMatrix(JJ3, JJ4, J24, kk3, kk3, kk4, kk4);*/
+
+  // o6 * o6
+  int n21 = nn4+nn4; int k21 = kk4+kk4; int **G21; int **GBar21; int *h21; int Q21; int *D21; int **J21;
+  G21 = calloc(nn4+nn4,sizeof(int*));
+  GBar21 = calloc(nn4+nn4,sizeof(int*));
+  h21 = calloc(nn4+nn4,sizeof(int));
+  D21 = calloc(kk4+kk4,sizeof(int));
+  J21 = calloc(kk4+kk4,sizeof(int*));
+  for(i=0; i<nn4+nn4; i++) {
+    G21[i] = calloc(nn4+nn4, sizeof(int)); GBar21[i] = calloc(nn4+nn4, sizeof(int));
+  }
+  for(i=0; i<kk4+kk4; i++)
+     J21[i] = calloc(kk4+kk4, sizeof(int));
+  //appendBlockMatrix(GG4, GG4, G25, nn4, nn4, nn4, nn4);
+  addSubMatrix(GG4, G21, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GG4, G21, kk4, nn4, 0, 0, kk4, nn4);
+  addSubMatrix(GG4, G21, nn4-kk4, nn4, kk4, 0, kk4+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG4, G21, nn4-kk4, nn4, kk4, 0, kk4+kk4+nn4-kk4, nn4);
+  //appendBlockMatrix(GGBar4, GGBar4, GBar25, nn4, nn4, nn4, nn4);
+  addSubMatrix(GGBar4, GBar21, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GGBar4, GBar21, kk4, nn4, 0, 0, kk4, nn4);
+  addSubMatrix(GGBar4, GBar21, nn4-kk4, nn4, kk4, 0, kk4+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar4, GBar21, nn4-kk4, nn4, kk4, 0, kk4+kk4+nn4-kk4, nn4);
+  appendVector(hh4, hh4, h21, nn4, nn4);
+  Q21 = (QQ4+QQ4);
+  appendVector(DD4, DD4, D21, kk4, kk4);
+  appendBlockMatrix(JJ4, JJ4, J21, kk4, kk4, kk4, kk4);
+
+  // k6 * o6
+  int n22 = nn4+nn5; int k22 = kk4+kk5; int **G22; int **GBar22; int *h22; int Q22; int *D22; int **J22;
+  G22 = calloc(nn4+nn5,sizeof(int*));
+  GBar22 = calloc(nn4+nn5,sizeof(int*));
+  h22 = calloc(nn4+nn5,sizeof(int));
+  D22 = calloc(kk4+kk5,sizeof(int));
+  J22 = calloc(kk4+kk5,sizeof(int*));
+  for(i=0; i<nn4+nn5; i++) {
+    G22[i] = calloc(nn4+nn5, sizeof(int)); GBar22[i] = calloc(nn4+nn5, sizeof(int));
+  }
+  for(i=0; i<kk4+kk5; i++)
+     J22[i] = calloc(kk4+kk5, sizeof(int));
+  //appendBlockMatrix(GG5, GG4, G26, nn5, nn5, nn4, nn4);
+  addSubMatrix(GG5, G22, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GG4, G22, kk4, nn4, 0, 0, kk5, nn5);
+  addSubMatrix(GG5, G22, nn5-kk5, nn5, kk5, 0, kk5+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG4, G22, nn4-kk4, nn4, kk4, 0, kk5+kk4+nn5-kk5, nn4);
+  //appendBlockMatrix(GGBar5, GGBar4, GBar26, nn5, nn5, nn4, nn4);
+  addSubMatrix(GGBar5, GBar22, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GGBar4, GBar22, kk4, nn4, 0, 0, kk5, nn5);
+  addSubMatrix(GGBar5, GBar22, nn5-kk5, nn5, kk5, 0, kk5+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar4, GBar22, nn4-kk4, nn4, kk4, 0, kk5+kk4+nn5-kk5, nn4);
+  appendVector(hh5, hh4, h22, nn5, nn4);
+  Q22 = (QQ4+QQ5);
+  appendVector(DD5, DD4, D22, kk5, kk4);
+  appendBlockMatrix(JJ5, JJ4, J22, kk5, kk5, kk4, kk4);
+  
+  // phiprime * o6
+  int n23 = nn4+nn6; int k23 = kk4+kk6; int **G23; int **GBar23; int *h23; int Q23; int *D23; int **J23;
+  G23 = calloc(nn4+nn6,sizeof(int*));
+  GBar23 = calloc(nn4+nn6,sizeof(int*));
+  h23 = calloc(nn4+nn6,sizeof(int));
+  D23 = calloc(kk4+kk6,sizeof(int));
+  J23 = calloc(kk4+kk6,sizeof(int*));
+  for(i=0; i<nn4+nn6; i++) {
+    G23[i] = calloc(nn4+nn6, sizeof(int)); GBar23[i] = calloc(nn4+nn6, sizeof(int));
+  }
+  for(i=0; i<kk4+kk6; i++)
+     J23[i] = calloc(kk4+kk6, sizeof(int));
+  //appendBlockMatrix(GG6, GG4, G27, nn6, nn6, nn4, nn4);
+  addSubMatrix(GG6, G23, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GG4, G23, kk4, nn4, 0, 0, kk6, nn6);
+  addSubMatrix(GG6, G23, nn6-kk6, nn6, kk6, 0, kk6+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG4, G23, nn4-kk4, nn4, kk4, 0, kk6+kk4+nn6-kk6, nn4);
+  //appendBlockMatrix(GGBar6, GGBar4, GBar27, nn6, nn6, nn4, nn4);
+  addSubMatrix(GGBar6, GBar23, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GGBar4, GBar23, kk4, nn4, 0, 0, kk6, nn6);
+  addSubMatrix(GGBar6, GBar23, nn6-kk6, nn6, kk6, 0, kk6+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar4, GBar23, nn4-kk4, nn4, kk4, 0, kk6+kk4+nn6-kk6, nn4);
+  appendVector(hh6, hh4, h23, nn6, nn4);
+  Q23 = (QQ4+QQ6);
+  appendVector(DD6, DD4, D23, kk6, kk4);
+  appendBlockMatrix(JJ6, JJ4, J23, kk6, kk6, kk4, kk4);
+
+  // phidprime * o6
+  int n24 = nn4+nn7; int k24 = kk4+kk7; int **G24; int **GBar24; int *h24; int Q24; int *D24; int **J24;
+  G24 = calloc(nn4+nn7,sizeof(int*));
+  GBar24 = calloc(nn4+nn7,sizeof(int*));
+  h24 = calloc(nn4+nn7,sizeof(int));
+  D24 = calloc(kk4+kk7,sizeof(int));
+  J24 = calloc(kk4+kk7,sizeof(int*));
+  for(i=0; i<nn4+nn7; i++) {
+    G24[i] = calloc(nn4+nn7, sizeof(int)); GBar24[i] = calloc(nn4+nn7, sizeof(int));
+  }
+  for(i=0; i<kk4+kk7; i++)
+     J24[i] = calloc(kk4+kk7, sizeof(int));
+  //appendBlockMatrix(GG7, GG4, G28, nn7, nn7, nn4, nn4);
+  addSubMatrix(GG7, G24, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GG4, G24, kk4, nn4, 0, 0, kk7, nn7);
+  addSubMatrix(GG7, G24, nn7-kk7, nn7, kk7, 0, kk7+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG4, G24, nn4-kk4, nn4, kk4, 0, kk7+kk4+nn7-kk7, nn4);
+  //appendBlockMatrix(GGBar7, GGBar4, GBar28, nn7, nn7, nn4, nn4);
+  addSubMatrix(GGBar7, GBar24, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GGBar4, GBar24, kk4, nn4, 0, 0, kk7, nn7);
+  addSubMatrix(GGBar7, GBar24, nn7-kk7, nn7, kk7, 0, kk7+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar4, GBar24, nn4-kk4, nn4, kk4, 0, kk7+kk4+nn7-kk7, nn4);
+  appendVector(hh7, hh4, h24, nn7, nn4);
+  Q24 = (QQ4+QQ7);
+  appendVector(DD7, DD4, D24, kk7, kk4);
+  appendBlockMatrix(JJ7, JJ4, J24, kk7, kk7, kk4, kk4);
+
+  // b60 * k6
+  int n25 = nn5+nn1; int k25 = kk5+kk1; int **G25; int **GBar25; int *h25; int Q25; int *D25; int **J25;
+  G25 = calloc(nn5+nn1,sizeof(int*));
+  GBar25 = calloc(nn5+nn1,sizeof(int*));
+  h25 = calloc(nn5+nn1,sizeof(int));
+  D25 = calloc(kk5+kk1,sizeof(int));
+  J25 = calloc(kk5+kk1,sizeof(int*));
+  for(i=0; i<nn5+nn1; i++) {
+    G25[i] = calloc(nn5+nn1, sizeof(int)); GBar25[i] = calloc(nn5+nn1, sizeof(int));
+  }
+  for(i=0; i<kk5+kk1; i++)
+     J25[i] = calloc(kk5+kk1, sizeof(int));
+  //appendBlockMatrix(GG1, GG5, G29, nn1, nn1, nn5, nn5);
+  addSubMatrix(GG1, G25, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GG5, G25, kk5, nn5, 0, 0, kk1, nn1);
+  addSubMatrix(GG1, G25, nn1-kk1, nn1, kk1, 0, kk1+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG5, G25, nn5-kk5, nn5, kk5, 0, kk1+kk5+nn1-kk1, nn5);
+  //appendBlockMatrix(GGBar1, GGBar5, GBar29, nn1, nn1, nn5, nn5);
+  addSubMatrix(GGBar1, GBar25, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GGBar5, GBar25, kk5, nn5, 0, 0, kk1, nn1);
+  addSubMatrix(GGBar1, GBar25, nn1-kk1, nn1, kk1, 0, kk1+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar5, GBar25, nn5-kk5, nn5, kk5, 0, kk1+kk5+nn1-kk1, nn5);
+  appendVector(hh1, hh5, h25, nn1, nn5);
+  Q25 = (QQ5+QQ1);
+  appendVector(DD1, DD5, D25, kk1, kk5);
+  appendBlockMatrix(JJ1, JJ5, J25, kk1, kk1, kk5, kk5);
+
+  // b66 * k6
+  int n26 = nn5+nn2; int k26 = kk5+kk2; int **G26; int **GBar26; int *h26; int Q26; int *D26; int **J26;
+  G26 = calloc(nn5+nn2,sizeof(int*));
+  GBar26 = calloc(nn5+nn2,sizeof(int*));
+  h26 = calloc(nn5+nn2,sizeof(int));
+  D26 = calloc(kk5+kk2,sizeof(int));
+  J26 = calloc(kk5+kk2,sizeof(int*));
+  for(i=0; i<nn5+nn2; i++) {
+    G26[i] = calloc(nn5+nn2, sizeof(int)); GBar26[i] = calloc(nn5+nn2, sizeof(int));
+  }
+  for(i=0; i<kk5+kk2; i++)
+     J26[i] = calloc(kk5+kk2, sizeof(int));
+  //appendBlockMatrix(GG2, GG5, G30, nn2, nn2, nn5, nn5);
+  addSubMatrix(GG2, G26, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GG5, G26, kk5, nn5, 0, 0, kk2, nn2);
+  addSubMatrix(GG2, G26, nn2-kk2, nn2, kk2, 0, kk2+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG5, G26, nn5-kk5, nn5, kk5, 0, kk2+kk5+nn2-kk2, nn5);
+  //appendBlockMatrix(GGBar2, GGBar5, GBar30, nn2, nn2, nn5, nn5);
+  addSubMatrix(GGBar2, GBar26, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GGBar5, GBar26, kk5, nn5, 0, 0, kk2, nn2);
+  addSubMatrix(GGBar2, GBar26, nn2-kk2, nn2, kk2, 0, kk2+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar5, GBar26, nn5-kk5, nn5, kk5, 0, kk2+kk5+nn2-kk2, nn5);
+  appendVector(hh2, hh5, h26, nn2, nn5);
+  Q26 = (QQ5+QQ2);
+  appendVector(DD2, DD5, D26, kk2, kk5);
+  appendBlockMatrix(JJ2, JJ5, J26, kk2, kk2, kk5, kk5);
+  
+  // e6 * k6
+  int n27 = nn5+nn3; int k27 = kk5+kk3; int **G27; int **GBar27; int *h27; int Q27; int *D27; int **J27;
+  G27 = calloc(nn5+nn3,sizeof(int*));
+  GBar27 = calloc(nn5+nn3,sizeof(int*));
+  h27 = calloc(nn5+nn3,sizeof(int));
+  D27 = calloc(kk5+kk3,sizeof(int));
+  J27 = calloc(kk5+kk3,sizeof(int*));
+  for(i=0; i<nn5+nn3; i++) {
+    G27[i] = calloc(nn5+nn3, sizeof(int)); GBar27[i] = calloc(nn5+nn3, sizeof(int));
+  }
+  for(i=0; i<kk5+kk3; i++)
+     J27[i] = calloc(kk5+kk3, sizeof(int));
+  //appendBlockMatrix(GG3, GG5, G31, nn3, nn3, nn5, nn5);
+  addSubMatrix(GG3, G27, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GG5, G27, kk5, nn5, 0, 0, kk3, nn3);
+  addSubMatrix(GG3, G27, nn3-kk3, nn3, kk3, 0, kk3+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG5, G27, nn5-kk5, nn5, kk5, 0, kk3+kk5+nn3-kk3, nn5);
+  //appendBlockMatrix(GGBar3, GGBar5, GBar31, nn3, nn3, nn5, nn5);
+  addSubMatrix(GGBar3, GBar27, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GGBar5, GBar27, kk5, nn5, 0, 0, kk3, nn3);
+  addSubMatrix(GGBar3, GBar27, nn3-kk3, nn3, kk3, 0, kk3+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar5, GBar27, nn5-kk5, nn5, kk5, 0, kk3+kk5+nn3-kk3, nn5);
+  appendVector(hh3, hh5, h27, nn3, nn5);
+  Q27 = (QQ5+QQ3);
+  appendVector(DD3, DD5, D27, kk3, kk5);
+  appendBlockMatrix(JJ3, JJ5, J27, kk3, kk3, kk5, kk5);
+
+  // o6 * k6
+  int n28 = nn5+nn4; int k28 = kk5+kk4; int **G28; int **GBar28; int *h28; int Q28; int *D28; int **J28;
+  G28 = calloc(nn5+nn4,sizeof(int*));
+  GBar28 = calloc(nn5+nn4,sizeof(int*));
+  h28 = calloc(nn5+nn4,sizeof(int));
+  D28 = calloc(kk5+kk4,sizeof(int));
+  J28 = calloc(kk5+kk4,sizeof(int*));
+  for(i=0; i<nn5+nn4; i++) {
+    G28[i] = calloc(nn5+nn4, sizeof(int)); GBar28[i] = calloc(nn5+nn4, sizeof(int));
+  }
+  for(i=0; i<kk5+kk4; i++)
+     J28[i] = calloc(kk5+kk4, sizeof(int));
+  //appendBlockMatrix(GG4, GG5, G32, nn4, nn4, nn5, nn5);
+  addSubMatrix(GG4, G28, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GG5, G28, kk5, nn5, 0, 0, kk4, nn4);
+  addSubMatrix(GG4, G28, nn4-kk4, nn4, kk4, 0, kk4+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG5, G28, nn5-kk5, nn5, kk5, 0, kk4+kk5+nn4-kk4, nn5);
+  //appendBlockMatrix(GGBar4, GGBar5, GBar32, nn4, nn4, nn5, nn5);
+  addSubMatrix(GGBar4, GBar28, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GGBar5, GBar28, kk5, nn5, 0, 0, kk4, nn4);
+  addSubMatrix(GGBar4, GBar28, nn4-kk4, nn4, kk4, 0, kk4+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar5, GBar28, nn5-kk5, nn5, kk5, 0, kk4+kk5+nn4-kk4, nn5);
+  appendVector(hh4, hh5, h28, nn4, nn5);
+  Q28 = (QQ5+QQ4);
+  appendVector(DD4, DD5, D28, kk4, kk5);
+  appendBlockMatrix(JJ4, JJ5, J28, kk4, kk4, kk5, kk5);
+
+  // k6 * k6
+  int n29 = nn5+nn5; int k29 = kk5+kk5; int **G29; int **GBar29; int *h29; int Q29; int *D29; int **J29;
+  G29 = calloc(nn5+nn5,sizeof(int*));
+  GBar29 = calloc(nn5+nn5,sizeof(int*));
+  h29 = calloc(nn5+nn5,sizeof(int));
+  D29 = calloc(kk5+kk5,sizeof(int));
+  J29 = calloc(kk5+kk5,sizeof(int*));
+  for(i=0; i<nn5+nn5; i++) {
+    G29[i] = calloc(nn5+nn5, sizeof(int)); GBar29[i] = calloc(nn5+nn5, sizeof(int));
+  }
+  for(i=0; i<kk5+kk5; i++)
+     J29[i] = calloc(kk5+kk5, sizeof(int));
+  //appendBlockMatrix(GG5, GG5, G33, nn5, nn5, nn5, nn5);
+  addSubMatrix(GG5, G29, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GG5, G29, kk5, nn5, 0, 0, kk5, nn5);
+  addSubMatrix(GG5, G29, nn5-kk5, nn5, kk5, 0, kk5+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG5, G29, nn5-kk5, nn5, kk5, 0, kk5+kk5+nn5-kk5, nn5);
+  //appendBlockMatrix(GGBar5, GGBar5, GBar33, nn5, nn5, nn5, nn5);
+  addSubMatrix(GGBar5, GBar29, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GGBar5, GBar29, kk5, nn5, 0, 0, kk5, nn5);
+  addSubMatrix(GGBar5, GBar29, nn5-kk5, nn5, kk5, 0, kk5+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar5, GBar29, nn5-kk5, nn5, kk5, 0, kk5+kk5+nn5-kk5, nn5);
+  appendVector(hh5, hh5, h29, nn5, nn5);
+  Q29 = (QQ5+QQ5);
+  appendVector(DD5, DD5, D29, kk5, kk5);
+  appendBlockMatrix(JJ5, JJ5, J29, kk5, kk5, kk5, kk5);
+
+  // phiprime * k6
+  int n30 = nn5+nn6; int k30 = kk5+kk6; int **G30; int **GBar30; int *h30; int Q30; int *D30; int **J30;
+  G30 = calloc(nn5+nn6,sizeof(int*));
+  GBar30 = calloc(nn5+nn6,sizeof(int*));
+  h30 = calloc(nn5+nn6,sizeof(int));
+  D30 = calloc(kk5+kk6,sizeof(int));
+  J30 = calloc(kk5+kk6,sizeof(int*));
+  for(i=0; i<nn5+nn6; i++) {
+    G30[i] = calloc(nn5+nn6, sizeof(int)); GBar30[i] = calloc(nn5+nn6, sizeof(int));
+  }
+  for(i=0; i<kk5+kk6; i++)
+     J30[i] = calloc(kk5+kk6, sizeof(int));
+  //appendBlockMatrix(GG6, GG5, G34, nn6, nn6, nn5, nn5);
+  addSubMatrix(GG6, G30, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GG5, G30, kk5, nn5, 0, 0, kk6, nn6);
+  addSubMatrix(GG6, G30, nn6-kk6, nn6, kk6, 0, kk6+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG5, G30, nn5-kk5, nn5, kk5, 0, kk6+kk5+nn6-kk6, nn5);
+  //appendBlockMatrix(GGBar6, GGBar5, GBar34, nn6, nn6, nn5, nn5);
+  addSubMatrix(GGBar6, GBar30, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GGBar5, GBar30, kk5, nn5, 0, 0, kk6, nn6);
+  addSubMatrix(GGBar6, GBar30, nn6-kk6, nn6, kk6, 0, kk6+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar5, GBar30, nn5-kk5, nn5, kk5, 0, kk6+kk5+nn6-kk6, nn5);
+  appendVector(hh6, hh5, h30, nn6, nn5);
+  Q30 = (QQ5+QQ6);
+  appendVector(DD6, DD5, D30, kk6, kk5);
+  appendBlockMatrix(JJ6, JJ5, J30, kk6, kk6, kk5, kk5);
+  
+  // phidprime * k6
+  int n31 = nn5+nn7; int k31 = kk5+kk7; int **G31; int **GBar31; int *h31; int Q31; int *D31; int **J31;
+  G31 = calloc(nn5+nn7,sizeof(int*));
+  GBar31 = calloc(nn5+nn7,sizeof(int*));
+  h31 = calloc(nn5+nn7,sizeof(int));
+  D31 = calloc(kk5+kk7,sizeof(int));
+  J31 = calloc(kk5+kk7,sizeof(int*));
+  for(i=0; i<nn5+nn7; i++) {
+    G31[i] = calloc(nn5+nn7, sizeof(int)); GBar31[i] = calloc(nn5+nn7, sizeof(int));
+  }
+  for(i=0; i<kk5+kk7; i++)
+     J31[i] = calloc(kk5+kk7, sizeof(int));
+  //appendBlockMatrix(GG7, GG5, G35, nn7, nn7, nn5, nn5);
+  addSubMatrix(GG7, G31, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GG5, G31, kk5, nn5, 0, 0, kk7, nn7);
+  addSubMatrix(GG7, G31, nn7-kk7, nn7, kk7, 0, kk7+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG5, G31, nn5-kk5, nn5, kk5, 0, kk7+kk5+nn7-kk7, nn5);
+  //appendBlockMatrix(GGBar7, GGBar5, GBar35, nn7, nn7, nn5, nn5);
+  addSubMatrix(GGBar7, GBar31, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GGBar5, GBar31, kk5, nn5, 0, 0, kk7, nn7);
+  addSubMatrix(GGBar7, GBar31, nn7-kk7, nn7, kk7, 0, kk7+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar5, GBar31, nn5-kk5, nn5, kk5, 0, kk7+kk5+nn7-kk7, nn5);
+  appendVector(hh7, hh5, h31, nn7, nn5);
+  Q31 = (QQ5+QQ7);
+  appendVector(DD7, DD5, D31, kk7, kk5);
+  appendBlockMatrix(JJ7, JJ5, J31, kk7, kk7, kk5, kk5);
+
+  // b60 * phiprime
+  int n32 = nn6+nn1; int k32 = kk6+kk1; int **G32; int **GBar32; int *h32; int Q32; int *D32; int **J32;
+  G32 = calloc(nn6+nn1,sizeof(int*));
+  GBar32 = calloc(nn6+nn1,sizeof(int*));
+  h32 = calloc(nn6+nn1,sizeof(int));
+  D32 = calloc(kk6+kk1,sizeof(int));
+  J32 = calloc(kk6+kk1,sizeof(int*));
+  for(i=0; i<nn6+nn1; i++) {
+    G32[i] = calloc(nn6+nn1, sizeof(int)); GBar32[i] = calloc(nn6+nn1, sizeof(int));
+  }
+  for(i=0; i<kk6+kk1; i++)
+     J32[i] = calloc(kk6+kk1, sizeof(int));
+  //appendBlockMatrix(GG1, GG6, G36, nn1, nn1, nn6, nn6);
+  addSubMatrix(GG1, G32, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GG6, G32, kk6, nn6, 0, 0, kk1, nn1);
+  addSubMatrix(GG1, G32, nn1-kk1, nn1, kk1, 0, kk1+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG6, G32, nn6-kk6, nn6, kk6, 0, kk1+kk6+nn1-kk1, nn6);
+  //appendBlockMatrix(GGBar1, GGBar6, GBar36, nn1, nn1, nn6, nn6);
+  addSubMatrix(GGBar1, GBar32, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GGBar6, GBar32, kk6, nn6, 0, 0, kk1, nn1);
+  addSubMatrix(GGBar1, GBar32, nn1-kk1, nn1, kk1, 0, kk1+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar6, GBar32, nn6-kk6, nn6, kk6, 0, kk1+kk6+nn1-kk1, nn6);
+  appendVector(hh1, hh6, h32, nn1, nn6);
+  Q32 = (QQ6+QQ1);
+  appendVector(DD1, DD6, D32, kk1, kk6);
+  appendBlockMatrix(JJ1, JJ6, J32, kk1, kk1, kk6, kk6);
+
+  // b66 * phiprime
+  int n33 = nn6+nn2; int k33 = kk6+kk2; int **G33; int **GBar33; int *h33; int Q33; int *D33; int **J33;
+  G33 = calloc(nn6+nn2,sizeof(int*));
+  GBar33 = calloc(nn6+nn2,sizeof(int*));
+  h33 = calloc(nn6+nn2,sizeof(int));
+  D33 = calloc(kk6+kk2,sizeof(int));
+  J33 = calloc(kk6+kk2,sizeof(int*));
+  for(i=0; i<nn6+nn2; i++) {
+    G33[i] = calloc(nn6+nn2, sizeof(int)); GBar33[i] = calloc(nn6+nn2, sizeof(int));
+  }
+  for(i=0; i<kk6+kk2; i++)
+     J33[i] = calloc(kk6+kk2, sizeof(int));
+  //appendBlockMatrix(GG2, GG6, G37, nn2, nn2, nn6, nn6);
+  addSubMatrix(GG2, G33, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GG6, G33, kk6, nn6, 0, 0, kk2, nn2);
+  addSubMatrix(GG2, G33, nn2-kk2, nn2, kk2, 0, kk2+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG6, G33, nn6-kk6, nn6, kk6, 0, kk2+kk6+nn2-kk2, nn6);
+  //appendBlockMatrix(GGBar2, GGBar6, GBar37, nn2, nn2, nn6, nn6);
+  addSubMatrix(GGBar2, GBar33, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GGBar6, GBar33, kk6, nn6, 0, 0, kk2, nn2);
+  addSubMatrix(GGBar2, GBar33, nn2-kk2, nn2, kk2, 0, kk2+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar6, GBar33, nn6-kk6, nn6, kk6, 0, kk2+kk6+nn2-kk2, nn6);
+  appendVector(hh2, hh6, h33, nn2, nn6);
+  Q33 = (QQ6+QQ2);
+  appendVector(DD2, DD6, D33, kk2, kk6);
+  appendBlockMatrix(JJ2, JJ6, J33, kk2, kk2, kk6, kk6);
+
+  // e6 * phiprime
+  int n34 = nn6+nn3; int k34 = kk6+kk3; int **G34; int **GBar34; int *h34; int Q34; int *D34; int **J34;
+  G34 = calloc(nn6+nn3,sizeof(int*));
+  GBar34 = calloc(nn6+nn3,sizeof(int*));
+  h34 = calloc(nn6+nn3,sizeof(int));
+  D34 = calloc(kk6+kk3,sizeof(int));
+  J34 = calloc(kk6+kk3,sizeof(int*));
+  for(i=0; i<nn6+nn3; i++) {
+    G34[i] = calloc(nn6+nn3, sizeof(int)); GBar34[i] = calloc(nn6+nn3, sizeof(int));
+  }
+  for(i=0; i<kk6+kk3; i++)
+     J34[i] = calloc(kk6+kk3, sizeof(int));
+  //appendBlockMatrix(GG3, GG6, G38, nn3, nn3, nn6, nn6);
+  addSubMatrix(GG3, G34, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GG6, G34, kk6, nn6, 0, 0, kk3, nn3);
+  addSubMatrix(GG3, G34, nn3-kk3, nn3, kk3, 0, kk3+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG6, G34, nn6-kk6, nn6, kk6, 0, kk3+kk6+nn3-kk3, nn6);
+  //appendBlockMatrix(GGBar3, GGBar6, GBar38, nn3, nn3, nn6, nn6);
+  addSubMatrix(GGBar3, GBar34, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GGBar6, GBar34, kk6, nn6, 0, 0, kk3, nn3);
+  addSubMatrix(GGBar3, GBar34, nn3-kk3, nn3, kk3, 0, kk3+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar6, GBar34, nn6-kk6, nn6, kk6, 0, kk3+kk6+nn3-kk3, nn6);
+  appendVector(hh3, hh6, h34, nn3, nn6);
+  Q34 = (QQ6+QQ3);
+  appendVector(DD3, DD6, D34, kk3, kk6);
+  appendBlockMatrix(JJ3, JJ6, J34, kk3, kk3, kk6, kk6);
+
+  // o6 * phiprime
+  int n35 = nn6+nn4; int k35 = kk6+kk4; int **G35; int **GBar35; int *h35; int Q35; int *D35; int **J35;
+  G35 = calloc(nn6+nn4,sizeof(int*));
+  GBar35 = calloc(nn6+nn4,sizeof(int*));
+  h35 = calloc(nn6+nn4,sizeof(int));
+  D35 = calloc(kk6+kk4,sizeof(int));
+  J35 = calloc(kk6+kk4,sizeof(int*));
+  for(i=0; i<nn6+nn4; i++) {
+    G35[i] = calloc(nn6+nn4, sizeof(int)); GBar35[i] = calloc(nn6+nn4, sizeof(int));
+  }
+  for(i=0; i<kk6+kk4; i++)
+     J35[i] = calloc(kk6+kk4, sizeof(int));
+  //appendBlockMatrix(GG4, GG6, G39, nn4, nn4, nn6, nn6);
+  addSubMatrix(GG4, G35, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GG6, G35, kk6, nn6, 0, 0, kk4, nn4);
+  addSubMatrix(GG4, G35, nn4-kk4, nn4, kk4, 0, kk4+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG6, G35, nn6-kk6, nn6, kk6, 0, kk4+kk6+nn4-kk4, nn6);
+  //appendBlockMatrix(GGBar4, GGBar6, GBar39, nn4, nn4, nn6, nn6);
+  addSubMatrix(GGBar4, GBar35, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GGBar6, GBar35, kk6, nn6, 0, 0, kk4, nn4);
+  addSubMatrix(GGBar4, GBar35, nn4-kk4, nn4, kk4, 0, kk4+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar6, GBar35, nn6-kk6, nn6, kk6, 0, kk4+kk6+nn4-kk4, nn6);
+  appendVector(hh4, hh6, h35, nn4, nn6);
+  Q35 = (QQ6+QQ4);
+  appendVector(DD4, DD6, D35, kk4, kk6);
+  appendBlockMatrix(JJ4, JJ6, J35, kk4, kk4, kk6, kk6);
+
+  // k6 * phiprime
+  int n36 = nn6+nn5; int k36 = kk6+kk5; int **G36; int **GBar36; int *h36; int Q36; int *D36; int **J36;
+  G36 = calloc(nn6+nn5,sizeof(int*));
+  GBar36 = calloc(nn6+nn5,sizeof(int*));
+  h36 = calloc(nn6+nn5,sizeof(int));
+  D36 = calloc(kk6+kk5,sizeof(int));
+  J36 = calloc(kk6+kk5,sizeof(int*));
+  for(i=0; i<nn6+nn5; i++) {
+    G36[i] = calloc(nn6+nn5, sizeof(int)); GBar36[i] = calloc(nn6+nn5, sizeof(int));
+  }
+  for(i=0; i<kk6+kk5; i++)
+     J36[i] = calloc(kk6+kk5, sizeof(int));
+  //appendBlockMatrix(GG5, GG6, G40, nn5, nn5, nn6, nn6);
+  addSubMatrix(GG5, G36, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GG6, G36, kk6, nn6, 0, 0, kk5, nn5);
+  addSubMatrix(GG5, G36, nn5-kk5, nn5, kk5, 0, kk5+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG6, G36, nn6-kk6, nn6, kk6, 0, kk5+kk6+nn5-kk5, nn6);
+  //appendBlockMatrix(GGBar5, GGBar6, GBar40, nn5, nn5, nn6, nn6);
+  addSubMatrix(GGBar5, GBar36, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GGBar6, GBar36, kk6, nn6, 0, 0, kk5, nn5);
+  addSubMatrix(GGBar5, GBar36, nn5-kk5, nn5, kk5, 0, kk5+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar6, GBar36, nn6-kk6, nn6, kk6, 0, kk5+kk6+nn5-kk5, nn6);
+  appendVector(hh5, hh6, h36, nn5, nn6);
+  Q36 = (QQ6+QQ5);
+  appendVector(DD5, DD6, D36, kk5, kk6);
+  appendBlockMatrix(JJ5, JJ6, J36, kk5, kk5, kk6, kk6);
+
+  // phiprime * phiprime
+  int n37 = nn6+nn6; int k37 = kk6+kk6; int **G37; int **GBar37; int *h37; int Q37; int *D37; int **J37;
+  G37 = calloc(nn6+nn6,sizeof(int*));
+  GBar37 = calloc(nn6+nn6,sizeof(int*));
+  h37 = calloc(nn6+nn6,sizeof(int));
+  D37 = calloc(kk6+kk6,sizeof(int));
+  J37 = calloc(kk6+kk6,sizeof(int*));
+  for(i=0; i<nn6+nn6; i++) {
+    G37[i] = calloc(nn6+nn6, sizeof(int)); GBar37[i] = calloc(nn6+nn6, sizeof(int));
+  }
+  for(i=0; i<kk6+kk6; i++)
+     J37[i] = calloc(kk6+kk6, sizeof(int));
+  //appendBlockMatrix(GG6, GG6, G41, nn6, nn6, nn6, nn6);
+  addSubMatrix(GG6, G37, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GG6, G37, kk6, nn6, 0, 0, kk6, nn6);
+  addSubMatrix(GG6, G37, nn6-kk6, nn6, kk6, 0, kk6+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG6, G37, nn6-kk6, nn6, kk6, 0, kk6+kk6+nn6-kk6, nn6);
+  //appendBlockMatrix(GGBar6, GGBar6, GBar41, nn6, nn6, nn6, nn6);
+  addSubMatrix(GGBar6, GBar37, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GGBar6, GBar37, kk6, nn6, 0, 0, kk6, nn6);
+  addSubMatrix(GGBar6, GBar37, nn6-kk6, nn6, kk6, 0, kk6+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar6, GBar37, nn6-kk6, nn6, kk6, 0, kk6+kk6+nn6-kk6, nn6);
+  appendVector(hh6, hh6, h37, nn6, nn6);
+  Q37 = (QQ6+QQ6);
+  appendVector(DD6, DD6, D37, kk6, kk6);
+  appendBlockMatrix(JJ6, JJ6, J37, kk6, kk6, kk6, kk6);
+
+  // phidprime * phiprime
+  int n38 = nn6+nn7; int k38 = kk6+kk7; int **G38; int **GBar38; int *h38; int Q38; int *D38; int **J38;
+  G38 = calloc(nn6+nn7,sizeof(int*));
+  GBar38 = calloc(nn6+nn7,sizeof(int*));
+  h38 = calloc(nn6+nn7,sizeof(int));
+  D38 = calloc(kk6+kk7,sizeof(int));
+  J38 = calloc(kk6+kk7,sizeof(int*));
+  for(i=0; i<nn6+nn7; i++) {
+    G38[i] = calloc(nn6+nn7, sizeof(int)); GBar38[i] = calloc(nn6+nn7, sizeof(int));
+  }
+  for(i=0; i<kk6+kk7; i++)
+     J38[i] = calloc(kk6+kk7, sizeof(int));
+  //appendBlockMatrix(GG7, GG6, G42, nn7, nn7, nn6, nn6);
+  addSubMatrix(GG7, G38, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GG6, G38, kk6, nn6, 0, 0, kk7, nn7);
+  addSubMatrix(GG7, G38, nn7-kk7, nn7, kk7, 0, kk7+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG6, G38, nn6-kk6, nn6, kk6, 0, kk7+kk6+nn7-kk7, nn6);
+  //appendBlockMatrix(GGBar7, GGBar6, GBar42, nn7, nn7, nn6, nn6);
+  addSubMatrix(GGBar7, GBar38, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GGBar6, GBar38, kk6, nn6, 0, 0, kk7, nn7);
+  addSubMatrix(GGBar7, GBar38, nn7-kk7, nn7, kk7, 0, kk7+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar6, GBar38, nn6-kk6, nn6, kk6, 0, kk7+kk6+nn7-kk7, nn6);
+  appendVector(hh7, hh6, h38, nn7, nn6);
+  Q38 = (QQ6+QQ7);
+  appendVector(DD7, DD6, D38, kk7, kk6);
+  appendBlockMatrix(JJ7, JJ6, J38, kk7, kk7, kk6, kk6);
+
+  // b60 * phidprime
+  int n39 = nn7+nn1; int k39 = kk7+kk1; int **G39; int **GBar39; int *h39; int Q39; int *D39; int **J39;
+  G39 = calloc(nn7+nn1,sizeof(int*));
+  GBar39 = calloc(nn7+nn1,sizeof(int*));
+  h39 = calloc(nn7+nn1,sizeof(int));
+  D39 = calloc(kk7+kk1,sizeof(int));
+  J39 = calloc(kk7+kk1,sizeof(int*));
+  for(i=0; i<nn7+nn1; i++) {
+    G39[i] = calloc(nn7+nn1, sizeof(int)); GBar39[i] = calloc(nn7+nn1, sizeof(int));
+  }
+  for(i=0; i<kk7+kk1; i++)
+     J39[i] = calloc(kk7+kk1, sizeof(int));
+  //appendBlockMatrix(GG1, GG7, G43, nn1, nn1, nn7, nn7);
+  addSubMatrix(GG1, G39, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GG7, G39, kk7, nn7, 0, 0, kk1, nn1);
+  addSubMatrix(GG1, G39, nn1-kk1, nn1, kk1, 0, kk1+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG7, G39, nn7-kk7, nn7, kk7, 0, kk1+kk7+nn1-kk1, nn7);
+  //appendBlockMatrix(GGBar1, GGBar7, GBar43, nn1, nn1, nn7, nn7);
+  addSubMatrix(GGBar1, GBar39, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GGBar7, GBar39, kk7, nn7, 0, 0, kk1, nn1);
+  addSubMatrix(GGBar1, GBar39, nn1-kk1, nn1, kk1, 0, kk1+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar7, GBar39, nn7-kk7, nn7, kk7, 0, kk1+kk7+nn1-kk1, nn7);
+  appendVector(hh1, hh7, h39, nn1, nn7);
+  Q39 = (QQ7+QQ1);
+  appendVector(DD1, DD7, D39, kk1, kk7);
+  appendBlockMatrix(JJ1, JJ7, J39, kk1, kk1, kk7, kk7);
+  
+  // b66 * phidprime
+  int n40 = nn7+nn2; int k40 = kk7+kk2; int **G40; int **GBar40; int *h40; int Q40; int *D40; int **J40;
+  G40 = calloc(nn7+nn2,sizeof(int*));
+  GBar40 = calloc(nn7+nn2,sizeof(int*));
+  h40 = calloc(nn7+nn2,sizeof(int));
+  D40 = calloc(kk7+kk2,sizeof(int));
+  J40 = calloc(kk7+kk2,sizeof(int*));
+  for(i=0; i<nn7+nn2; i++) {
+    G40[i] = calloc(nn7+nn2, sizeof(int)); GBar40[i] = calloc(nn7+nn2, sizeof(int));
+  }
+  for(i=0; i<kk7+kk2; i++)
+     J40[i] = calloc(kk7+kk2, sizeof(int));
+  //appendBlockMatrix(GG2, GG7, G44, nn2, nn2, nn7, nn7);
+  addSubMatrix(GG2, G40, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GG7, G40, kk7, nn7, 0, 0, kk2, nn2);
+  addSubMatrix(GG1, G40, nn2-kk2, nn2, kk2, 0, kk2+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG7, G40, nn7-kk7, nn7, kk7, 0, kk2+kk7+nn2-kk2, nn7);
+  //appendBlockMatrix(GGBar2, GGBar7, GBar44, nn2, nn2, nn7, nn7);
+  addSubMatrix(GGBar2, GBar40, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GGBar7, GBar40, kk7, nn7, 0, 0, kk2, nn2);
+  addSubMatrix(GGBar1, GBar40, nn2-kk2, nn2, kk2, 0, kk2+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar7, GBar40, nn7-kk7, nn7, kk7, 0, kk2+kk7+nn2-kk2, nn7);
+  appendVector(hh2, hh7, h40, nn2, nn7);
+  Q40 = (QQ7+QQ2);
+  appendVector(DD2, DD7, D40, kk2, kk7);
+  appendBlockMatrix(JJ2, JJ7, J40, kk2, kk2, kk7, kk7);
+  
+  // e6 * phidprime
+  int n41 = nn7+nn3; int k41 = kk7+kk3; int **G41; int **GBar41; int *h41; int Q41; int *D41; int **J41;
+  G41 = calloc(nn7+nn3,sizeof(int*));
+  GBar41 = calloc(nn7+nn3,sizeof(int*));
+  h41 = calloc(nn7+nn3,sizeof(int));
+  D41 = calloc(kk7+kk3,sizeof(int));
+  J41 = calloc(kk7+kk3,sizeof(int*));
+  for(i=0; i<nn7+nn3; i++) {
+    G41[i] = calloc(nn7+nn3, sizeof(int)); GBar41[i] = calloc(nn7+nn3, sizeof(int));
+  }
+  for(i=0; i<kk7+kk3; i++)
+     J41[i] = calloc(kk7+kk3, sizeof(int));
+  //appendBlockMatrix(GG3, GG7, G45, nn3, nn3, nn7, nn7);
+  addSubMatrix(GG3, G41, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GG7, G41, kk7, nn7, 0, 0, kk3, nn3);
+  addSubMatrix(GG3, G41, nn3-kk3, nn3, kk3, 0, kk3+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG7, G41, nn7-kk7, nn7, kk7, 0, kk3+kk7+nn3-kk3, nn7);
+  //appendBlockMatrix(GGBar3, GGBar7, GBar45, nn3, nn3, nn7, nn7);
+  addSubMatrix(GGBar3, GBar41, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GGBar7, GBar41, kk7, nn7, 0, 0, kk3, nn3);
+  addSubMatrix(GGBar3, GBar41, nn3-kk3, nn3, kk3, 0, kk3+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar7, GBar41, nn7-kk7, nn7, kk7, 0, kk3+kk7+nn3-kk3, nn7);
+  appendVector(hh3, hh7, h41, nn3, nn7);
+  Q41 = (QQ7+QQ3);
+  appendVector(DD3, DD7, D41, kk3, kk7);
+  appendBlockMatrix(JJ3, JJ7, J41, kk3, kk3, kk7, kk7);
+
+  // o6 * phidprime
+  int n42 = nn7+nn4; int k42 = kk7+kk4; int **G42; int **GBar42; int *h42; int Q42; int *D42; int **J42;
+  G42 = calloc(nn7+nn4,sizeof(int*));
+  GBar42 = calloc(nn7+nn4,sizeof(int*));
+  h42 = calloc(nn7+nn4,sizeof(int));
+  D42 = calloc(kk7+kk4,sizeof(int));
+  J42 = calloc(kk7+kk4,sizeof(int*));
+  for(i=0; i<nn7+nn4; i++) {
+    G42[i] = calloc(nn7+nn4, sizeof(int)); GBar42[i] = calloc(nn7+nn4, sizeof(int));
+  }
+  for(i=0; i<kk7+kk4; i++)
+     J42[i] = calloc(kk7+kk4, sizeof(int));
+  //appendBlockMatrix(GG4, GG7, G46, nn4, nn4, nn7, nn7);
+  addSubMatrix(GG4, G42, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GG7, G42, kk7, nn7, 0, 0, kk4, nn4);
+  addSubMatrix(GG4, G42, nn4-kk4, nn4, kk4, 0, kk4+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG7, G42, nn7-kk7, nn7, kk7, 0, kk4+kk7+nn4-kk4, nn7);
+  //appendBlockMatrix(GGBar4, GGBar7, GBar46, nn4, nn4, nn7, nn7);
+  addSubMatrix(GGBar4, GBar42, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GGBar7, GBar42, kk7, nn7, 0, 0, kk4, nn4);
+  addSubMatrix(GGBar4, GBar42, nn4-kk4, nn4, kk4, 0, kk4+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar7, GBar42, nn7-kk7, nn7, kk7, 0, kk4+kk7+nn4-kk4, nn7);
+  appendVector(hh4, hh7, h42, nn4, nn7);
+  Q42 = (QQ7+QQ4);
+  appendVector(DD4, DD7, D42, kk4, kk7);
+  appendBlockMatrix(JJ4, JJ7, J42, kk4, kk4, kk7, kk7);
+
+  // k6 * phidprime
+  int n43 = nn7+nn5; int k43 = kk7+kk5; int **G43; int **GBar43; int *h43; int Q43; int *D43; int **J43;
+  G43 = calloc(nn7+nn5,sizeof(int*));
+  GBar43 = calloc(nn7+nn5,sizeof(int*));
+  h43 = calloc(nn7+nn5,sizeof(int));
+  D43 = calloc(kk7+kk5,sizeof(int));
+  J43 = calloc(kk7+kk5,sizeof(int*));
+  for(i=0; i<nn7+nn5; i++) {
+    G43[i] = calloc(nn7+nn5, sizeof(int)); GBar43[i] = calloc(nn7+nn5, sizeof(int));
+  }
+  for(i=0; i<kk7+kk5; i++)
+     J43[i] = calloc(kk7+kk5, sizeof(int));
+  //appendBlockMatrix(GG5, GG7, G47, nn5, nn5, nn7, nn7);
+  addSubMatrix(GG5, G43, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GG7, G43, kk7, nn7, 0, 0, kk5, nn5);
+  addSubMatrix(GG5, G43, nn5-kk5, nn5, kk5, 0, kk5+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG7, G43, nn7-kk7, nn7, kk7, 0, kk5+kk7+nn5-kk5, nn7);
+  //appendBlockMatrix(GGBar5, GGBar7, GBar47, nn5, nn5, nn7, nn7);
+  addSubMatrix(GGBar5, GBar43, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GGBar7, GBar43, kk7, nn7, 0, 0, kk5, nn5);
+  addSubMatrix(GGBar5, GBar43, nn5-kk5, nn5, kk5, 0, kk5+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar7, GBar43, nn7-kk7, nn7, kk7, 0, kk5+kk7+nn5-kk5, nn7);
+  appendVector(hh5, hh7, h43, nn5, nn7);
+  Q43 = (QQ7+QQ5);
+  appendVector(DD5, DD7, D43, kk5, kk7);
+  appendBlockMatrix(JJ5, JJ7, J43, kk5, kk5, kk7, kk7);
+
+  // phiprime * phidprime
+  int n44 = nn7+nn6; int k44 = kk7+kk6; int **G44; int **GBar44; int *h44; int Q44; int *D44; int **J44;
+  G44 = calloc(nn7+nn6,sizeof(int*));
+  GBar44 = calloc(nn7+nn6,sizeof(int*));
+  h44 = calloc(nn7+nn6,sizeof(int));
+  D44 = calloc(kk7+kk6,sizeof(int));
+  J44 = calloc(kk7+kk6,sizeof(int*));
+  for(i=0; i<nn7+nn6; i++) {
+    G44[i] = calloc(nn7+nn6, sizeof(int)); GBar44[i] = calloc(nn7+nn6, sizeof(int));
+  }
+  for(i=0; i<kk7+kk6; i++)
+     J44[i] = calloc(kk7+kk6, sizeof(int));
+  //appendBlockMatrix(GG6, GG7, G48, nn6, nn6, nn7, nn7);
+  addSubMatrix(GG6, G44, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GG7, G44, kk7, nn7, 0, 0, kk6, nn6);
+  addSubMatrix(GG6, G44, nn6-kk6, nn6, kk6, 0, kk6+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG7, G44, nn7-kk7, nn7, kk7, 0, kk6+kk7+nn6-kk6, nn7);
+  //appendBlockMatrix(GGBar6, GGBar7, GBar48, nn6, nn6, nn7, nn7);
+  addSubMatrix(GGBar6, GBar44, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GGBar7, GBar44, kk7, nn7, 0, 0, kk6, nn6);
+  addSubMatrix(GGBar6, GBar44, nn6-kk6, nn6, kk6, 0, kk6+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar7, GBar44, nn7-kk7, nn7, kk7, 0, kk6+kk7+nn6-kk6, nn7);
+  appendVector(hh6, hh7, h44, nn6, nn7);
+  Q44 = (QQ7+QQ6);
+  appendVector(DD6, DD7, D44, kk6, kk7);
+  appendBlockMatrix(JJ6, JJ7, J44, kk6, kk6, kk7, kk7);
+
+  // phidprime * phidprime
+  int n45 = nn7+nn7; int k45 = kk7+kk7; int **G45; int **GBar45; int *h45; int Q45; int *D45; int **J45;
+  G45 = calloc(nn7+nn7,sizeof(int*));
+  GBar45 = calloc(nn7+nn7,sizeof(int*));
+  h45 = calloc(nn7+nn7,sizeof(int));
+  D45 = calloc(kk7+kk7,sizeof(int));
+  J45 = calloc(kk7+kk7,sizeof(int*));
+  for(i=0; i<nn7+nn7; i++) {
+    G45[i] = calloc(nn7+nn7, sizeof(int)); GBar45[i] = calloc(nn7+nn7, sizeof(int));
+  }
+  for(i=0; i<kk7+kk7; i++)
+     J45[i] = calloc(kk7+kk7, sizeof(int));
+  //appendBlockMatrix(GG7, GG7, G49, nn7, nn7, nn7, nn7);
+  addSubMatrix(GG7, G45, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GG7, G45, kk7, nn7, 0, 0, kk7, nn7);
+  addSubMatrix(GG7, G45, nn7-kk7, nn7, kk7, 0, kk7+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG7, G45, nn7-kk7, nn7, kk7, 0, kk7+kk7+nn7-kk7, nn7);
+  //appendBlockMatrix(GGBar7, GGBar7, GBar49, nn7, nn7, nn7, nn7);
+  addSubMatrix(GGBar7, GBar45, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GGBar7, GBar45, kk7, nn7, 0, 0, kk7, nn7);
+  addSubMatrix(GGBar7, GBar45, nn7-kk7, nn7, kk7, 0, kk7+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar7, GBar45, nn7-kk7, nn7, kk7, 0, kk7+kk7+nn7-kk7, nn7);
+  appendVector(hh7, hh7, h45, nn7, nn7);
+  Q45 = (QQ7+QQ7);
+  appendVector(DD7, DD7, D45, kk7, kk7);
+  appendBlockMatrix(JJ7, JJ7, J45, kk7, kk7, kk7, kk7);
+
+  // b60 * b66 + b66 * b60
+  int n46 = 12; int k46 = 11;
+  int (*(G46[])) = { (int[]) {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+  int (*(GBar46[])) = { (int[]) {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}};
+  int h46[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  int Q46 = 4;
+  int D46[] = {0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4};
+  int (*(J46[])) = { (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+
+  // e6 * o6 + e6 * o6
+  int n47 = 12; int k47 = 11;
+  int (*(G47[])) = { (int[]) {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+  int (*(GBar47[])) = { (int[]) {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}};
+  int h47[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  int Q47 = 0;
+  int D47[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  int (*(J47[])) = { (int[]) {0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, (int[]) {4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4}, (int[]) {4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 4}, (int[]) {4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4}, (int[]) {4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4}, (int[]) {4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4}, (int[]) {4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4}, (int[]) {4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4}, (int[]) {4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4}, (int[]) {4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4}, (int[]) {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0}};
+  
+
+  
+  int *K; int ***G; int ***GBar; int **h; int *Q; int **D; int ***J;
+  double complex Gamma[(int)pow(47,N/12)]; // prefactor in front of resultant state
+  G = calloc(pow(47,N/12),sizeof(int*)); GBar = calloc(pow(47,N/12),sizeof(int*));
+  h = calloc(pow(47,N/12),sizeof(int*));
+  
+  J = calloc(pow(47,N/12),sizeof(int*)); D = calloc(pow(47,N/12),sizeof(int*)); Q = calloc(pow(47,N/12),sizeof(int));
+
+  K = calloc(pow(47,N/12), sizeof(int));
+
+  double complex origGamma[(int)pow(47,N/12)];
+  int *origK, *origQ, **origD;
+  int ***origJ;
+  int ***origG, ***origGBar;
+  int **origh;
+
+  origG = calloc(pow(47,N/12),sizeof(int*)); origGBar = calloc(pow(47,N/12),sizeof(int*));
+  origh = calloc(pow(47,N/12),sizeof(int*));
+  
+  origJ = calloc(pow(47,N/12),sizeof(int*)); origD = calloc(pow(47,N/12),sizeof(int*)); origQ = calloc(pow(47,N/12),sizeof(int));
+
+  origK = calloc(pow(47,N/12), sizeof(int));
+
+  int combination; // a particular combination from the linear combo of stabilizer states making up the tensor factors multiplied together
+  
+
+  for(j=0; j<pow(47,N/12); j++) { // there will be 47^(N/12) combinations when using k=12 tensor factors
+
+    combination = j;
+
+    K[j] = 0.0;
+    
+    for(k=0; k<N/12; k++) {
+      K[j] += (((combination%47)==46)*k47 + ((combination%47)==45)*k46 + ((combination%47)==44)*k45 + ((combination%47)==43)*k44 + ((combination%47)==42)*k43 + ((combination%47)==41)*k42 + ((combination%47)==40)*k41 + ((combination%47)==39)*k40 +
+              ((combination%47)==38)*k39 + ((combination%47)==37)*k38 + ((combination%47)==36)*k37 + ((combination%47)==35)*k36 + ((combination%47)==34)*k35 + ((combination%47)==33)*k34 + ((combination%47)==32)*k33 + ((combination%47)==31)*k32 + ((combination%47)==30)*k31 + ((combination%47)==29)*k30 +
+              ((combination%47)==28)*k29 + ((combination%47)==27)*k28 + ((combination%47)==26)*k27 + ((combination%47)==25)*k26 + ((combination%47)==24)*k25 + ((combination%47)==23)*k24 + ((combination%47)==22)*k23 + ((combination%47)==21)*k22 + ((combination%47)==20)*k21 + ((combination%47)==19)*k20 +
+              ((combination%47)==18)*k19 + ((combination%47)==17)*k18 + ((combination%47)==16)*k17 + ((combination%47)==15)*k16 + ((combination%47)==14)*k15 + ((combination%47)==13)*k14 + ((combination%47)==12)*k13 + ((combination%47)==11)*k12 + ((combination%47)==10)*k11 + ((combination%47)==9)*k10 +
+              ((combination%47)==8)*k9 + ((combination%47)==7)*k8 + ((combination%47)==6)*k7 + ((combination%47)==5)*k6 + ((combination%47)==4)*k5 + ((combination%47)==3)*k4 + ((combination%47)==2)*k3 + ((combination%47)==1)*k2 + ((combination%47)==0)*k1);
+      combination /= 47;
+    }
+    combination = j;
+    origK[j] = K[j];
+
+    Gamma[j] = 1.0;
+
+    G[j] = calloc(N, sizeof(int*)); GBar[j] = calloc(N, sizeof(int*));
+    h[j] = calloc(N, sizeof(int));
+
+    if(K[j] > 0) {
+      J[j] = calloc(K[j], sizeof(int*)); D[j] = calloc(K[j], sizeof(int));
+      for(k=0; k<K[j]; k++)
+       J[j][k] = calloc(K[j], sizeof(int));
+    }
+
+    origG[j] = calloc(N, sizeof(int*)); origGBar[j] = calloc(N, sizeof(int*));
+    origh[j] = calloc(N, sizeof(int));
+
+    if(K[j] > 0) {
+      origJ[j] = calloc(K[j], sizeof(int*)); origD[j] = calloc(K[j], sizeof(int));
+      for(k=0; k<K[j]; k++)
+       origJ[j][k] = calloc(K[j], sizeof(int));
+    }
+
+    for(k=0; k<N; k++) {
+      G[j][k] = calloc(N, sizeof(int)); GBar[j][k] = calloc(N, sizeof(int));
+      origG[j][k] = calloc(N, sizeof(int)); origGBar[j][k] = calloc(N, sizeof(int));
+    }
+
+    int Kcounter = 0; // Kcounter keeps track of the K<=N that we have added already to the G rows etc. for each combination that is indexed by the digits (base 3) of 'j' in that we go through with 'k'
+    int Kcombo; // Kcombo stores the k<(n1=n2=n3) dimension of the member of the combination that we are currently adding
+    for(k=0; k<N/12; k++) {
+
+      Q[j] += (((combination%47)==46)*Q47 + ((combination%47)==45)*Q46 + ((combination%47)==44)*Q45 + ((combination%47)==43)*Q44 + ((combination%47)==42)*Q43 + ((combination%47)==41)*Q42 + ((combination%47)==40)*Q41 + ((combination%47)==39)*Q40 +
+              ((combination%47)==38)*Q39 + ((combination%47)==37)*Q38 + ((combination%47)==36)*Q37 + ((combination%47)==35)*Q36 + ((combination%47)==34)*Q35 + ((combination%47)==33)*Q34 + ((combination%47)==32)*Q33 + ((combination%47)==31)*Q32 + ((combination%47)==30)*Q31 + ((combination%47)==29)*Q30 +
+              ((combination%47)==28)*Q29 + ((combination%47)==27)*Q28 + ((combination%47)==26)*Q27 + ((combination%47)==25)*Q26 + ((combination%47)==24)*Q25 + ((combination%47)==23)*Q24 + ((combination%47)==22)*Q23 + ((combination%47)==21)*Q22 + ((combination%47)==20)*Q21 + ((combination%47)==19)*Q20 +
+              ((combination%47)==18)*Q19 + ((combination%47)==17)*Q18 + ((combination%47)==16)*Q17 + ((combination%47)==15)*Q16 + ((combination%47)==14)*Q15 + ((combination%47)==13)*Q14 + ((combination%47)==12)*Q13 + ((combination%47)==11)*Q12 + ((combination%47)==10)*Q11 + ((combination%47)==9)*Q10 +
+              ((combination%47)==8)*Q9 + ((combination%47)==7)*Q8 + ((combination%47)==6)*Q7 + ((combination%47)==5)*Q6 + ((combination%47)==4)*Q5 + ((combination%47)==3)*Q4 + ((combination%47)==2)*Q3 + ((combination%47)==1)*Q2 + ((combination%47)==0)*Q1);
+      
+
+      Gamma[j] *= (((combination%47)==46)*coeffe6*coeffo6*sqrt(2.0) + ((combination%47)==45)*coeffb60*coeffb66*sqrt(2.0) + ((combination%47)==44)*coeffphidprime*coeffphidprime + ((combination%47)==43)*coeffphiprime*coeffphidprime + ((combination%47)==42)*coeffk6*coeffphidprime + ((combination%47)==41)*coeffo6*coeffphidprime + ((combination%47)==40)*coeffe6*coeffphidprime + ((combination%47)==39)*coeffb66*coeffphidprime + ((combination%47)==38)*coeffb60*coeffphidprime
+                  + ((combination%47)==37)*coeffphidprime*coeffphiprime + ((combination%47)==36)*coeffphiprime*coeffphiprime + ((combination%47)==35)*coeffk6*coeffphiprime + ((combination%47)==34)*coeffo6*coeffphiprime + ((combination%47)==33)*coeffe6*coeffphiprime + ((combination%47)==32)*coeffb66*coeffphiprime + ((combination%47)==31)*coeffb60*coeffphiprime
+                  + ((combination%47)==30)*coeffphidprime*coeffk6 + ((combination%47)==29)*coeffphiprime*coeffk6 + ((combination%47)==28)*coeffk6*coeffk6 + ((combination%47)==27)*coeffo6*coeffk6 + ((combination%47)==26)*coeffe6*coeffk6 + ((combination%47)==25)*coeffb66*coeffk6 + ((combination%47)==24)*coeffb60*coeffk6
+                  + ((combination%47)==23)*coeffphidprime*coeffo6 + ((combination%47)==22)*coeffphiprime*coeffo6 + ((combination%47)==21)*coeffk6*coeffo6 + ((combination%47)==20)*coeffo6*coeffo6  + ((combination%47)==19)*coeffb66*coeffo6 + ((combination%47)==18)*coeffb60*coeffo6
+                  + ((combination%47)==17)*coeffphidprime*coeffe6 + ((combination%47)==16)*coeffphiprime*coeffe6 + ((combination%47)==15)*coeffk6*coeffe6 + ((combination%47)==14)*coeffe6*coeffe6 + ((combination%47)==13)*coeffb66*coeffe6 + ((combination%47)==12)*coeffb60*coeffe6
+                  + ((combination%47)==11)*coeffphidprime*coeffb66 + ((combination%47)==10)*coeffphiprime*coeffb66 + ((combination%47)==9)*coeffk6*coeffb66 + ((combination%47)==8)*coeffo6*coeffb66 + ((combination%47)==7)*coeffe6*coeffb66 + ((combination%47)==6)*coeffb66*coeffb66
+                  + ((combination%47)==5)*coeffphidprime*coeffb60 + ((combination%47)==4)*coeffphiprime*coeffb60 + ((combination%47)==3)*coeffk6*coeffb60 + ((combination%47)==2)*coeffo6*coeffb60 + ((combination%47)==1)*coeffe6*coeffb60 + ((combination%47)==0)*coeffb60*coeffb60);
+
+      Kcombo = (((combination%47)==46)*k47 + ((combination%47)==45)*k46 + ((combination%47)==44)*k45 + ((combination%47)==43)*k44 + ((combination%47)==42)*k43 + ((combination%47)==41)*k42 + ((combination%47)==40)*k41 + ((combination%47)==39)*k40 +
+              ((combination%47)==38)*k39 + ((combination%47)==37)*k38 + ((combination%47)==36)*k37 + ((combination%47)==35)*k36 + ((combination%47)==34)*k35 + ((combination%47)==33)*k34 + ((combination%47)==32)*k33 + ((combination%47)==31)*k32 + ((combination%47)==30)*k31 + ((combination%47)==29)*k30 +
+              ((combination%47)==28)*k29 + ((combination%47)==27)*k28 + ((combination%47)==26)*k27 + ((combination%47)==25)*k26 + ((combination%47)==24)*k25 + ((combination%47)==23)*k24 + ((combination%47)==22)*k23 + ((combination%47)==21)*k22 + ((combination%47)==20)*k21 + ((combination%47)==19)*k20 +
+              ((combination%47)==18)*k19 + ((combination%47)==17)*k18 + ((combination%47)==16)*k17 + ((combination%47)==15)*k16 + ((combination%47)==14)*k15 + ((combination%47)==13)*k14 + ((combination%47)==12)*k13 + ((combination%47)==11)*k12 + ((combination%47)==10)*k11 + ((combination%47)==9)*k10 +
+              ((combination%47)==8)*k9 + ((combination%47)==7)*k8 + ((combination%47)==6)*k7 + ((combination%47)==5)*k6 + ((combination%47)==4)*k5 + ((combination%47)==3)*k4 + ((combination%47)==2)*k3 + ((combination%47)==1)*k2 + ((combination%47)==0)*k1);
+      for(l=0; l<Kcombo; l++) {
+       // D1 has a different number of rows 'l' than D2 and D3 so you need to use something like 'switch' to check combination%3 without going out of bound of J1
+       switch(combination%47) {
+       case 0:
+         D[j][Kcounter+l] = D1[l];
+         break;
+       case 1:
+         D[j][Kcounter+l] = D2[l];
+         break;
+       case 2:
+         D[j][Kcounter+l] = D3[l];
+         break;
+       case 3:
+         D[j][Kcounter+l] = D4[l];
+           break;
+       case 4:
+         D[j][Kcounter+l] = D5[l];
+         break;
+       case 5:
+         D[j][Kcounter+l] = D6[l];
+         break;
+       case 6:
+         D[j][Kcounter+l] = D7[l];
+         break;
+       case 7:
+         D[j][Kcounter+l] = D8[l];
+         break;
+       case 8:
+         D[j][Kcounter+l] = D9[l];
+         break;
+       case 9:
+         D[j][Kcounter+l] = D10[l];
+         break;
+       case 10:
+         D[j][Kcounter+l] = D11[l];
+         break;
+       case 11:
+         D[j][Kcounter+l] = D12[l];
+         break;
+       case 12:
+         D[j][Kcounter+l] = D13[l];
+         break;
+       case 13:
+         D[j][Kcounter+l] = D14[l];
+           break;
+       case 14:
+         D[j][Kcounter+l] = D15[l];
+         break;
+       case 15:
+         D[j][Kcounter+l] = D16[l];
+         break;
+       case 16:
+         D[j][Kcounter+l] = D17[l];
+         break;
+       case 17:
+         D[j][Kcounter+l] = D18[l];
+         break;
+       case 18:
+         D[j][Kcounter+l] = D19[l];
+         break;
+       case 19:
+         D[j][Kcounter+l] = D20[l];
+         break;
+       case 20:
+         D[j][Kcounter+l] = D21[l];
+         break;
+       case 21:
+         D[j][Kcounter+l] = D22[l];
+         break;
+       case 22:
+         D[j][Kcounter+l] = D23[l];
+         break;
+       case 23:
+         D[j][Kcounter+l] = D24[l];
+           break;
+       case 24:
+         D[j][Kcounter+l] = D25[l];
+         break;
+       case 25:
+         D[j][Kcounter+l] = D26[l];
+         break;
+       case 26:
+         D[j][Kcounter+l] = D27[l];
+         break;
+       case 27:
+         D[j][Kcounter+l] = D28[l];
+         break;
+       case 28:
+         D[j][Kcounter+l] = D29[l];
+         break;
+       case 29:
+         D[j][Kcounter+l] = D30[l];
+         break;
+       case 30:
+         D[j][Kcounter+l] = D31[l];
+         break;
+       case 31:
+         D[j][Kcounter+l] = D32[l];
+         break;
+       case 32:
+         D[j][Kcounter+l] = D33[l];
+         break;
+       case 33:
+         D[j][Kcounter+l] = D34[l];
+           break;
+       case 34:
+         D[j][Kcounter+l] = D35[l];
+         break;
+       case 35:
+         D[j][Kcounter+l] = D36[l];
+         break;
+       case 36:
+         D[j][Kcounter+l] = D37[l];
+         break;
+       case 37:
+         D[j][Kcounter+l] = D38[l];
+         break;
+       case 38:
+         D[j][Kcounter+l] = D39[l];
+         break;
+       case 39:
+         D[j][Kcounter+l] = D40[l];
+         break;
+       case 40:
+         D[j][Kcounter+l] = D41[l];
+         break;
+       case 41:
+         D[j][Kcounter+l] = D42[l];
+         break;
+       case 42:
+         D[j][Kcounter+l] = D43[l];
+         break;
+       case 43:
+         D[j][Kcounter+l] = D44[l];
+           break;
+       case 44:
+         D[j][Kcounter+l] = D45[l];
+         break;
+       case 45:
+         D[j][Kcounter+l] = D46[l];
+         break;
+       case 46:
+         D[j][Kcounter+l] = D47[l];
+         break;
+       default:
+         printf("error");
+         return 1;
+         }
+       for(m=0; m<Kcombo; m++) {
+         // J1 has a different number of rows 'l' than J2 and J3 so you need to use something like 'switch' to check combination%3 without going out of bound of J1
+         switch(combination%47) {
+         case 0:
+           J[j][Kcounter+l][Kcounter+m] = J1[l][m];
+           break;
+         case 1:
+           J[j][Kcounter+l][Kcounter+m] = J2[l][m];
+           break;
+         case 2:
+           J[j][Kcounter+l][Kcounter+m] = J3[l][m];
+           break;
+         case 3:
+           J[j][Kcounter+l][Kcounter+m] = J4[l][m];
+           break;
+         case 4:
+           J[j][Kcounter+l][Kcounter+m] = J5[l][m];
+           break;
+         case 5:
+           J[j][Kcounter+l][Kcounter+m] = J6[l][m];
+           break;
+         case 6:
+           J[j][Kcounter+l][Kcounter+m] = J7[l][m];
+           break;
+         case 7:
+           J[j][Kcounter+l][Kcounter+m] = J8[l][m];
+           break;
+         case 8:
+           J[j][Kcounter+l][Kcounter+m] = J9[l][m];
+           break;
+         case 9:
+           J[j][Kcounter+l][Kcounter+m] = J10[l][m];
+           break;
+         case 10:
+           J[j][Kcounter+l][Kcounter+m] = J11[l][m];
+           break;
+         case 11:
+           J[j][Kcounter+l][Kcounter+m] = J12[l][m];
+           break;
+         case 12:
+           J[j][Kcounter+l][Kcounter+m] = J13[l][m];
+           break;
+         case 13:
+           J[j][Kcounter+l][Kcounter+m] = J14[l][m];
+           break;
+         case 14:
+           J[j][Kcounter+l][Kcounter+m] = J15[l][m];
+           break;
+         case 15:
+           J[j][Kcounter+l][Kcounter+m] = J16[l][m];
+           break;
+         case 16:
+           J[j][Kcounter+l][Kcounter+m] = J17[l][m];
+           break;
+         case 17:
+           J[j][Kcounter+l][Kcounter+m] = J18[l][m];
+           break;
+         case 18:
+           J[j][Kcounter+l][Kcounter+m] = J19[l][m];
+           break;
+         case 19:
+           J[j][Kcounter+l][Kcounter+m] = J20[l][m];
+           break;
+         case 20:
+           J[j][Kcounter+l][Kcounter+m] = J21[l][m];
+           break;
+         case 21:
+           J[j][Kcounter+l][Kcounter+m] = J22[l][m];
+           break;
+         case 22:
+           J[j][Kcounter+l][Kcounter+m] = J23[l][m];
+           break;
+         case 23:
+           J[j][Kcounter+l][Kcounter+m] = J24[l][m];
+           break;
+         case 24:
+           J[j][Kcounter+l][Kcounter+m] = J25[l][m];
+           break;
+         case 25:
+           J[j][Kcounter+l][Kcounter+m] = J26[l][m];
+           break;
+         case 26:
+           J[j][Kcounter+l][Kcounter+m] = J27[l][m];
+           break;
+         case 27:
+           J[j][Kcounter+l][Kcounter+m] = J28[l][m];
+           break;
+         case 28:
+           J[j][Kcounter+l][Kcounter+m] = J29[l][m];
+           break;
+         case 29:
+           J[j][Kcounter+l][Kcounter+m] = J30[l][m];
+           break;
+         case 30:
+           J[j][Kcounter+l][Kcounter+m] = J31[l][m];
+           break;
+         case 31:
+           J[j][Kcounter+l][Kcounter+m] = J32[l][m];
+           break;
+         case 32:
+           J[j][Kcounter+l][Kcounter+m] = J33[l][m];
+           break;
+         case 33:
+           J[j][Kcounter+l][Kcounter+m] = J34[l][m];
+           break;
+         case 34:
+           J[j][Kcounter+l][Kcounter+m] = J35[l][m];
+           break;
+         case 35:
+           J[j][Kcounter+l][Kcounter+m] = J36[l][m];
+           break;
+         case 36:
+           J[j][Kcounter+l][Kcounter+m] = J37[l][m];
+           break;
+         case 37:
+           J[j][Kcounter+l][Kcounter+m] = J38[l][m];
+           break;
+         case 38:
+           J[j][Kcounter+l][Kcounter+m] = J39[l][m];
+           break;
+         case 39:
+           J[j][Kcounter+l][Kcounter+m] = J40[l][m];
+           break;
+         case 40:
+           J[j][Kcounter+l][Kcounter+m] = J41[l][m];
+           break;
+         case 41:
+           J[j][Kcounter+l][Kcounter+m] = J42[l][m];
+           break;
+         case 42:
+           J[j][Kcounter+l][Kcounter+m] = J43[l][m];
+           break;
+         case 43:
+           J[j][Kcounter+l][Kcounter+m] = J44[l][m];
+           break;
+         case 44:
+           J[j][Kcounter+l][Kcounter+m] = J45[l][m];
+           break;
+         case 45:
+           J[j][Kcounter+l][Kcounter+m] = J46[l][m];
+           break;
+         case 46:
+           J[j][Kcounter+l][Kcounter+m] = J47[l][m];
+           break;
+         default:
+           printf("error");
+           return 1;
+         }
+       }
+      }
+
+      for(l=0; l<n1; l++) { // assuming n1=n2=n3
+       h[j][k*n1+l] = (((combination%47)==46)*h47[l] + ((combination%47)==45)*h46[l] + ((combination%47)==44)*h45[l] + ((combination%47)==43)*h44[l] + ((combination%47)==42)*h43[l] + ((combination%47)==41)*h42[l] + ((combination%47)==40)*h41[l] + ((combination%47)==39)*h40[l] +
+                       ((combination%47)==38)*h39[l] + ((combination%47)==37)*h38[l] + ((combination%47)==36)*h37[l] + ((combination%47)==35)*h36[l] + ((combination%47)==34)*h35[l] + ((combination%47)==33)*h34[l] + ((combination%47)==32)*h33[l] + ((combination%47)==31)*h32[l] + ((combination%47)==30)*h31[l] + ((combination%47)==29)*h30[l] +
+                       ((combination%47)==28)*h29[l] + ((combination%47)==27)*h28[l] + ((combination%47)==26)*h27[l] + ((combination%47)==25)*h26[l] + ((combination%47)==24)*h25[l] + ((combination%47)==23)*h24[l] + ((combination%47)==22)*h23[l] + ((combination%47)==21)*h22[l] + ((combination%47)==20)*h21[l] + ((combination%47)==19)*h20[l] +
+                       ((combination%47)==18)*h19[l] + ((combination%47)==17)*h18[l] + ((combination%47)==16)*h17[l] + ((combination%47)==15)*h16[l] + ((combination%47)==14)*h15[l] + ((combination%47)==13)*h14[l] + ((combination%47)==12)*h13[l] + ((combination%47)==11)*h12[l] + ((combination%47)==10)*h11[l] + ((combination%47)==9)*h10[l] +
+                       ((combination%47)==8)*h9[l] + ((combination%47)==7)*h8[l] + ((combination%47)==6)*h7[l] + ((combination%47)==5)*h6[l] + ((combination%47)==4)*h5[l] + ((combination%47)==3)*h4[l] + ((combination%47)==2)*h3[l] + ((combination%47)==1)*h2[l] + ((combination%47)==0)*h1[l]);
+      }
+      // only filling the K[j] first rows of G and GBar here corresponding to the basis for D and J
+      for(l=0; l<Kcombo; l++) {
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         G[j][Kcounter+l][k*n1+m] = (((combination%47)==46)*G47[l][m] + ((combination%47)==45)*G46[l][m] + ((combination%47)==44)*G45[l][m] + ((combination%47)==43)*G44[l][m] + ((combination%47)==42)*G43[l][m] + ((combination%47)==41)*G42[l][m] + ((combination%47)==40)*G41[l][m] + ((combination%47)==39)*G40[l][m] +
+                                     ((combination%47)==38)*G39[l][m] + ((combination%47)==37)*G38[l][m] + ((combination%47)==36)*G37[l][m] + ((combination%47)==35)*G36[l][m] + ((combination%47)==34)*G35[l][m] + ((combination%47)==33)*G34[l][m] + ((combination%47)==32)*G33[l][m] + ((combination%47)==31)*G32[l][m] + ((combination%47)==30)*G31[l][m] + ((combination%47)==29)*G30[l][m] +
+                                     ((combination%47)==28)*G29[l][m] + ((combination%47)==27)*G28[l][m] + ((combination%47)==26)*G27[l][m] + ((combination%47)==25)*G26[l][m] + ((combination%47)==24)*G25[l][m] + ((combination%47)==23)*G24[l][m] + ((combination%47)==22)*G23[l][m] + ((combination%47)==21)*G22[l][m] + ((combination%47)==20)*G21[l][m] + ((combination%47)==19)*G20[l][m] +
+                                     ((combination%47)==18)*G19[l][m] + ((combination%47)==17)*G18[l][m] + ((combination%47)==16)*G17[l][m] + ((combination%47)==15)*G16[l][m] + ((combination%47)==14)*G15[l][m] + ((combination%47)==13)*G14[l][m] + ((combination%47)==12)*G13[l][m] + ((combination%47)==11)*G12[l][m] + ((combination%47)==10)*G11[l][m] + ((combination%47)==9)*G10[l][m] +
+                                     ((combination%47)==8)*G9[l][m] + ((combination%47)==7)*G8[l][m] + ((combination%47)==6)*G7[l][m] + ((combination%47)==5)*G6[l][m] + ((combination%47)==4)*G5[l][m] + ((combination%47)==3)*G4[l][m] + ((combination%47)==2)*G3[l][m] + ((combination%47)==1)*G2[l][m] + ((combination%47)==0)*G1[l][m]);
+         GBar[j][Kcounter+l][k*n1+m] = (((combination%47)==46)*GBar47[l][m] + ((combination%47)==45)*GBar46[l][m] + ((combination%47)==44)*GBar45[l][m] + ((combination%47)==43)*GBar44[l][m] + ((combination%47)==42)*GBar43[l][m] + ((combination%47)==41)*GBar42[l][m] + ((combination%47)==40)*GBar41[l][m] + ((combination%47)==39)*GBar40[l][m] +
+                                        ((combination%47)==38)*GBar39[l][m] + ((combination%47)==37)*GBar38[l][m] + ((combination%47)==36)*GBar37[l][m] + ((combination%47)==35)*GBar36[l][m] + ((combination%47)==34)*GBar35[l][m] + ((combination%47)==33)*GBar34[l][m] + ((combination%47)==32)*GBar33[l][m] + ((combination%47)==31)*GBar32[l][m] + ((combination%47)==30)*GBar31[l][m] + ((combination%47)==29)*GBar30[l][m] +
+                                        ((combination%47)==28)*GBar29[l][m] + ((combination%47)==27)*GBar28[l][m] + ((combination%47)==26)*GBar27[l][m] + ((combination%47)==25)*GBar26[l][m] + ((combination%47)==24)*GBar25[l][m] + ((combination%47)==23)*GBar24[l][m] + ((combination%47)==22)*GBar23[l][m] + ((combination%47)==21)*GBar22[l][m] + ((combination%47)==20)*GBar21[l][m] + ((combination%47)==19)*GBar20[l][m] +
+                                        ((combination%47)==18)*GBar19[l][m] + ((combination%47)==17)*GBar18[l][m] + ((combination%47)==16)*GBar17[l][m] + ((combination%47)==15)*GBar16[l][m] + ((combination%47)==14)*GBar15[l][m] + ((combination%47)==13)*GBar14[l][m] + ((combination%47)==12)*GBar13[l][m] + ((combination%47)==11)*GBar12[l][m] + ((combination%47)==10)*GBar11[l][m] + ((combination%47)==9)*GBar10[l][m] +
+                                        ((combination%47)==8)*GBar9[l][m] + ((combination%47)==7)*GBar8[l][m] + ((combination%47)==6)*GBar7[l][m] + ((combination%47)==5)*GBar6[l][m] + ((combination%47)==4)*GBar5[l][m] + ((combination%47)==3)*GBar4[l][m] + ((combination%47)==2)*GBar3[l][m] + ((combination%47)==1)*GBar2[l][m] + ((combination%47)==0)*GBar1[l][m]);
+       }
+      }
+      Kcounter = Kcounter + Kcombo;
+      
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      //memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
+
+      //memcpy(origJ[j][k], J[j][k], K[j]*sizeof(int));
+      
+      combination /= 47; // shift to the right by one (in base-47 arithmetic)
+    }
+    //printf("!\n");
+
+    // now need to fill the N-Kcounter remaining rows of G and GBar that are outside the spanning basis states of D and J
+    combination = j;
+    for(k=0; k<(N/12); k++) {
+      Kcombo = (((combination%47)==46)*k47 + ((combination%47)==45)*k46 + ((combination%47)==44)*k45 + ((combination%47)==43)*k44 + ((combination%47)==42)*k43 + ((combination%47)==41)*k42 + ((combination%47)==40)*k41 + ((combination%47)==39)*k40 +
+              ((combination%47)==38)*k39 + ((combination%47)==37)*k38 + ((combination%47)==36)*k37 + ((combination%47)==35)*k36 + ((combination%47)==34)*k35 + ((combination%47)==33)*k34 + ((combination%47)==32)*k33 + ((combination%47)==31)*k32 + ((combination%47)==30)*k31 + ((combination%47)==29)*k30 +
+              ((combination%47)==28)*k29 + ((combination%47)==27)*k28 + ((combination%47)==26)*k27 + ((combination%47)==25)*k26 + ((combination%47)==24)*k25 + ((combination%47)==23)*k24 + ((combination%47)==22)*k23 + ((combination%47)==21)*k22 + ((combination%47)==20)*k21 + ((combination%47)==19)*k20 +
+              ((combination%47)==18)*k19 + ((combination%47)==17)*k18 + ((combination%47)==16)*k17 + ((combination%47)==15)*k16 + ((combination%47)==14)*k15 + ((combination%47)==13)*k14 + ((combination%47)==12)*k13 + ((combination%47)==11)*k12 + ((combination%47)==10)*k11 + ((combination%47)==9)*k10 +
+              ((combination%47)==8)*k9 + ((combination%47)==7)*k8 + ((combination%47)==6)*k7 + ((combination%47)==5)*k6 + ((combination%47)==4)*k5 + ((combination%47)==3)*k4 + ((combination%47)==2)*k3 + ((combination%47)==1)*k2 + ((combination%47)==0)*k1);
+      //printf("Kcounter=%d\n", Kcounter);
+      // G and GBar rows that are outside the first 'k' spanning basis states
+      for(l=Kcombo; l<n1; l++) { // assuming n1=n2=n3
+       //printf("l=%d\n", l);
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         /* printf("m=%d\n", m); */
+         /* printf("Kcounter+l=%d\n", Kcounter+l); */
+         /* printf("k*n1+m=%d\n", k*n1+m); */
+         G[j][Kcounter+l-Kcombo][k*n1+m] = (((combination%47)==46)*G47[l][m] + ((combination%47)==45)*G46[l][m] + ((combination%47)==44)*G45[l][m] + ((combination%47)==43)*G44[l][m] + ((combination%47)==42)*G43[l][m] + ((combination%47)==41)*G42[l][m] + ((combination%47)==40)*G41[l][m] + ((combination%47)==39)*G40[l][m] +
+                                     ((combination%47)==38)*G39[l][m] + ((combination%47)==37)*G38[l][m] + ((combination%47)==36)*G37[l][m] + ((combination%47)==35)*G36[l][m] + ((combination%47)==34)*G35[l][m] + ((combination%47)==33)*G34[l][m] + ((combination%47)==32)*G33[l][m] + ((combination%47)==31)*G32[l][m] + ((combination%47)==30)*G31[l][m] + ((combination%47)==29)*G30[l][m] +
+                                     ((combination%47)==28)*G29[l][m] + ((combination%47)==27)*G28[l][m] + ((combination%47)==26)*G27[l][m] + ((combination%47)==25)*G26[l][m] + ((combination%47)==24)*G25[l][m] + ((combination%47)==23)*G24[l][m] + ((combination%47)==22)*G23[l][m] + ((combination%47)==21)*G22[l][m] + ((combination%47)==20)*G21[l][m] + ((combination%47)==19)*G20[l][m] +
+                                     ((combination%47)==18)*G19[l][m] + ((combination%47)==17)*G18[l][m] + ((combination%47)==16)*G17[l][m] + ((combination%47)==15)*G16[l][m] + ((combination%47)==14)*G15[l][m] + ((combination%47)==13)*G14[l][m] + ((combination%47)==12)*G13[l][m] + ((combination%47)==11)*G12[l][m] + ((combination%47)==10)*G11[l][m] + ((combination%47)==9)*G10[l][m] +
+                                     ((combination%47)==8)*G9[l][m] + ((combination%47)==7)*G8[l][m] + ((combination%47)==6)*G7[l][m] + ((combination%47)==5)*G6[l][m] + ((combination%47)==4)*G5[l][m] + ((combination%47)==3)*G4[l][m] + ((combination%47)==2)*G3[l][m] + ((combination%47)==1)*G2[l][m] + ((combination%47)==0)*G1[l][m]);
+         GBar[j][Kcounter+l-Kcombo][k*n1+m] = (((combination%47)==46)*GBar47[l][m] + ((combination%47)==45)*GBar46[l][m] + ((combination%47)==44)*GBar45[l][m] + ((combination%47)==43)*GBar44[l][m] + ((combination%47)==42)*GBar43[l][m] + ((combination%47)==41)*GBar42[l][m] + ((combination%47)==40)*GBar41[l][m] + ((combination%47)==39)*GBar40[l][m] +
+                                        ((combination%47)==38)*GBar39[l][m] + ((combination%47)==37)*GBar38[l][m] + ((combination%47)==36)*GBar37[l][m] + ((combination%47)==35)*GBar36[l][m] + ((combination%47)==34)*GBar35[l][m] + ((combination%47)==33)*GBar34[l][m] + ((combination%47)==32)*GBar33[l][m] + ((combination%47)==31)*GBar32[l][m] + ((combination%47)==30)*GBar31[l][m] + ((combination%47)==29)*GBar30[l][m] +
+                                        ((combination%47)==28)*GBar29[l][m] + ((combination%47)==27)*GBar28[l][m] + ((combination%47)==26)*GBar27[l][m] + ((combination%47)==25)*GBar26[l][m] + ((combination%47)==24)*GBar25[l][m] + ((combination%47)==23)*GBar24[l][m] + ((combination%47)==22)*GBar23[l][m] + ((combination%47)==21)*GBar22[l][m] + ((combination%47)==20)*GBar21[l][m] + ((combination%47)==19)*GBar20[l][m] +
+                                        ((combination%47)==18)*GBar19[l][m] + ((combination%47)==17)*GBar18[l][m] + ((combination%47)==16)*GBar17[l][m] + ((combination%47)==15)*GBar16[l][m] + ((combination%47)==14)*GBar15[l][m] + ((combination%47)==13)*GBar14[l][m] + ((combination%47)==12)*GBar13[l][m] + ((combination%47)==11)*GBar12[l][m] + ((combination%47)==10)*GBar11[l][m] + ((combination%47)==9)*GBar10[l][m] +
+                                        ((combination%47)==8)*GBar9[l][m] + ((combination%47)==7)*GBar8[l][m] + ((combination%47)==6)*GBar7[l][m] + ((combination%47)==5)*GBar6[l][m] + ((combination%47)==4)*GBar5[l][m] + ((combination%47)==3)*GBar4[l][m] + ((combination%47)==2)*GBar3[l][m] + ((combination%47)==1)*GBar2[l][m] + ((combination%47)==0)*GBar1[l][m]);
+       }
+      }
+      Kcounter = Kcounter + (n1-Kcombo);
+
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      
+      combination /= 47;
+    }
+    for(k=0; k<N; k++) {
+      memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
+    }
+    for(k=0; k<K[j]; k++) {
+      memcpy(origJ[j][k], J[j][k], K[j]*sizeof(int));      
+    }
+
+    memcpy(origh[j], h[j], N*sizeof(int));
+    memcpy(origD[j], D[j], K[j]*sizeof(int));
+
+    /*printf("G[%d]:\n", j);
+    printMatrix(G[j], N, N);
+    printf("GBar[%d]:\n", j);
+    printMatrix(GBar[j], N, N);
+
+    printf("h[%d]:\n", j);
+    printVector(h[j], N);
+
+    printf("J[%d]:\n", j);
+    printMatrix(J[j], K[j], K[j]);
+    
+    printf("D[%d]:\n", j);
+    printVector(D[j], K[j]);
+
+    printf("Q[%d]=%d\n", j, Q[j]);*/
+
+  }
+  //exit(0);
+  memcpy(origGamma, Gamma, pow(47,N/12)*sizeof(double complex));
+
+  memcpy(origQ, Q, pow(47,N/12)*sizeof(int));
+
+  while(readPaulicoeffs(&omega, alpha, beta, gamma, delta, N)) {
+
+    Paulicounter++;
+    if(Paulicounter > N) {
+      printf("Error: Number of Paulis is greater than N!\n");
+      return 1;
+    }
+    
+    // Let's break up the Ys into Xs and Zs in the order Z X, as required to pass to measurepauli()
+    // Y_i = -I*Z*X
+    for(i=0; i<N; i++) {
+      if(delta[i]){
+       omega += 3; // -I = I^3
+       beta[i] = delta[i];
+       gamma[i] = delta[i];
+      }
+    }
+
+    /*printf("*******\n");
+    printf("*******\n");
+    printf("omega=%d\n", omega);
+    printf("X:\n");
+    printVector(gamma, N);
+    printf("Z:\n");
+    printVector(beta, N);
+    printf("*******\n");
+    printf("*******\n");*/
+
+    for(j=0; j<pow(47,N/12); j++) { // the kets
+
+      /*printf("========\n");
+      printf("before:\n");
+      printf("K=%d\n", K[j]);
+      printf("h:\n");
+      printVector(h[j], N);
+      printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
+      printf("G:\n");
+      printMatrix(G[j], N, N);
+      printf("GBar:\n");
+      printMatrix(GBar[j], N, N);
+      printf("Q=%d\n", Q[j]);
+      printf("D:\n");
+      printVector(D[j], K[j]);
+      printf("J:\n");
+      printMatrix(J[j], K[j], K[j]);*/
+      Gamma[j] *= measurepauli(N, &K[j], h[j], G[j], GBar[j], &Q[j], &D[j], &J[j], omega, gamma, beta);
+      /*printf("\nafter:\n");
+      printf("K=%d\n", K[j]);
+      printf("h:\n");
+      printVector(h[j], N);
+      printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
+      printf("G:\n");
+      printMatrix(G[j], N, N);
+      printf("GBar:\n");
+      printMatrix(GBar[j], N, N);
+      printf("Q=%d\n", Q[j]);
+      printf("D:\n");
+      printVector(D[j], K[j]);
+      printf("J:\n");
+      printMatrix(J[j], K[j], K[j]);*/
+
+    }
+
+  }
+
+  double complex amplitude = 0.0 + 0.0*I;
+  for(i=0; i<pow(47,N/12); i++) { // the bras
+    printf("i=%d\n", i);
+    for(j=0; j<pow(47,N/12); j++) {
+      double complex newamplitude = innerproduct(N, K[j], h[j], G[j], GBar[j], Q[j], D[j], J[j], N, origK[i], origh[i], origG[i], origGBar[i], origQ[i], origD[i], origJ[i]);
+      amplitude = amplitude + conj(origGamma[i])*Gamma[j]*newamplitude;
+    }
+  }
+
+  printf("amplitude:\n");
+  if(creal(amplitude+ZEROTHRESHOLD)>0)
+    printf("%.10lf %c %.10lf I\n", cabs(creal(amplitude)), cimag(amplitude+ZEROTHRESHOLD)>0?'+':'-' , cabs(cimag(amplitude)));
+  else
+    printf("%.10lf %c %.10lf I\n", creal(amplitude), cimag(amplitude+ZEROTHRESHOLD)>0?'+':'-' , cabs(cimag(amplitude)));
+
+  return 0;
+
+}
+
+
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits)
+{
+    
+  int newomega, newalpha, newbeta, newgamma, newdelta;
+  int i;
+
+  if(scanf("%d", &newomega) != EOF) {
+    *omega = newomega;
+    for(i=0; i<numqubits; i++) {
+      if(scanf("%d %d %d %d", &newalpha, &newbeta, &newgamma, &newdelta) == EOF) {
+       printf("Error: Too few input coeffs!\n");
+       exit(0);
+      }
+      if(newalpha+newbeta+newgamma+newdelta > 1) {
+       printf("Error: Too many coefficients are non-zero at Pauli %d!\n", i);
+       exit(0);
+      }
+      alpha[i] = newalpha; beta[i] = newbeta; gamma[i] = newgamma; delta[i] = newdelta;
+    }
+    return 1;
+  } else
+    return 0;
+    
+}
diff --git a/strongsim12_relerr.c b/strongsim12_relerr.c
new file mode 100644 (file)
index 0000000..8ec8d76
--- /dev/null
@@ -0,0 +1,2059 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <complex.h>
+#include <time.h>
+#include "matrix.h"
+#include "exponentialsum.h"
+#include "shrinkstar.h"
+#include "extend.h"
+#include "measurepauli.h"
+#include "innerproduct.h"
+#include "randomstabilizerstate.h"
+
+#define ZEROTHRESHOLD (0.00000001)
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits);
+
+// order of matrix elements is [row][column]!!!
+
+int main(int argc, char *argv[])
+{
+
+  if(argc != 2) {
+    printf("strongsim12_rellerr argument: \"number of stabilizer state samples\"\n");
+    exit(0);
+  }
+
+  int NUMSTABSTATESAMPLES = atoi(argv[1]);        // number of stabilizer state samples
+
+  int N;                  // number of qubits
+  scanf("%d", &N);
+
+  if(N%12 != 0) {
+    printf("'N' needs to be a multiple of 12 for a k=12 tensor factor decomposition!\n");
+    return 1;
+  }
+
+  int T;              // number of T gate magic states (set to the first 'K' of the 'N' qubits -- the rest are set to the '0' computational basis state)
+  scanf("%d", &T);
+
+  int omega[N]; // max of N measurements
+  int alpha[N][N], beta[N][N], gamma[N][N], delta[N][N]; // max of N measurements of N Paulis
+  int Paulicounter = 0;
+
+  int i, j, k, l, m;
+
+  FILE *fp;
+  char buff[255];
+
+  srand((unsigned)time(NULL)); // seeding the random number generator for randomstabilizerstate()
+  
+  fp = fopen("Pd.txt", "r");
+
+  if(fscanf(fp, "%s", buff) == EOF) {
+    printf("Error: Pd.txt should start with the number N of P(d) of values tabulated.");
+    return 1;
+  }
+  
+  double** Pd;
+
+  int PdN = atoi(buff);
+
+  Pd = calloc(PdN, sizeof(double*));
+  for(i=0; i<PdN; i++) 
+    Pd[i] = calloc(PdN+1, sizeof(double));
+
+  double tmp;
+  
+  for(i=1; i<PdN; i++) {
+    tmp = 0.0;
+    for(j=0; j<=i; j++) {
+      if(fscanf(fp, "%s", buff) == EOF) {
+       printf("Error: expected more values tabulated for P(d) for N=%d", PdN);
+       return 1;
+      }
+      Pd[i][j] = atof(buff);
+      //printf("%e ", Pd[i][j]);
+      tmp += Pd[i][j];
+    }
+    //printf("\n");
+    //printf("total=%f\n", tmp);
+  }
+
+
+  double complex coeffb60 = (-16.0+12.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(6.0*PI*I/8.0)/8.0*cpow(2.0,3.0);
+  double complex coeffb66 = (96.0-68.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(6.0*PI*I/8.0)/8.0*cpow(2.0,3.0);
+  double complex coeffe6 = (10.0-7.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(6.0*PI*I/8.0)*cpow(2.0,2.5);
+  double complex coeffo6 = (-14.0+10.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(-14.0*PI*I/8.0)*cpow(2.0,2.5);
+  double complex coeffk6 = (7.0-5.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(-8.0*PI*I/8.0)*4.0*csqrt(2.0)*cpow(2.0,0.5);
+  double complex coeffphiprime = (10.0-7.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(2.0*PI*I/8.0)*cpow(2.0,2.5);
+  double complex coeffphidprime = (10.0-7.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(2.0*PI*I/8.0)*cpow(2.0,2.5);
+
+  // b60
+  int nn1 = 6; int kk1 = 6; int (*(GG1[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}}; int (*(GGBar1[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}}; int hh1[] = {0, 0, 0, 0, 0, 0}; int QQ1 = 0; int DD1[] = {0, 0, 0, 0, 0, 0}; int (*(JJ1[])) = { (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0} };
+  // b66
+  int nn2 = 6; int kk2 = 6; int (*(GG2[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}}; int (*(GGBar2[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}}; int hh2[] = {0, 0, 0, 0, 0, 0}; int QQ2 = 4; int DD2[] = {4, 4, 4, 4, 4, 4}; int (*(JJ2[])) = { (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0} };
+  // e6
+  int nn3 = 6; int kk3 = 5; int (*(GG3[])) = { (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0} }; int (*(GGBar3[])) = { (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1} }; int hh3[] = {1, 0, 0, 0, 0, 0}; int QQ3 = 4; int DD3[] = {0, 0, 0, 0, 0}; int (*(JJ3[])) = { (int[]) {0, 4, 4, 4, 4}, (int[]) {4, 0, 4, 4, 4}, (int[]) {4, 4, 0, 4, 4}, (int[]) {4, 4, 4, 0, 4}, (int[]) {4, 4, 4, 4, 0}  };
+  // o6
+  int nn4 = 6; int kk4 = 5; int (*(GG4[])) = { (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0} }; int (*(GGBar4[])) = { (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1} }; int hh4[] = {0, 0, 0, 0, 0, 0}; int QQ4 = 4; int DD4[] = {4, 4, 4, 4, 4}; int (*(JJ4[])) = { (int[]) {0, 4, 4, 4, 4}, (int[]) {4, 0, 4, 4, 4}, (int[]) {4, 4, 0, 4, 4}, (int[]) {4, 4, 4, 0, 4}, (int[]) {4, 4, 4, 4, 0}  };
+  // k6
+  int nn5 = 6; int kk5 = 1; int (*(GG5[])) = { (int[]) {1, 1, 1, 1, 1, 1}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1} }; int (*(GGBar5[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1} }; int hh5[] = {1, 1, 1, 1, 1, 1}; int QQ5 = 6; int DD5[] = {2}; int (*(JJ5[])) = { (int[]) {4} };
+  // phiprime
+  int nn6 = 6; int kk6 = 5; int (*(GG6[])) = { (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0} }; int (*(GGBar6[])) = { (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1} }; int hh6[] = {1, 0, 0, 0, 0, 0}; int QQ6 = 0; int DD6[] = {0, 0, 0, 0, 0}; int (*(JJ6[])) = { (int[]) {0, 4, 0, 0, 4}, (int[]) {4, 0, 4, 0, 0}, (int[]) {0, 4, 0, 4, 0}, (int[]) {0, 0, 4, 0, 4}, (int[]) {4, 0, 0, 4, 0}  };
+  // phidoubleprime
+  int nn7 = 6; int kk7 = 5; int (*(GG7[])) = { (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0} }; int (*(GGBar7[])) = { (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1} }; int hh7[] = {1, 0, 0, 0, 0, 0}; int QQ7 = 0; int DD7[] = {0, 0, 0, 0, 0}; int (*(JJ7[])) = { (int[]) {0, 0, 4, 4, 0}, (int[]) {0, 0, 0, 4, 4}, (int[]) {4, 0, 0, 0, 4}, (int[]) {4, 4, 0, 0, 0}, (int[]) {0, 4, 4, 0, 0}  };
+
+  // b60 * b60
+  int n1 = nn1+nn1; int k1 = kk1+kk1; int **G1; int **GBar1; int *h1; int Q1; int *D1; int **J1;
+  G1 = calloc(nn1+nn1,sizeof(int*));
+  GBar1 = calloc(nn1+nn1,sizeof(int*));
+  h1 = calloc(nn1+nn1,sizeof(int));
+  D1 = calloc(kk1+kk1,sizeof(int));
+  J1 = calloc(kk1+kk1,sizeof(int*));
+  for(i=0; i<nn1+nn1; i++) {
+    G1[i] = calloc(nn1+nn1, sizeof(int)); GBar1[i] = calloc(nn1+nn1, sizeof(int));
+  }
+  for(i=0; i<kk1+kk1; i++)
+     J1[i] = calloc(kk1+kk1, sizeof(int));
+  //appendBlockMatrix(GG1, GG1, G1, nn1, nn1, nn1, nn1);
+  addSubMatrix(GG1, G1, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GG1, G1, kk1, nn1, 0, 0, kk1, nn1);
+  addSubMatrix(GG1, G1, nn1-kk1, nn1, kk1, 0, kk1+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG1, G1, nn1-kk1, nn1, kk1, 0, kk1+kk1+nn1-kk1, nn1);
+  //appendBlockMatrix(GGBar1, GGBar1, GBar1, nn1, nn1, nn1, nn1);
+  addSubMatrix(GGBar1, GBar1, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GGBar1, GBar1, kk1, nn1, 0, 0, kk1, nn1);
+  addSubMatrix(GGBar1, GBar1, nn1-kk1, nn1, kk1, 0, kk1+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar1, GBar1, nn1-kk1, nn1, kk1, 0, kk1+kk1+nn1-kk1, nn1);
+  appendVector(hh1, hh1, h1, nn1, nn1);
+  Q1 = (QQ1+QQ1);
+  appendVector(DD1, DD1, D1, kk1, kk1);
+  appendBlockMatrix(JJ1, JJ1, J1, kk1, kk1, kk1, kk1);
+  //addSubMatrix(JJ1, J1, kk1, kk1, 0, 0, 0, 0);
+  //addSubMatrix(JJ1, J1, kk1, kk1, 0, 0, kk1, kk1);
+
+  // b66 * b60
+  /*int n2 = nn1+nn2; int k2 = kk1+kk2; int **G2; int **GBar2; int *h2; int Q2; int *D2; int **J2;
+  G2 = calloc(nn1+nn2,sizeof(int*));
+  GBar2 = calloc(nn1+nn2,sizeof(int*));
+  h2 = calloc(nn1+nn2,sizeof(int));
+  D2 = calloc(kk1+kk2,sizeof(int));
+  J2 = calloc(kk1+kk2,sizeof(int*));
+  for(i=0; i<nn1+nn2; i++) {
+    G2[i] = calloc(nn1+nn2, sizeof(int)); GBar2[i] = calloc(nn1+nn2, sizeof(int));
+  }
+  for(i=0; i<kk1+kk2; i++)
+     J2[i] = calloc(kk1+kk2, sizeof(int));
+  //appendBlockMatrix(GG2, GG1, G2, nn2, nn2, nn1, nn1);
+  addSubMatrix(GG2, G2, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GG1, G2, kk1, nn1, 0, 0, kk2, nn2);
+  addSubMatrix(GG2, G2, nn2-kk2, nn2, kk2, 0, kk2+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG1, G2, nn1-kk1, nn1, kk1, 0, kk2+kk1+nn2-kk2, nn1);
+  //appendBlockMatrix(GGBar2, GGBar1, GBar2, nn2, nn2, nn1, nn1);
+  addSubMatrix(GGBar2, GBar2, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GGBar1, GBar2, kk1, nn1, 0, 0, kk2, nn2);
+  addSubMatrix(GGBar2, GBar2, nn2-kk2, nn2, kk2, 0, kk2+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar1, GBar2, nn1-kk1, nn1, kk1, 0, kk2+kk1+nn2-kk2, nn1);
+  appendVector(hh2, hh1, h2, nn2, nn1);
+  Q2 = (QQ1+QQ2);
+  appendVector(DD2, DD1, D2, kk2, kk1);
+  appendBlockMatrix(JJ2, JJ1, J2, kk2, kk2, kk1, kk1);*/
+
+  // e6 * b60
+  int n2 = nn1+nn3; int k2 = kk1+kk3; int **G2; int **GBar2; int *h2; int Q2; int *D2; int **J2;
+  G2 = calloc(nn1+nn3,sizeof(int*));
+  GBar2 = calloc(nn1+nn3,sizeof(int*));
+  h2 = calloc(nn1+nn3,sizeof(int));
+  D2 = calloc(kk1+kk3,sizeof(int));
+  J2 = calloc(kk1+kk3,sizeof(int*));
+  for(i=0; i<nn1+nn3; i++) {
+    G2[i] = calloc(nn1+nn3, sizeof(int)); GBar2[i] = calloc(nn1+nn3, sizeof(int));
+  }
+  for(i=0; i<kk1+kk3; i++)
+     J2[i] = calloc(kk1+kk3, sizeof(int));
+  //appendBlockMatrix(GG3, GG1, G3, nn3, nn3, nn1, nn1);
+  addSubMatrix(GG3, G2, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GG1, G2, kk1, nn1, 0, 0, kk3, nn3);
+  addSubMatrix(GG3, G2, nn3-kk3, nn3, kk3, 0, kk3+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG1, G2, nn1-kk1, nn1, kk1, 0, kk3+kk1+nn3-kk3, nn1);
+  //appendBlockMatrix(GGBar3, GGBar1, GBar3, nn3, nn3, nn1, nn1);
+  addSubMatrix(GGBar3, GBar2, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GGBar1, GBar2, kk1, nn1, 0, 0, kk3, nn3);
+  addSubMatrix(GGBar3, GBar2, nn3-kk3, nn3, kk3, 0, kk3+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar1, GBar2, nn1-kk1, nn1, kk1, 0, kk3+kk1+nn3-kk3, nn1);
+  appendVector(hh3, hh1, h2, nn3, nn1);
+  Q2 = (QQ1+QQ3);
+  appendVector(DD3, DD1, D2, kk3, kk1);
+  appendBlockMatrix(JJ3, JJ1, J2, kk3, kk3, kk1, kk1);
+  
+  // o6 * b60
+  int n3 = nn1+nn4; int k3 = kk1+kk4; int **G3; int **GBar3; int *h3; int Q3; int *D3; int **J3;
+  G3 = calloc(nn1+nn4,sizeof(int*));
+  GBar3 = calloc(nn1+nn4,sizeof(int*));
+  h3 = calloc(nn1+nn4,sizeof(int));
+  D3 = calloc(kk1+kk4,sizeof(int));
+  J3 = calloc(kk1+kk4,sizeof(int*));
+  for(i=0; i<nn1+nn4; i++) {
+    G3[i] = calloc(nn1+nn4, sizeof(int)); GBar3[i] = calloc(nn1+nn4, sizeof(int));
+  }
+  for(i=0; i<kk1+kk4; i++)
+     J3[i] = calloc(kk1+kk4, sizeof(int));
+  //appendBlockMatrix(GG4, GG1, G4, nn4, nn4, nn1, nn1);
+  addSubMatrix(GG4, G3, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GG1, G3, kk1, nn1, 0, 0, kk4, nn4);
+  addSubMatrix(GG4, G3, nn4-kk4, nn4, kk4, 0, kk4+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG1, G3, nn1-kk1, nn1, kk1, 0, kk4+kk1+nn4-kk4, nn1);
+  //appendBlockMatrix(GGBar4, GGBar1, GBar4, nn4, nn4, nn1, nn1);
+  addSubMatrix(GGBar4, GBar3, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GGBar1, GBar3, kk1, nn1, 0, 0, kk4, nn4);
+  addSubMatrix(GGBar4, GBar3, nn4-kk4, nn4, kk4, 0, kk4+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar1, GBar3, nn1-kk1, nn1, kk1, 0, kk4+kk1+nn4-kk4, nn1);
+  appendVector(hh4, hh1, h3, nn4, nn1);
+  Q3 = (QQ1+QQ4);
+  appendVector(DD4, DD1, D3, kk4, kk1);
+  appendBlockMatrix(JJ4, JJ1, J3, kk4, kk4, kk1, kk1);
+
+  // k6 * b60
+  int n4 = nn1+nn5; int k4 = kk1+kk5; int **G4; int **GBar4; int *h4; int Q4; int *D4; int **J4;
+  G4 = calloc(nn1+nn5,sizeof(int*));
+  GBar4 = calloc(nn1+nn5,sizeof(int*));
+  h4 = calloc(nn1+nn5,sizeof(int));
+  D4 = calloc(kk1+kk5,sizeof(int));
+  J4 = calloc(kk1+kk5,sizeof(int*));
+  for(i=0; i<nn1+nn5; i++) {
+    G4[i] = calloc(nn1+nn5, sizeof(int)); GBar4[i] = calloc(nn1+nn5, sizeof(int));
+  }
+  for(i=0; i<kk1+kk5; i++)
+     J4[i] = calloc(kk1+kk5, sizeof(int));
+  //appendBlockMatrix(GG5, GG1, G5, nn5, nn5, nn1, nn1);
+  addSubMatrix(GG5, G4, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GG1, G4, kk1, nn1, 0, 0, kk5, nn5);
+  addSubMatrix(GG5, G4, nn5-kk5, nn5, kk5, 0, kk5+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG1, G4, nn1-kk1, nn1, kk1, 0, kk5+kk1+nn5-kk5, nn1);
+  //appendBlockMatrix(GGBar5, GGBar1, GBar5, nn5, nn5, nn1, nn1);
+  addSubMatrix(GGBar5, GBar4, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GGBar1, GBar4, kk1, nn1, 0, 0, kk5, nn5);
+  addSubMatrix(GGBar5, GBar4, nn5-kk5, nn5, kk5, 0, kk5+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar1, GBar4, nn1-kk1, nn1, kk1, 0, kk5+kk1+nn5-kk5, nn1);
+  appendVector(hh5, hh1, h4, nn5, nn1);
+  Q4 = (QQ1+QQ5);
+  appendVector(DD5, DD1, D4, kk5, kk1);
+  appendBlockMatrix(JJ5, JJ1, J4, kk5, kk5, kk1, kk1);
+
+  // phiprime * b60 
+  int n5 = nn1+nn6; int k5 = kk1+kk6; int **G5; int **GBar5; int *h5; int Q5; int *D5; int **J5;
+  G5 = calloc(nn1+nn6,sizeof(int*));
+  GBar5 = calloc(nn1+nn6,sizeof(int*));
+  h5 = calloc(nn1+nn6,sizeof(int));
+  D5 = calloc(kk1+kk6,sizeof(int));
+  J5 = calloc(kk1+kk6,sizeof(int*));
+  for(i=0; i<nn1+nn6; i++) {
+    G5[i] = calloc(nn1+nn6, sizeof(int)); GBar5[i] = calloc(nn1+nn6, sizeof(int));
+  }
+  for(i=0; i<kk1+kk6; i++)
+     J5[i] = calloc(kk1+kk6, sizeof(int));
+  //appendBlockMatrix(GG6, GG1, G6, nn6, nn6, nn1, nn1);
+  addSubMatrix(GG6, G5, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GG1, G5, kk1, nn1, 0, 0, kk6, nn6);
+  addSubMatrix(GG6, G5, nn6-kk6, nn6, kk6, 0, kk6+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG1, G5, nn1-kk1, nn1, kk1, 0, kk6+kk1+nn6-kk6, nn1);
+  //appendBlockMatrix(GGBar6, GGBar1, GBar6, nn6, nn6, nn1, nn1);
+  addSubMatrix(GGBar6, GBar5, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GGBar1, GBar5, kk1, nn1, 0, 0, kk6, nn6);
+  addSubMatrix(GGBar6, GBar5, nn6-kk6, nn6, kk6, 0, kk6+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar1, GBar5, nn1-kk1, nn1, kk1, 0, kk6+kk1+nn6-kk6, nn1);
+  appendVector(hh6, hh1, h5, nn6, nn1);
+  Q5 = (QQ1+QQ6);
+  appendVector(DD6, DD1, D5, kk6, kk1);
+  appendBlockMatrix(JJ6, JJ1, J5, kk6, kk6, kk1, kk1);
+  
+  // phidprime * b60
+  int n6 = nn1+nn7; int k6 = kk1+kk7; int **G6; int **GBar6; int *h6; int Q6; int *D6; int **J6;
+  G6 = calloc(nn1+nn7,sizeof(int*));
+  GBar6 = calloc(nn1+nn7,sizeof(int*));
+  h6 = calloc(nn1+nn7,sizeof(int));
+  D6 = calloc(kk1+kk7,sizeof(int));
+  J6 = calloc(kk1+kk7,sizeof(int*));
+  for(i=0; i<nn1+nn7; i++) {
+    G6[i] = calloc(nn1+nn7, sizeof(int)); GBar6[i] = calloc(nn1+nn7, sizeof(int));
+  }
+  for(i=0; i<kk1+kk7; i++)
+     J6[i] = calloc(kk1+kk7, sizeof(int));
+  //appendBlockMatrix(GG7, GG1, G7, nn7, nn7, nn1, nn1);
+  addSubMatrix(GG7, G6, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GG1, G6, kk1, nn1, 0, 0, kk7, nn7);
+  addSubMatrix(GG7, G6, nn7-kk7, nn7, kk7, 0, kk7+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG1, G6, nn1-kk1, nn1, kk1, 0, kk7+kk1+nn7-kk7, nn1);
+  //appendBlockMatrix(GGBar7, GGBar1, GBar7, nn7, nn7, nn1, nn1);
+  addSubMatrix(GGBar7, GBar6, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GGBar1, GBar6, kk1, nn1, 0, 0, kk7, nn7);
+  addSubMatrix(GGBar7, GBar6, nn7-kk7, nn7, kk7, 0, kk7+kk1, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar1, GBar6, nn1-kk1, nn1, kk1, 0, kk7+kk1+nn7-kk7, nn1);
+  appendVector(hh7, hh1, h6, nn7, nn1);
+  Q6 = (QQ1+QQ7);
+  appendVector(DD7, DD1, D6, kk7, kk1);
+  appendBlockMatrix(JJ7, JJ1, J6, kk7, kk7, kk1, kk1);
+
+  // b60 * b66
+  /*int n8 = nn2+nn1; int k8 = kk2+kk1; int **G8; int **GBar8; int *h8; int Q8; int *D8; int **J8;
+  G8 = calloc(nn2+nn1,sizeof(int*));
+  GBar8 = calloc(nn2+nn1,sizeof(int*));
+  h8 = calloc(nn2+nn1,sizeof(int));
+  D8 = calloc(kk2+kk1,sizeof(int));
+  J8 = calloc(kk2+kk1,sizeof(int*));
+  for(i=0; i<nn2+nn1; i++) {
+    G8[i] = calloc(nn2+nn1, sizeof(int)); GBar8[i] = calloc(nn2+nn1, sizeof(int));
+  }
+  for(i=0; i<kk2+kk1; i++)
+     J8[i] = calloc(kk2+kk1, sizeof(int));
+  //appendBlockMatrix(GG1, GG2, G8, nn1, nn1, nn2, nn2);
+  addSubMatrix(GG1, G8, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GG2, G8, kk2, nn2, 0, 0, kk1, nn1);
+  addSubMatrix(GG1, G8, nn1-kk1, nn1, kk1, 0, kk1+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG2, G8, nn2-kk2, nn2, kk2, 0, kk1+kk2+nn1-kk1, nn2);
+  //appendBlockMatrix(GGBar1, GGBar2, GBar8, nn1, nn1, nn2, nn2);
+  addSubMatrix(GGBar1, GBar8, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GGBar2, GBar8, kk2, nn2, 0, 0, kk1, nn1);
+  addSubMatrix(GGBar1, GBar8, nn1-kk1, nn1, kk1, 0, kk1+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar2, GBar8, nn2-kk2, nn2, kk2, 0, kk1+kk2+nn1-kk1, nn2);
+  appendVector(hh1, hh2, h8, nn1, nn2);
+  Q8 = (QQ2+QQ1);
+  appendVector(DD1, DD2, D8, kk1, kk2);
+  appendBlockMatrix(JJ1, JJ2, J8, kk1, kk1, kk2, kk2);*/
+
+  // b66 * b66
+  int n7 = nn2+nn2; int k7 = kk2+kk2; int **G7; int **GBar7; int *h7; int Q7; int *D7; int **J7;
+  G7 = calloc(nn2+nn2,sizeof(int*));
+  GBar7 = calloc(nn2+nn2,sizeof(int*));
+  h7 = calloc(nn2+nn2,sizeof(int));
+  D7 = calloc(kk2+kk2,sizeof(int));
+  J7 = calloc(kk2+kk2,sizeof(int*));
+  for(i=0; i<nn2+nn2; i++) {
+    G7[i] = calloc(nn2+nn2, sizeof(int)); GBar7[i] = calloc(nn2+nn2, sizeof(int));
+  }
+  for(i=0; i<kk2+kk2; i++)
+     J7[i] = calloc(kk2+kk2, sizeof(int));
+  //appendBlockMatrix(GG2, GG2, G9, nn2, nn2, nn2, nn2);
+  addSubMatrix(GG2, G7, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GG2, G7, kk2, nn2, 0, 0, kk2, nn2);
+  addSubMatrix(GG2, G7, nn2-kk2, nn2, kk2, 0, kk2+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG2, G7, nn2-kk2, nn2, kk2, 0, kk2+kk2+nn2-kk2, nn2);
+  //appendBlockMatrix(GGBar2, GGBar2, GBar9, nn2, nn2, nn2, nn2);
+  addSubMatrix(GGBar2, GBar7, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GGBar2, GBar7, kk2, nn2, 0, 0, kk2, nn2);
+  addSubMatrix(GGBar2, GBar7, nn2-kk2, nn2, kk2, 0, kk2+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar2, GBar7, nn2-kk2, nn2, kk2, 0, kk2+kk2+nn2-kk2, nn2);
+  appendVector(hh2, hh2, h7, nn2, nn2);
+  Q7 = (QQ2+QQ2);
+  appendVector(DD2, DD2, D7, kk2, kk2);
+  appendBlockMatrix(JJ2, JJ2, J7, kk2, kk2, kk2, kk2);
+
+  // e6 * b66
+  int n8 = nn2+nn3; int k8 = kk2+kk3; int **G8; int **GBar8; int *h8; int Q8; int *D8; int **J8;
+  G8 = calloc(nn2+nn3,sizeof(int*));
+  GBar8 = calloc(nn2+nn3,sizeof(int*));
+  h8 = calloc(nn2+nn3,sizeof(int));
+  D8 = calloc(kk2+kk3,sizeof(int));
+  J8 = calloc(kk2+kk3,sizeof(int*));
+  for(i=0; i<nn2+nn3; i++) {
+    G8[i] = calloc(nn2+nn3, sizeof(int)); GBar8[i] = calloc(nn2+nn3, sizeof(int));
+  }
+  for(i=0; i<kk2+kk3; i++)
+     J8[i] = calloc(kk2+kk3, sizeof(int));
+  //appendBlockMatrix(GG3, GG2, G10, nn3, nn3, nn2, nn2);
+  addSubMatrix(GG3, G8, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GG2, G8, kk2, nn2, 0, 0, kk3, nn3);
+  addSubMatrix(GG3, G8, nn3-kk3, nn3, kk3, 0, kk3+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG2, G8, nn2-kk2, nn2, kk2, 0, kk3+kk2+nn3-kk3, nn2);
+  //appendBlockMatrix(GGBar3, GGBar2, GBar10, nn3, nn3, nn2, nn2);
+  addSubMatrix(GGBar3, GBar8, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GGBar2, GBar8, kk2, nn2, 0, 0, kk3, nn3);
+  addSubMatrix(GGBar3, GBar8, nn3-kk3, nn3, kk3, 0, kk3+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar2, GBar8, nn2-kk2, nn2, kk2, 0, kk3+kk2+nn3-kk3, nn2);
+  appendVector(hh3, hh2, h8, nn3, nn2);
+  Q8 = (QQ2+QQ3);
+  appendVector(DD3, DD2, D8, kk3, kk2);
+  appendBlockMatrix(JJ3, JJ2, J8, kk3, kk3, kk2, kk2);
+
+  // o6 * b66
+  int n9 = nn2+nn4; int k9 = kk2+kk4; int **G9; int **GBar9; int *h9; int Q9; int *D9; int **J9;
+  G9 = calloc(nn2+nn4,sizeof(int*));
+  GBar9 = calloc(nn2+nn4,sizeof(int*));
+  h9 = calloc(nn2+nn4,sizeof(int));
+  D9 = calloc(kk2+kk4,sizeof(int));
+  J9 = calloc(kk2+kk4,sizeof(int*));
+  for(i=0; i<nn2+nn4; i++) {
+    G9[i] = calloc(nn2+nn4, sizeof(int)); GBar9[i] = calloc(nn2+nn4, sizeof(int));
+  }
+  for(i=0; i<kk2+kk4; i++)
+     J9[i] = calloc(kk2+kk4, sizeof(int));
+  //appendBlockMatrix(GG4, GG2, G11, nn4, nn4, nn2, nn2);
+  addSubMatrix(GG4, G9, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GG2, G9, kk2, nn2, 0, 0, kk4, nn4);
+  addSubMatrix(GG4, G9, nn4-kk4, nn4, kk4, 0, kk4+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG2, G9, nn2-kk2, nn2, kk2, 0, kk4+kk2+nn4-kk4, nn2);
+  //appendBlockMatrix(GGBar4, GGBar2, GBar11, nn4, nn4, nn2, nn2);
+  addSubMatrix(GGBar4, GBar9, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GGBar2, GBar9, kk2, nn2, 0, 0, kk4, nn4);
+  addSubMatrix(GGBar4, GBar9, nn4-kk4, nn4, kk4, 0, kk4+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar2, GBar9, nn2-kk2, nn2, kk2, 0, kk4+kk2+nn4-kk4, nn2);
+  appendVector(hh4, hh2, h9, nn4, nn2);
+  Q9 = (QQ2+QQ4);
+  appendVector(DD4, DD2, D9, kk4, kk2);
+  appendBlockMatrix(JJ4, JJ2, J9, kk4, kk4, kk2, kk2);
+
+  // k6 * b66
+  int n10 = nn2+nn5; int k10 = kk2+kk5; int **G10; int **GBar10; int *h10; int Q10; int *D10; int **J10;
+  G10 = calloc(nn2+nn5,sizeof(int*));
+  GBar10 = calloc(nn2+nn5,sizeof(int*));
+  h10 = calloc(nn2+nn5,sizeof(int));
+  D10 = calloc(kk2+kk5,sizeof(int));
+  J10 = calloc(kk2+kk5,sizeof(int*));
+  for(i=0; i<nn2+nn5; i++) {
+    G10[i] = calloc(nn2+nn5, sizeof(int)); GBar10[i] = calloc(nn2+nn5, sizeof(int));
+  }
+  for(i=0; i<kk2+kk5; i++)
+     J10[i] = calloc(kk2+kk5, sizeof(int));
+  //appendBlockMatrix(GG5, GG2, G12, nn5, nn5, nn2, nn2);
+  addSubMatrix(GG5, G10, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GG2, G10, kk2, nn2, 0, 0, kk5, nn5);
+  addSubMatrix(GG5, G10, nn5-kk5, nn5, kk5, 0, kk5+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG2, G10, nn2-kk2, nn2, kk2, 0, kk5+kk2+nn5-kk5, nn2);
+  //appendBlockMatrix(GGBar5, GGBar2, GBar12, nn5, nn5, nn2, nn2);
+  addSubMatrix(GGBar5, GBar10, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GGBar2, GBar10, kk2, nn2, 0, 0, kk5, nn5);
+  addSubMatrix(GGBar5, GBar10, nn5-kk5, nn5, kk5, 0, kk5+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar2, GBar10, nn2-kk2, nn2, kk2, 0, kk5+kk2+nn5-kk5, nn2);
+  appendVector(hh5, hh2, h10, nn5, nn2);
+  Q10 = (QQ2+QQ5);
+  appendVector(DD5, DD2, D10, kk5, kk2);
+  appendBlockMatrix(JJ5, JJ2, J10, kk5, kk5, kk2, kk2);
+  
+  // phiprime * b66
+  int n11 = nn2+nn6; int k11 = kk2+kk6; int **G11; int **GBar11; int *h11; int Q11; int *D11; int **J11;
+  G11 = calloc(nn2+nn6,sizeof(int*));
+  GBar11 = calloc(nn2+nn6,sizeof(int*));
+  h11 = calloc(nn2+nn6,sizeof(int));
+  D11 = calloc(kk2+kk6,sizeof(int));
+  J11 = calloc(kk2+kk6,sizeof(int*));
+  for(i=0; i<nn2+nn6; i++) {
+    G11[i] = calloc(nn2+nn6, sizeof(int)); GBar11[i] = calloc(nn2+nn6, sizeof(int));
+  }
+  for(i=0; i<kk2+kk6; i++)
+     J11[i] = calloc(kk2+kk6, sizeof(int));
+  //appendBlockMatrix(GG6, GG2, G13, nn6, nn6, nn2, nn2);
+  addSubMatrix(GG6, G11, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GG2, G11, kk2, nn2, 0, 0, kk6, nn6);
+  addSubMatrix(GG6, G11, nn6-kk6, nn6, kk6, 0, kk6+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG2, G11, nn2-kk2, nn2, kk2, 0, kk6+kk2+nn6-kk6, nn2);
+  //appendBlockMatrix(GGBar6, GGBar2, GBar13, nn6, nn6, nn2, nn2);
+  addSubMatrix(GGBar6, GBar11, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GGBar2, GBar11, kk2, nn2, 0, 0, kk6, nn6);
+  addSubMatrix(GGBar6, GBar11, nn6-kk6, nn6, kk6, 0, kk6+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar2, GBar11, nn2-kk2, nn2, kk2, 0, kk6+kk2+nn6-kk6, nn2);
+  appendVector(hh6, hh2, h11, nn6, nn2);
+  Q11 = (QQ2+QQ6);
+  appendVector(DD6, DD2, D11, kk6, kk2);
+  appendBlockMatrix(JJ6, JJ2, J11, kk6, kk6, kk2, kk2);
+
+  // phidprime * b66
+  int n12 = nn2+nn7; int k12 = kk2+kk7; int **G12; int **GBar12; int *h12; int Q12; int *D12; int **J12;
+  G12 = calloc(nn2+nn7,sizeof(int*));
+  GBar12 = calloc(nn2+nn7,sizeof(int*));
+  h12 = calloc(nn2+nn7,sizeof(int));
+  D12 = calloc(kk2+kk7,sizeof(int));
+  J12 = calloc(kk2+kk7,sizeof(int*));
+  for(i=0; i<nn2+nn7; i++) {
+    G12[i] = calloc(nn2+nn7, sizeof(int)); GBar12[i] = calloc(nn2+nn7, sizeof(int));
+  }
+  for(i=0; i<kk2+kk7; i++)
+     J12[i] = calloc(kk2+kk7, sizeof(int));
+  //appendBlockMatrix(GG7, GG2, G14, nn7, nn7, nn2, nn2);
+  addSubMatrix(GG7, G12, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GG2, G12, kk2, nn2, 0, 0, kk7, nn7);
+  addSubMatrix(GG7, G12, nn7-kk7, nn7, kk7, 0, kk7+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG2, G12, nn2-kk2, nn2, kk2, 0, kk7+kk2+nn7-kk7, nn2);
+  //appendBlockMatrix(GGBar7, GGBar2, GBar14, nn7, nn7, nn2, nn2);
+  addSubMatrix(GGBar7, GBar12, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GGBar2, GBar12, kk2, nn2, 0, 0, kk7, nn7);
+  addSubMatrix(GGBar7, GBar12, nn7-kk7, nn7, kk7, 0, kk7+kk2, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar2, GBar12, nn2-kk2, nn2, kk2, 0, kk7+kk2+nn7-kk7, nn2);
+  appendVector(hh7, hh2, h12, nn7, nn2);
+  Q12 = (QQ2+QQ7);
+  appendVector(DD7, DD2, D12, kk7, kk2);
+  appendBlockMatrix(JJ7, JJ2, J12, kk7, kk7, kk2, kk2);
+
+  // b60 * e6
+  int n13 = nn3+nn1; int k13 = kk3+kk1; int **G13; int **GBar13; int *h13; int Q13; int *D13; int **J13;
+  G13 = calloc(nn3+nn1,sizeof(int*));
+  GBar13 = calloc(nn3+nn1,sizeof(int*));
+  h13 = calloc(nn3+nn1,sizeof(int));
+  D13 = calloc(kk3+kk1,sizeof(int));
+  J13 = calloc(kk3+kk1,sizeof(int*));
+  for(i=0; i<nn3+nn1; i++) {
+    G13[i] = calloc(nn3+nn1, sizeof(int)); GBar13[i] = calloc(nn3+nn1, sizeof(int));
+  }
+  for(i=0; i<kk3+kk1; i++)
+     J13[i] = calloc(kk3+kk1, sizeof(int));
+  //appendBlockMatrix(GG1, GG3, G15, nn1, nn1, nn3, nn3);
+  addSubMatrix(GG1, G13, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GG3, G13, kk3, nn3, 0, 0, kk1, nn1);
+  addSubMatrix(GG1, G13, nn1-kk1, nn1, kk1, 0, kk1+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG3, G13, nn3-kk3, nn3, kk3, 0, kk1+kk3+nn1-kk1, nn3);
+  //appendBlockMatrix(GGBar1, GGBar3, GBar15, nn1, nn1, nn3, nn3);
+  addSubMatrix(GGBar1, GBar13, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GGBar3, GBar13, kk3, nn3, 0, 0, kk1, nn1);
+  addSubMatrix(GGBar1, GBar13, nn1-kk1, nn1, kk1, 0, kk1+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar3, GBar13, nn3-kk3, nn3, kk3, 0, kk1+kk3+nn1-kk1, nn3);
+  appendVector(hh1, hh3, h13, nn1, nn3);
+  Q13 = (QQ3+QQ1);
+  appendVector(DD1, DD3, D13, kk1, kk3);
+  appendBlockMatrix(JJ1, JJ3, J13, kk1, kk1, kk3, kk3);
+
+  // b66 * e6
+  int n14 = nn3+nn2; int k14 = kk3+kk2; int **G14; int **GBar14; int *h14; int Q14; int *D14; int **J14;
+  G14 = calloc(nn3+nn2,sizeof(int*));
+  GBar14 = calloc(nn3+nn2,sizeof(int*));
+  h14 = calloc(nn3+nn2,sizeof(int));
+  D14 = calloc(kk3+kk2,sizeof(int));
+  J14 = calloc(kk3+kk2,sizeof(int*));
+  for(i=0; i<nn3+nn2; i++) {
+    G14[i] = calloc(nn3+nn2, sizeof(int)); GBar14[i] = calloc(nn3+nn2, sizeof(int));
+  }
+  for(i=0; i<kk3+kk2; i++)
+     J14[i] = calloc(kk3+kk2, sizeof(int));
+  //appendBlockMatrix(GG2, GG3, G16, nn2, nn2, nn3, nn3);
+  addSubMatrix(GG2, G14, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GG3, G14, kk3, nn3, 0, 0, kk2, nn2);
+  addSubMatrix(GG2, G14, nn2-kk2, nn2, kk2, 0, kk2+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG3, G14, nn3-kk3, nn3, kk3, 0, kk2+kk3+nn2-kk2, nn3);
+  //appendBlockMatrix(GGBar2, GGBar3, GBar16, nn2, nn2, nn3, nn3);
+  addSubMatrix(GGBar2, GBar14, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GGBar3, GBar14, kk3, nn3, 0, 0, kk2, nn2);
+  addSubMatrix(GGBar2, GBar14, nn2-kk2, nn2, kk2, 0, kk2+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar3, GBar14, nn3-kk3, nn3, kk3, 0, kk2+kk3+nn2-kk2, nn3);
+  appendVector(hh2, hh3, h14, nn2, nn3);
+  Q14 = (QQ3+QQ2);
+  appendVector(DD2, DD3, D14, kk2, kk3);
+  appendBlockMatrix(JJ2, JJ3, J14, kk2, kk2, kk3, kk3);
+
+  // e6 * e6
+  int n15 = nn3+nn3; int k15 = kk3+kk3; int **G15; int **GBar15; int *h15; int Q15; int *D15; int **J15;
+  G15 = calloc(nn3+nn3,sizeof(int*));
+  GBar15 = calloc(nn3+nn3,sizeof(int*));
+  h15 = calloc(nn3+nn3,sizeof(int));
+  D15 = calloc(kk3+kk3,sizeof(int));
+  J15 = calloc(kk3+kk3,sizeof(int*));
+  for(i=0; i<nn3+nn3; i++) {
+    G15[i] = calloc(nn3+nn3, sizeof(int)); GBar15[i] = calloc(nn3+nn3, sizeof(int));
+  }
+  for(i=0; i<kk3+kk3; i++)
+     J15[i] = calloc(kk3+kk3, sizeof(int));
+  //appendBlockMatrix(GG3, GG3, G17, nn3, nn3, nn3, nn3);
+  addSubMatrix(GG3, G15, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GG3, G15, kk3, nn3, 0, 0, kk3, nn3);
+  addSubMatrix(GG3, G15, nn3-kk3, nn3, kk3, 0, kk3+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG3, G15, nn3-kk3, nn3, kk3, 0, kk3+kk3+nn3-kk3, nn3);
+  //appendBlockMatrix(GGBar3, GGBar3, GBar17, nn3, nn3, nn3, nn3);
+  addSubMatrix(GGBar3, GBar15, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GGBar3, GBar15, kk3, nn3, 0, 0, kk3, nn3);
+  addSubMatrix(GGBar3, GBar15, nn3-kk3, nn3, kk3, 0, kk3+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar3, GBar15, nn3-kk3, nn3, kk3, 0, kk3+kk3+nn3-kk3, nn3);
+  appendVector(hh3, hh3, h15, nn3, nn3);
+  Q15 = (QQ3+QQ3);
+  appendVector(DD3, DD3, D15, kk3, kk3);
+  appendBlockMatrix(JJ3, JJ3, J15, kk3, kk3, kk3, kk3);
+
+  // o6 * e6
+  /*int n18 = nn3+nn4; int k18 = kk3+kk4; int **G18; int **GBar18; int *h18; int Q18; int *D18; int **J18;
+  G18 = calloc(nn3+nn4,sizeof(int*));
+  GBar18 = calloc(nn3+nn4,sizeof(int*));
+  h18 = calloc(nn3+nn4,sizeof(int));
+  D18 = calloc(kk3+kk4,sizeof(int));
+  J18 = calloc(kk3+kk4,sizeof(int*));
+  for(i=0; i<nn3+nn4; i++) {
+    G18[i] = calloc(nn3+nn4, sizeof(int)); GBar18[i] = calloc(nn3+nn4, sizeof(int));
+  }
+  for(i=0; i<kk3+kk4; i++)
+     J18[i] = calloc(kk3+kk4, sizeof(int));
+  //appendBlockMatrix(GG4, GG3, G18, nn4, nn4, nn3, nn3);
+  addSubMatrix(GG4, G18, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GG3, G18, kk3, nn3, 0, 0, kk4, nn4);
+  addSubMatrix(GG4, G18, nn4-kk4, nn4, kk4, 0, kk4+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG3, G18, nn3-kk3, nn3, kk3, 0, kk4+kk3+nn4-kk4, nn3);
+  //appendBlockMatrix(GGBar4, GGBar3, GBar18, nn4, nn4, nn3, nn3);
+  addSubMatrix(GGBar4, GBar18, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GGBar3, GBar18, kk3, nn3, 0, 0, kk4, nn4);
+  addSubMatrix(GGBar4, GBar18, nn4-kk4, nn4, kk4, 0, kk4+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar3, GBar18, nn3-kk3, nn3, kk3, 0, kk4+kk3+nn4-kk4, nn3);
+  appendVector(hh4, hh3, h18, nn4, nn3);
+  Q18 = (QQ3+QQ4);
+  appendVector(DD4, DD3, D18, kk4, kk3);
+  appendBlockMatrix(JJ4, JJ3, J18, kk4, kk4, kk3, kk3);*/
+
+  // k6 * e6
+  int n16 = nn3+nn5; int k16 = kk3+kk5; int **G16; int **GBar16; int *h16; int Q16; int *D16; int **J16;
+  G16 = calloc(nn3+nn5,sizeof(int*));
+  GBar16 = calloc(nn3+nn5,sizeof(int*));
+  h16 = calloc(nn3+nn5,sizeof(int));
+  D16 = calloc(kk3+kk5,sizeof(int));
+  J16 = calloc(kk3+kk5,sizeof(int*));
+  for(i=0; i<nn3+nn5; i++) {
+    G16[i] = calloc(nn3+nn5, sizeof(int)); GBar16[i] = calloc(nn3+nn5, sizeof(int));
+  }
+  for(i=0; i<kk3+kk5; i++)
+     J16[i] = calloc(kk3+kk5, sizeof(int));
+  //appendBlockMatrix(GG5, GG3, G19, nn5, nn5, nn3, nn3);
+  addSubMatrix(GG5, G16, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GG3, G16, kk3, nn3, 0, 0, kk5, nn5);
+  addSubMatrix(GG5, G16, nn5-kk5, nn5, kk5, 0, kk5+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG3, G16, nn3-kk3, nn3, kk3, 0, kk5+kk3+nn5-kk5, nn3);
+  //appendBlockMatrix(GGBar5, GGBar3, GBar19, nn5, nn5, nn3, nn3);
+  addSubMatrix(GGBar5, GBar16, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GGBar3, GBar16, kk3, nn3, 0, 0, kk5, nn5);
+  addSubMatrix(GGBar5, GBar16, nn5-kk5, nn5, kk5, 0, kk5+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar3, GBar16, nn3-kk3, nn3, kk3, 0, kk5+kk3+nn5-kk5, nn3);
+  appendVector(hh5, hh3, h16, nn5, nn3);
+  Q16 = (QQ3+QQ5);
+  appendVector(DD5, DD3, D16, kk5, kk3);
+  appendBlockMatrix(JJ5, JJ3, J16, kk5, kk5, kk3, kk3);
+  
+  // phiprime * e6
+  int n17 = nn3+nn6; int k17 = kk3+kk6; int **G17; int **GBar17; int *h17; int Q17; int *D17; int **J17;
+  G17 = calloc(nn3+nn6,sizeof(int*));
+  GBar17 = calloc(nn3+nn6,sizeof(int*));
+  h17 = calloc(nn3+nn6,sizeof(int));
+  D17 = calloc(kk3+kk6,sizeof(int));
+  J17 = calloc(kk3+kk6,sizeof(int*));
+  for(i=0; i<nn3+nn6; i++) {
+    G17[i] = calloc(nn3+nn6, sizeof(int)); GBar17[i] = calloc(nn3+nn6, sizeof(int));
+  }
+  for(i=0; i<kk3+kk6; i++)
+     J17[i] = calloc(kk3+kk6, sizeof(int));
+  //appendBlockMatrix(GG6, GG3, G20, nn6, nn6, nn3, nn3);
+  addSubMatrix(GG6, G17, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GG3, G17, kk3, nn3, 0, 0, kk6, nn6);
+  addSubMatrix(GG6, G17, nn6-kk6, nn6, kk6, 0, kk6+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG3, G17, nn3-kk3, nn3, kk3, 0, kk6+kk3+nn6-kk6, nn3);
+  //appendBlockMatrix(GGBar6, GGBar3, GBar20, nn6, nn6, nn3, nn3);
+  addSubMatrix(GGBar6, GBar17, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GGBar3, GBar17, kk3, nn3, 0, 0, kk6, nn6);
+  addSubMatrix(GGBar6, GBar17, nn6-kk6, nn6, kk6, 0, kk6+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar3, GBar17, nn3-kk3, nn3, kk3, 0, kk6+kk3+nn6-kk6, nn3);
+  appendVector(hh6, hh3, h17, nn6, nn3);
+  Q17 = (QQ3+QQ6);
+  appendVector(DD6, DD3, D17, kk6, kk3);
+  appendBlockMatrix(JJ6, JJ3, J17, kk6, kk6, kk3, kk3);
+
+  // phidprime * e6
+  int n18 = nn3+nn7; int k18 = kk3+kk7; int **G18; int **GBar18; int *h18; int Q18; int *D18; int **J18;
+  G18 = calloc(nn3+nn7,sizeof(int*));
+  GBar18 = calloc(nn3+nn7,sizeof(int*));
+  h18 = calloc(nn3+nn7,sizeof(int));
+  D18 = calloc(kk3+kk7,sizeof(int));
+  J18 = calloc(kk3+kk7,sizeof(int*));
+  for(i=0; i<nn3+nn7; i++) {
+    G18[i] = calloc(nn3+nn7, sizeof(int)); GBar18[i] = calloc(nn3+nn7, sizeof(int));
+  }
+  for(i=0; i<kk3+kk7; i++)
+     J18[i] = calloc(kk3+kk7, sizeof(int));
+  //appendBlockMatrix(GG7, GG3, G21, nn7, nn7, nn3, nn3);
+  addSubMatrix(GG7, G18, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GG3, G18, kk3, nn3, 0, 0, kk7, nn7);
+  addSubMatrix(GG7, G18, nn7-kk7, nn7, kk7, 0, kk7+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG3, G18, nn3-kk3, nn3, kk3, 0, kk7+kk3+nn7-kk7, nn3);
+  //appendBlockMatrix(GGBar7, GGBar3, GBar21, nn7, nn7, nn3, nn3);
+  addSubMatrix(GGBar7, GBar18, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GGBar3, GBar18, kk3, nn3, 0, 0, kk7, nn7);
+  addSubMatrix(GGBar7, GBar18, nn7-kk7, nn7, kk7, 0, kk7+kk3, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar3, GBar18, nn3-kk3, nn3, kk3, 0, kk7+kk3+nn7-kk7, nn3);
+  appendVector(hh7, hh3, h18, nn7, nn3);
+  Q18 = (QQ3+QQ7);
+  appendVector(DD7, DD3, D18, kk7, kk3);
+  appendBlockMatrix(JJ7, JJ3, J18, kk7, kk7, kk3, kk3);
+
+  // b60 * o6
+  int n19 = nn4+nn1; int k19 = kk4+kk1; int **G19; int **GBar19; int *h19; int Q19; int *D19; int **J19;
+  G19 = calloc(nn4+nn1,sizeof(int*));
+  GBar19 = calloc(nn4+nn1,sizeof(int*));
+  h19 = calloc(nn4+nn1,sizeof(int));
+  D19 = calloc(kk4+kk1,sizeof(int));
+  J19 = calloc(kk4+kk1,sizeof(int*));
+  for(i=0; i<nn4+nn1; i++) {
+    G19[i] = calloc(nn4+nn1, sizeof(int)); GBar19[i] = calloc(nn4+nn1, sizeof(int));
+  }
+  for(i=0; i<kk4+kk1; i++)
+     J19[i] = calloc(kk4+kk1, sizeof(int));
+  //appendBlockMatrix(GG1, GG4, G22, nn1, nn1, nn4, nn4);
+  addSubMatrix(GG1, G19, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GG4, G19, kk4, nn4, 0, 0, kk1, nn1);
+  addSubMatrix(GG1, G19, nn1-kk1, nn1, kk1, 0, kk1+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG4, G19, nn4-kk4, nn4, kk4, 0, kk1+kk4+nn1-kk1, nn4);
+  //appendBlockMatrix(GGBar1, GGBar4, GBar22, nn1, nn1, nn4, nn4);
+  addSubMatrix(GGBar1, GBar19, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GGBar4, GBar19, kk4, nn4, 0, 0, kk1, nn1);
+  addSubMatrix(GGBar1, GBar19, nn1-kk1, nn1, kk1, 0, kk1+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar4, GBar19, nn4-kk4, nn4, kk4, 0, kk1+kk4+nn1-kk1, nn4);
+  appendVector(hh1, hh4, h19, nn1, nn4);
+  Q19 = (QQ4+QQ1);
+  appendVector(DD1, DD4, D19, kk1, kk4);
+  appendBlockMatrix(JJ1, JJ4, J19, kk1, kk1, kk4, kk4);
+
+  // b66 * o6
+  int n20 = nn4+nn2; int k20 = kk4+kk2; int **G20; int **GBar20; int *h20; int Q20; int *D20; int **J20;
+  G20 = calloc(nn4+nn2,sizeof(int*));
+  GBar20 = calloc(nn4+nn2,sizeof(int*));
+  h20 = calloc(nn4+nn2,sizeof(int));
+  D20 = calloc(kk4+kk2,sizeof(int));
+  J20 = calloc(kk4+kk2,sizeof(int*));
+  for(i=0; i<nn4+nn2; i++) {
+    G20[i] = calloc(nn4+nn2, sizeof(int)); GBar20[i] = calloc(nn4+nn2, sizeof(int));
+  }
+  for(i=0; i<kk4+kk2; i++)
+     J20[i] = calloc(kk4+kk2, sizeof(int));
+  //appendBlockMatrix(GG2, GG4, G23, nn2, nn2, nn4, nn4);
+  addSubMatrix(GG2, G20, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GG4, G20, kk4, nn4, 0, 0, kk2, nn2);
+  addSubMatrix(GG2, G20, nn2-kk2, nn2, kk2, 0, kk2+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG4, G20, nn4-kk4, nn4, kk4, 0, kk2+kk4+nn2-kk2, nn4);
+  //appendBlockMatrix(GGBar2, GGBar4, GBar23, nn2, nn2, nn4, nn4);
+  addSubMatrix(GGBar2, GBar20, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GGBar4, GBar20, kk4, nn4, 0, 0, kk2, nn2);
+  addSubMatrix(GGBar2, GBar20, nn2-kk2, nn2, kk2, 0, kk2+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar4, GBar20, nn4-kk4, nn4, kk4, 0, kk2+kk4+nn2-kk2, nn4);
+  appendVector(hh2, hh4, h20, nn2, nn4);
+  Q20 = (QQ4+QQ2);
+  appendVector(DD2, DD4, D20, kk2, kk4);
+  appendBlockMatrix(JJ2, JJ4, J20, kk2, kk2, kk4, kk4);
+  
+  // e6 * o6
+  /*int n24 = nn4+nn3; int k24 = kk4+kk3; int **G24; int **GBar24; int *h24; int Q24; int *D24; int **J24;
+  G24 = calloc(nn4+nn3,sizeof(int*));
+  GBar24 = calloc(nn4+nn3,sizeof(int*));
+  h24 = calloc(nn4+nn3,sizeof(int));
+  D24 = calloc(kk4+kk3,sizeof(int));
+  J24 = calloc(kk4+kk3,sizeof(int*));
+  for(i=0; i<nn4+nn3; i++) {
+    G24[i] = calloc(nn4+nn3, sizeof(int)); GBar24[i] = calloc(nn4+nn3, sizeof(int));
+  }
+  for(i=0; i<kk4+kk3; i++)
+     J24[i] = calloc(kk4+kk3, sizeof(int));
+  //appendBlockMatrix(GG3, GG4, G24, nn3, nn3, nn4, nn4);
+  addSubMatrix(GG3, G24, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GG4, G24, kk4, nn4, 0, 0, kk3, nn3);
+  addSubMatrix(GG3, G24, nn3-kk3, nn3, kk3, 0, kk3+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG4, G24, nn4-kk4, nn4, kk4, 0, kk3+kk4+nn3-kk3, nn4);
+  //appendBlockMatrix(GGBar3, GGBar4, GBar24, nn3, nn3, nn4, nn4);
+  addSubMatrix(GGBar3, GBar24, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GGBar4, GBar24, kk4, nn4, 0, 0, kk3, nn3);
+  addSubMatrix(GGBar3, GBar24, nn3-kk3, nn3, kk3, 0, kk3+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar4, GBar24, nn4-kk4, nn4, kk4, 0, kk3+kk4+nn3-kk3, nn4);
+  appendVector(hh3, hh4, h24, nn3, nn4);
+  Q24 = (QQ4+QQ3);
+  appendVector(DD3, DD4, D24, kk3, kk4);
+  appendBlockMatrix(JJ3, JJ4, J24, kk3, kk3, kk4, kk4);*/
+
+  // o6 * o6
+  int n21 = nn4+nn4; int k21 = kk4+kk4; int **G21; int **GBar21; int *h21; int Q21; int *D21; int **J21;
+  G21 = calloc(nn4+nn4,sizeof(int*));
+  GBar21 = calloc(nn4+nn4,sizeof(int*));
+  h21 = calloc(nn4+nn4,sizeof(int));
+  D21 = calloc(kk4+kk4,sizeof(int));
+  J21 = calloc(kk4+kk4,sizeof(int*));
+  for(i=0; i<nn4+nn4; i++) {
+    G21[i] = calloc(nn4+nn4, sizeof(int)); GBar21[i] = calloc(nn4+nn4, sizeof(int));
+  }
+  for(i=0; i<kk4+kk4; i++)
+     J21[i] = calloc(kk4+kk4, sizeof(int));
+  //appendBlockMatrix(GG4, GG4, G25, nn4, nn4, nn4, nn4);
+  addSubMatrix(GG4, G21, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GG4, G21, kk4, nn4, 0, 0, kk4, nn4);
+  addSubMatrix(GG4, G21, nn4-kk4, nn4, kk4, 0, kk4+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG4, G21, nn4-kk4, nn4, kk4, 0, kk4+kk4+nn4-kk4, nn4);
+  //appendBlockMatrix(GGBar4, GGBar4, GBar25, nn4, nn4, nn4, nn4);
+  addSubMatrix(GGBar4, GBar21, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GGBar4, GBar21, kk4, nn4, 0, 0, kk4, nn4);
+  addSubMatrix(GGBar4, GBar21, nn4-kk4, nn4, kk4, 0, kk4+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar4, GBar21, nn4-kk4, nn4, kk4, 0, kk4+kk4+nn4-kk4, nn4);
+  appendVector(hh4, hh4, h21, nn4, nn4);
+  Q21 = (QQ4+QQ4);
+  appendVector(DD4, DD4, D21, kk4, kk4);
+  appendBlockMatrix(JJ4, JJ4, J21, kk4, kk4, kk4, kk4);
+
+  // k6 * o6
+  int n22 = nn4+nn5; int k22 = kk4+kk5; int **G22; int **GBar22; int *h22; int Q22; int *D22; int **J22;
+  G22 = calloc(nn4+nn5,sizeof(int*));
+  GBar22 = calloc(nn4+nn5,sizeof(int*));
+  h22 = calloc(nn4+nn5,sizeof(int));
+  D22 = calloc(kk4+kk5,sizeof(int));
+  J22 = calloc(kk4+kk5,sizeof(int*));
+  for(i=0; i<nn4+nn5; i++) {
+    G22[i] = calloc(nn4+nn5, sizeof(int)); GBar22[i] = calloc(nn4+nn5, sizeof(int));
+  }
+  for(i=0; i<kk4+kk5; i++)
+     J22[i] = calloc(kk4+kk5, sizeof(int));
+  //appendBlockMatrix(GG5, GG4, G26, nn5, nn5, nn4, nn4);
+  addSubMatrix(GG5, G22, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GG4, G22, kk4, nn4, 0, 0, kk5, nn5);
+  addSubMatrix(GG5, G22, nn5-kk5, nn5, kk5, 0, kk5+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG4, G22, nn4-kk4, nn4, kk4, 0, kk5+kk4+nn5-kk5, nn4);
+  //appendBlockMatrix(GGBar5, GGBar4, GBar26, nn5, nn5, nn4, nn4);
+  addSubMatrix(GGBar5, GBar22, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GGBar4, GBar22, kk4, nn4, 0, 0, kk5, nn5);
+  addSubMatrix(GGBar5, GBar22, nn5-kk5, nn5, kk5, 0, kk5+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar4, GBar22, nn4-kk4, nn4, kk4, 0, kk5+kk4+nn5-kk5, nn4);
+  appendVector(hh5, hh4, h22, nn5, nn4);
+  Q22 = (QQ4+QQ5);
+  appendVector(DD5, DD4, D22, kk5, kk4);
+  appendBlockMatrix(JJ5, JJ4, J22, kk5, kk5, kk4, kk4);
+  
+  // phiprime * o6
+  int n23 = nn4+nn6; int k23 = kk4+kk6; int **G23; int **GBar23; int *h23; int Q23; int *D23; int **J23;
+  G23 = calloc(nn4+nn6,sizeof(int*));
+  GBar23 = calloc(nn4+nn6,sizeof(int*));
+  h23 = calloc(nn4+nn6,sizeof(int));
+  D23 = calloc(kk4+kk6,sizeof(int));
+  J23 = calloc(kk4+kk6,sizeof(int*));
+  for(i=0; i<nn4+nn6; i++) {
+    G23[i] = calloc(nn4+nn6, sizeof(int)); GBar23[i] = calloc(nn4+nn6, sizeof(int));
+  }
+  for(i=0; i<kk4+kk6; i++)
+     J23[i] = calloc(kk4+kk6, sizeof(int));
+  //appendBlockMatrix(GG6, GG4, G27, nn6, nn6, nn4, nn4);
+  addSubMatrix(GG6, G23, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GG4, G23, kk4, nn4, 0, 0, kk6, nn6);
+  addSubMatrix(GG6, G23, nn6-kk6, nn6, kk6, 0, kk6+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG4, G23, nn4-kk4, nn4, kk4, 0, kk6+kk4+nn6-kk6, nn4);
+  //appendBlockMatrix(GGBar6, GGBar4, GBar27, nn6, nn6, nn4, nn4);
+  addSubMatrix(GGBar6, GBar23, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GGBar4, GBar23, kk4, nn4, 0, 0, kk6, nn6);
+  addSubMatrix(GGBar6, GBar23, nn6-kk6, nn6, kk6, 0, kk6+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar4, GBar23, nn4-kk4, nn4, kk4, 0, kk6+kk4+nn6-kk6, nn4);
+  appendVector(hh6, hh4, h23, nn6, nn4);
+  Q23 = (QQ4+QQ6);
+  appendVector(DD6, DD4, D23, kk6, kk4);
+  appendBlockMatrix(JJ6, JJ4, J23, kk6, kk6, kk4, kk4);
+
+  // phidprime * o6
+  int n24 = nn4+nn7; int k24 = kk4+kk7; int **G24; int **GBar24; int *h24; int Q24; int *D24; int **J24;
+  G24 = calloc(nn4+nn7,sizeof(int*));
+  GBar24 = calloc(nn4+nn7,sizeof(int*));
+  h24 = calloc(nn4+nn7,sizeof(int));
+  D24 = calloc(kk4+kk7,sizeof(int));
+  J24 = calloc(kk4+kk7,sizeof(int*));
+  for(i=0; i<nn4+nn7; i++) {
+    G24[i] = calloc(nn4+nn7, sizeof(int)); GBar24[i] = calloc(nn4+nn7, sizeof(int));
+  }
+  for(i=0; i<kk4+kk7; i++)
+     J24[i] = calloc(kk4+kk7, sizeof(int));
+  //appendBlockMatrix(GG7, GG4, G28, nn7, nn7, nn4, nn4);
+  addSubMatrix(GG7, G24, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GG4, G24, kk4, nn4, 0, 0, kk7, nn7);
+  addSubMatrix(GG7, G24, nn7-kk7, nn7, kk7, 0, kk7+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG4, G24, nn4-kk4, nn4, kk4, 0, kk7+kk4+nn7-kk7, nn4);
+  //appendBlockMatrix(GGBar7, GGBar4, GBar28, nn7, nn7, nn4, nn4);
+  addSubMatrix(GGBar7, GBar24, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GGBar4, GBar24, kk4, nn4, 0, 0, kk7, nn7);
+  addSubMatrix(GGBar7, GBar24, nn7-kk7, nn7, kk7, 0, kk7+kk4, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar4, GBar24, nn4-kk4, nn4, kk4, 0, kk7+kk4+nn7-kk7, nn4);
+  appendVector(hh7, hh4, h24, nn7, nn4);
+  Q24 = (QQ4+QQ7);
+  appendVector(DD7, DD4, D24, kk7, kk4);
+  appendBlockMatrix(JJ7, JJ4, J24, kk7, kk7, kk4, kk4);
+
+  // b60 * k6
+  int n25 = nn5+nn1; int k25 = kk5+kk1; int **G25; int **GBar25; int *h25; int Q25; int *D25; int **J25;
+  G25 = calloc(nn5+nn1,sizeof(int*));
+  GBar25 = calloc(nn5+nn1,sizeof(int*));
+  h25 = calloc(nn5+nn1,sizeof(int));
+  D25 = calloc(kk5+kk1,sizeof(int));
+  J25 = calloc(kk5+kk1,sizeof(int*));
+  for(i=0; i<nn5+nn1; i++) {
+    G25[i] = calloc(nn5+nn1, sizeof(int)); GBar25[i] = calloc(nn5+nn1, sizeof(int));
+  }
+  for(i=0; i<kk5+kk1; i++)
+     J25[i] = calloc(kk5+kk1, sizeof(int));
+  //appendBlockMatrix(GG1, GG5, G29, nn1, nn1, nn5, nn5);
+  addSubMatrix(GG1, G25, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GG5, G25, kk5, nn5, 0, 0, kk1, nn1);
+  addSubMatrix(GG1, G25, nn1-kk1, nn1, kk1, 0, kk1+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG5, G25, nn5-kk5, nn5, kk5, 0, kk1+kk5+nn1-kk1, nn5);
+  //appendBlockMatrix(GGBar1, GGBar5, GBar29, nn1, nn1, nn5, nn5);
+  addSubMatrix(GGBar1, GBar25, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GGBar5, GBar25, kk5, nn5, 0, 0, kk1, nn1);
+  addSubMatrix(GGBar1, GBar25, nn1-kk1, nn1, kk1, 0, kk1+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar5, GBar25, nn5-kk5, nn5, kk5, 0, kk1+kk5+nn1-kk1, nn5);
+  appendVector(hh1, hh5, h25, nn1, nn5);
+  Q25 = (QQ5+QQ1);
+  appendVector(DD1, DD5, D25, kk1, kk5);
+  appendBlockMatrix(JJ1, JJ5, J25, kk1, kk1, kk5, kk5);
+
+  // b66 * k6
+  int n26 = nn5+nn2; int k26 = kk5+kk2; int **G26; int **GBar26; int *h26; int Q26; int *D26; int **J26;
+  G26 = calloc(nn5+nn2,sizeof(int*));
+  GBar26 = calloc(nn5+nn2,sizeof(int*));
+  h26 = calloc(nn5+nn2,sizeof(int));
+  D26 = calloc(kk5+kk2,sizeof(int));
+  J26 = calloc(kk5+kk2,sizeof(int*));
+  for(i=0; i<nn5+nn2; i++) {
+    G26[i] = calloc(nn5+nn2, sizeof(int)); GBar26[i] = calloc(nn5+nn2, sizeof(int));
+  }
+  for(i=0; i<kk5+kk2; i++)
+     J26[i] = calloc(kk5+kk2, sizeof(int));
+  //appendBlockMatrix(GG2, GG5, G30, nn2, nn2, nn5, nn5);
+  addSubMatrix(GG2, G26, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GG5, G26, kk5, nn5, 0, 0, kk2, nn2);
+  addSubMatrix(GG2, G26, nn2-kk2, nn2, kk2, 0, kk2+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG5, G26, nn5-kk5, nn5, kk5, 0, kk2+kk5+nn2-kk2, nn5);
+  //appendBlockMatrix(GGBar2, GGBar5, GBar30, nn2, nn2, nn5, nn5);
+  addSubMatrix(GGBar2, GBar26, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GGBar5, GBar26, kk5, nn5, 0, 0, kk2, nn2);
+  addSubMatrix(GGBar2, GBar26, nn2-kk2, nn2, kk2, 0, kk2+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar5, GBar26, nn5-kk5, nn5, kk5, 0, kk2+kk5+nn2-kk2, nn5);
+  appendVector(hh2, hh5, h26, nn2, nn5);
+  Q26 = (QQ5+QQ2);
+  appendVector(DD2, DD5, D26, kk2, kk5);
+  appendBlockMatrix(JJ2, JJ5, J26, kk2, kk2, kk5, kk5);
+  
+  // e6 * k6
+  int n27 = nn5+nn3; int k27 = kk5+kk3; int **G27; int **GBar27; int *h27; int Q27; int *D27; int **J27;
+  G27 = calloc(nn5+nn3,sizeof(int*));
+  GBar27 = calloc(nn5+nn3,sizeof(int*));
+  h27 = calloc(nn5+nn3,sizeof(int));
+  D27 = calloc(kk5+kk3,sizeof(int));
+  J27 = calloc(kk5+kk3,sizeof(int*));
+  for(i=0; i<nn5+nn3; i++) {
+    G27[i] = calloc(nn5+nn3, sizeof(int)); GBar27[i] = calloc(nn5+nn3, sizeof(int));
+  }
+  for(i=0; i<kk5+kk3; i++)
+     J27[i] = calloc(kk5+kk3, sizeof(int));
+  //appendBlockMatrix(GG3, GG5, G31, nn3, nn3, nn5, nn5);
+  addSubMatrix(GG3, G27, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GG5, G27, kk5, nn5, 0, 0, kk3, nn3);
+  addSubMatrix(GG3, G27, nn3-kk3, nn3, kk3, 0, kk3+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG5, G27, nn5-kk5, nn5, kk5, 0, kk3+kk5+nn3-kk3, nn5);
+  //appendBlockMatrix(GGBar3, GGBar5, GBar31, nn3, nn3, nn5, nn5);
+  addSubMatrix(GGBar3, GBar27, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GGBar5, GBar27, kk5, nn5, 0, 0, kk3, nn3);
+  addSubMatrix(GGBar3, GBar27, nn3-kk3, nn3, kk3, 0, kk3+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar5, GBar27, nn5-kk5, nn5, kk5, 0, kk3+kk5+nn3-kk3, nn5);
+  appendVector(hh3, hh5, h27, nn3, nn5);
+  Q27 = (QQ5+QQ3);
+  appendVector(DD3, DD5, D27, kk3, kk5);
+  appendBlockMatrix(JJ3, JJ5, J27, kk3, kk3, kk5, kk5);
+
+  // o6 * k6
+  int n28 = nn5+nn4; int k28 = kk5+kk4; int **G28; int **GBar28; int *h28; int Q28; int *D28; int **J28;
+  G28 = calloc(nn5+nn4,sizeof(int*));
+  GBar28 = calloc(nn5+nn4,sizeof(int*));
+  h28 = calloc(nn5+nn4,sizeof(int));
+  D28 = calloc(kk5+kk4,sizeof(int));
+  J28 = calloc(kk5+kk4,sizeof(int*));
+  for(i=0; i<nn5+nn4; i++) {
+    G28[i] = calloc(nn5+nn4, sizeof(int)); GBar28[i] = calloc(nn5+nn4, sizeof(int));
+  }
+  for(i=0; i<kk5+kk4; i++)
+     J28[i] = calloc(kk5+kk4, sizeof(int));
+  //appendBlockMatrix(GG4, GG5, G32, nn4, nn4, nn5, nn5);
+  addSubMatrix(GG4, G28, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GG5, G28, kk5, nn5, 0, 0, kk4, nn4);
+  addSubMatrix(GG4, G28, nn4-kk4, nn4, kk4, 0, kk4+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG5, G28, nn5-kk5, nn5, kk5, 0, kk4+kk5+nn4-kk4, nn5);
+  //appendBlockMatrix(GGBar4, GGBar5, GBar32, nn4, nn4, nn5, nn5);
+  addSubMatrix(GGBar4, GBar28, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GGBar5, GBar28, kk5, nn5, 0, 0, kk4, nn4);
+  addSubMatrix(GGBar4, GBar28, nn4-kk4, nn4, kk4, 0, kk4+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar5, GBar28, nn5-kk5, nn5, kk5, 0, kk4+kk5+nn4-kk4, nn5);
+  appendVector(hh4, hh5, h28, nn4, nn5);
+  Q28 = (QQ5+QQ4);
+  appendVector(DD4, DD5, D28, kk4, kk5);
+  appendBlockMatrix(JJ4, JJ5, J28, kk4, kk4, kk5, kk5);
+
+  // k6 * k6
+  int n29 = nn5+nn5; int k29 = kk5+kk5; int **G29; int **GBar29; int *h29; int Q29; int *D29; int **J29;
+  G29 = calloc(nn5+nn5,sizeof(int*));
+  GBar29 = calloc(nn5+nn5,sizeof(int*));
+  h29 = calloc(nn5+nn5,sizeof(int));
+  D29 = calloc(kk5+kk5,sizeof(int));
+  J29 = calloc(kk5+kk5,sizeof(int*));
+  for(i=0; i<nn5+nn5; i++) {
+    G29[i] = calloc(nn5+nn5, sizeof(int)); GBar29[i] = calloc(nn5+nn5, sizeof(int));
+  }
+  for(i=0; i<kk5+kk5; i++)
+     J29[i] = calloc(kk5+kk5, sizeof(int));
+  //appendBlockMatrix(GG5, GG5, G33, nn5, nn5, nn5, nn5);
+  addSubMatrix(GG5, G29, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GG5, G29, kk5, nn5, 0, 0, kk5, nn5);
+  addSubMatrix(GG5, G29, nn5-kk5, nn5, kk5, 0, kk5+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG5, G29, nn5-kk5, nn5, kk5, 0, kk5+kk5+nn5-kk5, nn5);
+  //appendBlockMatrix(GGBar5, GGBar5, GBar33, nn5, nn5, nn5, nn5);
+  addSubMatrix(GGBar5, GBar29, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GGBar5, GBar29, kk5, nn5, 0, 0, kk5, nn5);
+  addSubMatrix(GGBar5, GBar29, nn5-kk5, nn5, kk5, 0, kk5+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar5, GBar29, nn5-kk5, nn5, kk5, 0, kk5+kk5+nn5-kk5, nn5);
+  appendVector(hh5, hh5, h29, nn5, nn5);
+  Q29 = (QQ5+QQ5);
+  appendVector(DD5, DD5, D29, kk5, kk5);
+  appendBlockMatrix(JJ5, JJ5, J29, kk5, kk5, kk5, kk5);
+
+  // phiprime * k6
+  int n30 = nn5+nn6; int k30 = kk5+kk6; int **G30; int **GBar30; int *h30; int Q30; int *D30; int **J30;
+  G30 = calloc(nn5+nn6,sizeof(int*));
+  GBar30 = calloc(nn5+nn6,sizeof(int*));
+  h30 = calloc(nn5+nn6,sizeof(int));
+  D30 = calloc(kk5+kk6,sizeof(int));
+  J30 = calloc(kk5+kk6,sizeof(int*));
+  for(i=0; i<nn5+nn6; i++) {
+    G30[i] = calloc(nn5+nn6, sizeof(int)); GBar30[i] = calloc(nn5+nn6, sizeof(int));
+  }
+  for(i=0; i<kk5+kk6; i++)
+     J30[i] = calloc(kk5+kk6, sizeof(int));
+  //appendBlockMatrix(GG6, GG5, G34, nn6, nn6, nn5, nn5);
+  addSubMatrix(GG6, G30, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GG5, G30, kk5, nn5, 0, 0, kk6, nn6);
+  addSubMatrix(GG6, G30, nn6-kk6, nn6, kk6, 0, kk6+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG5, G30, nn5-kk5, nn5, kk5, 0, kk6+kk5+nn6-kk6, nn5);
+  //appendBlockMatrix(GGBar6, GGBar5, GBar34, nn6, nn6, nn5, nn5);
+  addSubMatrix(GGBar6, GBar30, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GGBar5, GBar30, kk5, nn5, 0, 0, kk6, nn6);
+  addSubMatrix(GGBar6, GBar30, nn6-kk6, nn6, kk6, 0, kk6+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar5, GBar30, nn5-kk5, nn5, kk5, 0, kk6+kk5+nn6-kk6, nn5);
+  appendVector(hh6, hh5, h30, nn6, nn5);
+  Q30 = (QQ5+QQ6);
+  appendVector(DD6, DD5, D30, kk6, kk5);
+  appendBlockMatrix(JJ6, JJ5, J30, kk6, kk6, kk5, kk5);
+  
+  // phidprime * k6
+  int n31 = nn5+nn7; int k31 = kk5+kk7; int **G31; int **GBar31; int *h31; int Q31; int *D31; int **J31;
+  G31 = calloc(nn5+nn7,sizeof(int*));
+  GBar31 = calloc(nn5+nn7,sizeof(int*));
+  h31 = calloc(nn5+nn7,sizeof(int));
+  D31 = calloc(kk5+kk7,sizeof(int));
+  J31 = calloc(kk5+kk7,sizeof(int*));
+  for(i=0; i<nn5+nn7; i++) {
+    G31[i] = calloc(nn5+nn7, sizeof(int)); GBar31[i] = calloc(nn5+nn7, sizeof(int));
+  }
+  for(i=0; i<kk5+kk7; i++)
+     J31[i] = calloc(kk5+kk7, sizeof(int));
+  //appendBlockMatrix(GG7, GG5, G35, nn7, nn7, nn5, nn5);
+  addSubMatrix(GG7, G31, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GG5, G31, kk5, nn5, 0, 0, kk7, nn7);
+  addSubMatrix(GG7, G31, nn7-kk7, nn7, kk7, 0, kk7+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG5, G31, nn5-kk5, nn5, kk5, 0, kk7+kk5+nn7-kk7, nn5);
+  //appendBlockMatrix(GGBar7, GGBar5, GBar35, nn7, nn7, nn5, nn5);
+  addSubMatrix(GGBar7, GBar31, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GGBar5, GBar31, kk5, nn5, 0, 0, kk7, nn7);
+  addSubMatrix(GGBar7, GBar31, nn7-kk7, nn7, kk7, 0, kk7+kk5, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar5, GBar31, nn5-kk5, nn5, kk5, 0, kk7+kk5+nn7-kk7, nn5);
+  appendVector(hh7, hh5, h31, nn7, nn5);
+  Q31 = (QQ5+QQ7);
+  appendVector(DD7, DD5, D31, kk7, kk5);
+  appendBlockMatrix(JJ7, JJ5, J31, kk7, kk7, kk5, kk5);
+
+  // b60 * phiprime
+  int n32 = nn6+nn1; int k32 = kk6+kk1; int **G32; int **GBar32; int *h32; int Q32; int *D32; int **J32;
+  G32 = calloc(nn6+nn1,sizeof(int*));
+  GBar32 = calloc(nn6+nn1,sizeof(int*));
+  h32 = calloc(nn6+nn1,sizeof(int));
+  D32 = calloc(kk6+kk1,sizeof(int));
+  J32 = calloc(kk6+kk1,sizeof(int*));
+  for(i=0; i<nn6+nn1; i++) {
+    G32[i] = calloc(nn6+nn1, sizeof(int)); GBar32[i] = calloc(nn6+nn1, sizeof(int));
+  }
+  for(i=0; i<kk6+kk1; i++)
+     J32[i] = calloc(kk6+kk1, sizeof(int));
+  //appendBlockMatrix(GG1, GG6, G36, nn1, nn1, nn6, nn6);
+  addSubMatrix(GG1, G32, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GG6, G32, kk6, nn6, 0, 0, kk1, nn1);
+  addSubMatrix(GG1, G32, nn1-kk1, nn1, kk1, 0, kk1+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG6, G32, nn6-kk6, nn6, kk6, 0, kk1+kk6+nn1-kk1, nn6);
+  //appendBlockMatrix(GGBar1, GGBar6, GBar36, nn1, nn1, nn6, nn6);
+  addSubMatrix(GGBar1, GBar32, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GGBar6, GBar32, kk6, nn6, 0, 0, kk1, nn1);
+  addSubMatrix(GGBar1, GBar32, nn1-kk1, nn1, kk1, 0, kk1+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar6, GBar32, nn6-kk6, nn6, kk6, 0, kk1+kk6+nn1-kk1, nn6);
+  appendVector(hh1, hh6, h32, nn1, nn6);
+  Q32 = (QQ6+QQ1);
+  appendVector(DD1, DD6, D32, kk1, kk6);
+  appendBlockMatrix(JJ1, JJ6, J32, kk1, kk1, kk6, kk6);
+
+  // b66 * phiprime
+  int n33 = nn6+nn2; int k33 = kk6+kk2; int **G33; int **GBar33; int *h33; int Q33; int *D33; int **J33;
+  G33 = calloc(nn6+nn2,sizeof(int*));
+  GBar33 = calloc(nn6+nn2,sizeof(int*));
+  h33 = calloc(nn6+nn2,sizeof(int));
+  D33 = calloc(kk6+kk2,sizeof(int));
+  J33 = calloc(kk6+kk2,sizeof(int*));
+  for(i=0; i<nn6+nn2; i++) {
+    G33[i] = calloc(nn6+nn2, sizeof(int)); GBar33[i] = calloc(nn6+nn2, sizeof(int));
+  }
+  for(i=0; i<kk6+kk2; i++)
+     J33[i] = calloc(kk6+kk2, sizeof(int));
+  //appendBlockMatrix(GG2, GG6, G37, nn2, nn2, nn6, nn6);
+  addSubMatrix(GG2, G33, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GG6, G33, kk6, nn6, 0, 0, kk2, nn2);
+  addSubMatrix(GG2, G33, nn2-kk2, nn2, kk2, 0, kk2+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG6, G33, nn6-kk6, nn6, kk6, 0, kk2+kk6+nn2-kk2, nn6);
+  //appendBlockMatrix(GGBar2, GGBar6, GBar37, nn2, nn2, nn6, nn6);
+  addSubMatrix(GGBar2, GBar33, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GGBar6, GBar33, kk6, nn6, 0, 0, kk2, nn2);
+  addSubMatrix(GGBar2, GBar33, nn2-kk2, nn2, kk2, 0, kk2+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar6, GBar33, nn6-kk6, nn6, kk6, 0, kk2+kk6+nn2-kk2, nn6);
+  appendVector(hh2, hh6, h33, nn2, nn6);
+  Q33 = (QQ6+QQ2);
+  appendVector(DD2, DD6, D33, kk2, kk6);
+  appendBlockMatrix(JJ2, JJ6, J33, kk2, kk2, kk6, kk6);
+
+  // e6 * phiprime
+  int n34 = nn6+nn3; int k34 = kk6+kk3; int **G34; int **GBar34; int *h34; int Q34; int *D34; int **J34;
+  G34 = calloc(nn6+nn3,sizeof(int*));
+  GBar34 = calloc(nn6+nn3,sizeof(int*));
+  h34 = calloc(nn6+nn3,sizeof(int));
+  D34 = calloc(kk6+kk3,sizeof(int));
+  J34 = calloc(kk6+kk3,sizeof(int*));
+  for(i=0; i<nn6+nn3; i++) {
+    G34[i] = calloc(nn6+nn3, sizeof(int)); GBar34[i] = calloc(nn6+nn3, sizeof(int));
+  }
+  for(i=0; i<kk6+kk3; i++)
+     J34[i] = calloc(kk6+kk3, sizeof(int));
+  //appendBlockMatrix(GG3, GG6, G38, nn3, nn3, nn6, nn6);
+  addSubMatrix(GG3, G34, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GG6, G34, kk6, nn6, 0, 0, kk3, nn3);
+  addSubMatrix(GG3, G34, nn3-kk3, nn3, kk3, 0, kk3+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG6, G34, nn6-kk6, nn6, kk6, 0, kk3+kk6+nn3-kk3, nn6);
+  //appendBlockMatrix(GGBar3, GGBar6, GBar38, nn3, nn3, nn6, nn6);
+  addSubMatrix(GGBar3, GBar34, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GGBar6, GBar34, kk6, nn6, 0, 0, kk3, nn3);
+  addSubMatrix(GGBar3, GBar34, nn3-kk3, nn3, kk3, 0, kk3+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar6, GBar34, nn6-kk6, nn6, kk6, 0, kk3+kk6+nn3-kk3, nn6);
+  appendVector(hh3, hh6, h34, nn3, nn6);
+  Q34 = (QQ6+QQ3);
+  appendVector(DD3, DD6, D34, kk3, kk6);
+  appendBlockMatrix(JJ3, JJ6, J34, kk3, kk3, kk6, kk6);
+
+  // o6 * phiprime
+  int n35 = nn6+nn4; int k35 = kk6+kk4; int **G35; int **GBar35; int *h35; int Q35; int *D35; int **J35;
+  G35 = calloc(nn6+nn4,sizeof(int*));
+  GBar35 = calloc(nn6+nn4,sizeof(int*));
+  h35 = calloc(nn6+nn4,sizeof(int));
+  D35 = calloc(kk6+kk4,sizeof(int));
+  J35 = calloc(kk6+kk4,sizeof(int*));
+  for(i=0; i<nn6+nn4; i++) {
+    G35[i] = calloc(nn6+nn4, sizeof(int)); GBar35[i] = calloc(nn6+nn4, sizeof(int));
+  }
+  for(i=0; i<kk6+kk4; i++)
+     J35[i] = calloc(kk6+kk4, sizeof(int));
+  //appendBlockMatrix(GG4, GG6, G39, nn4, nn4, nn6, nn6);
+  addSubMatrix(GG4, G35, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GG6, G35, kk6, nn6, 0, 0, kk4, nn4);
+  addSubMatrix(GG4, G35, nn4-kk4, nn4, kk4, 0, kk4+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG6, G35, nn6-kk6, nn6, kk6, 0, kk4+kk6+nn4-kk4, nn6);
+  //appendBlockMatrix(GGBar4, GGBar6, GBar39, nn4, nn4, nn6, nn6);
+  addSubMatrix(GGBar4, GBar35, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GGBar6, GBar35, kk6, nn6, 0, 0, kk4, nn4);
+  addSubMatrix(GGBar4, GBar35, nn4-kk4, nn4, kk4, 0, kk4+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar6, GBar35, nn6-kk6, nn6, kk6, 0, kk4+kk6+nn4-kk4, nn6);
+  appendVector(hh4, hh6, h35, nn4, nn6);
+  Q35 = (QQ6+QQ4);
+  appendVector(DD4, DD6, D35, kk4, kk6);
+  appendBlockMatrix(JJ4, JJ6, J35, kk4, kk4, kk6, kk6);
+
+  // k6 * phiprime
+  int n36 = nn6+nn5; int k36 = kk6+kk5; int **G36; int **GBar36; int *h36; int Q36; int *D36; int **J36;
+  G36 = calloc(nn6+nn5,sizeof(int*));
+  GBar36 = calloc(nn6+nn5,sizeof(int*));
+  h36 = calloc(nn6+nn5,sizeof(int));
+  D36 = calloc(kk6+kk5,sizeof(int));
+  J36 = calloc(kk6+kk5,sizeof(int*));
+  for(i=0; i<nn6+nn5; i++) {
+    G36[i] = calloc(nn6+nn5, sizeof(int)); GBar36[i] = calloc(nn6+nn5, sizeof(int));
+  }
+  for(i=0; i<kk6+kk5; i++)
+     J36[i] = calloc(kk6+kk5, sizeof(int));
+  //appendBlockMatrix(GG5, GG6, G40, nn5, nn5, nn6, nn6);
+  addSubMatrix(GG5, G36, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GG6, G36, kk6, nn6, 0, 0, kk5, nn5);
+  addSubMatrix(GG5, G36, nn5-kk5, nn5, kk5, 0, kk5+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG6, G36, nn6-kk6, nn6, kk6, 0, kk5+kk6+nn5-kk5, nn6);
+  //appendBlockMatrix(GGBar5, GGBar6, GBar40, nn5, nn5, nn6, nn6);
+  addSubMatrix(GGBar5, GBar36, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GGBar6, GBar36, kk6, nn6, 0, 0, kk5, nn5);
+  addSubMatrix(GGBar5, GBar36, nn5-kk5, nn5, kk5, 0, kk5+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar6, GBar36, nn6-kk6, nn6, kk6, 0, kk5+kk6+nn5-kk5, nn6);
+  appendVector(hh5, hh6, h36, nn5, nn6);
+  Q36 = (QQ6+QQ5);
+  appendVector(DD5, DD6, D36, kk5, kk6);
+  appendBlockMatrix(JJ5, JJ6, J36, kk5, kk5, kk6, kk6);
+
+  // phiprime * phiprime
+  int n37 = nn6+nn6; int k37 = kk6+kk6; int **G37; int **GBar37; int *h37; int Q37; int *D37; int **J37;
+  G37 = calloc(nn6+nn6,sizeof(int*));
+  GBar37 = calloc(nn6+nn6,sizeof(int*));
+  h37 = calloc(nn6+nn6,sizeof(int));
+  D37 = calloc(kk6+kk6,sizeof(int));
+  J37 = calloc(kk6+kk6,sizeof(int*));
+  for(i=0; i<nn6+nn6; i++) {
+    G37[i] = calloc(nn6+nn6, sizeof(int)); GBar37[i] = calloc(nn6+nn6, sizeof(int));
+  }
+  for(i=0; i<kk6+kk6; i++)
+     J37[i] = calloc(kk6+kk6, sizeof(int));
+  //appendBlockMatrix(GG6, GG6, G41, nn6, nn6, nn6, nn6);
+  addSubMatrix(GG6, G37, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GG6, G37, kk6, nn6, 0, 0, kk6, nn6);
+  addSubMatrix(GG6, G37, nn6-kk6, nn6, kk6, 0, kk6+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG6, G37, nn6-kk6, nn6, kk6, 0, kk6+kk6+nn6-kk6, nn6);
+  //appendBlockMatrix(GGBar6, GGBar6, GBar41, nn6, nn6, nn6, nn6);
+  addSubMatrix(GGBar6, GBar37, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GGBar6, GBar37, kk6, nn6, 0, 0, kk6, nn6);
+  addSubMatrix(GGBar6, GBar37, nn6-kk6, nn6, kk6, 0, kk6+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar6, GBar37, nn6-kk6, nn6, kk6, 0, kk6+kk6+nn6-kk6, nn6);
+  appendVector(hh6, hh6, h37, nn6, nn6);
+  Q37 = (QQ6+QQ6);
+  appendVector(DD6, DD6, D37, kk6, kk6);
+  appendBlockMatrix(JJ6, JJ6, J37, kk6, kk6, kk6, kk6);
+
+  // phidprime * phiprime
+  int n38 = nn6+nn7; int k38 = kk6+kk7; int **G38; int **GBar38; int *h38; int Q38; int *D38; int **J38;
+  G38 = calloc(nn6+nn7,sizeof(int*));
+  GBar38 = calloc(nn6+nn7,sizeof(int*));
+  h38 = calloc(nn6+nn7,sizeof(int));
+  D38 = calloc(kk6+kk7,sizeof(int));
+  J38 = calloc(kk6+kk7,sizeof(int*));
+  for(i=0; i<nn6+nn7; i++) {
+    G38[i] = calloc(nn6+nn7, sizeof(int)); GBar38[i] = calloc(nn6+nn7, sizeof(int));
+  }
+  for(i=0; i<kk6+kk7; i++)
+     J38[i] = calloc(kk6+kk7, sizeof(int));
+  //appendBlockMatrix(GG7, GG6, G42, nn7, nn7, nn6, nn6);
+  addSubMatrix(GG7, G38, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GG6, G38, kk6, nn6, 0, 0, kk7, nn7);
+  addSubMatrix(GG7, G38, nn7-kk7, nn7, kk7, 0, kk7+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG6, G38, nn6-kk6, nn6, kk6, 0, kk7+kk6+nn7-kk7, nn6);
+  //appendBlockMatrix(GGBar7, GGBar6, GBar42, nn7, nn7, nn6, nn6);
+  addSubMatrix(GGBar7, GBar38, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GGBar6, GBar38, kk6, nn6, 0, 0, kk7, nn7);
+  addSubMatrix(GGBar7, GBar38, nn7-kk7, nn7, kk7, 0, kk7+kk6, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar6, GBar38, nn6-kk6, nn6, kk6, 0, kk7+kk6+nn7-kk7, nn6);
+  appendVector(hh7, hh6, h38, nn7, nn6);
+  Q38 = (QQ6+QQ7);
+  appendVector(DD7, DD6, D38, kk7, kk6);
+  appendBlockMatrix(JJ7, JJ6, J38, kk7, kk7, kk6, kk6);
+
+  // b60 * phidprime
+  int n39 = nn7+nn1; int k39 = kk7+kk1; int **G39; int **GBar39; int *h39; int Q39; int *D39; int **J39;
+  G39 = calloc(nn7+nn1,sizeof(int*));
+  GBar39 = calloc(nn7+nn1,sizeof(int*));
+  h39 = calloc(nn7+nn1,sizeof(int));
+  D39 = calloc(kk7+kk1,sizeof(int));
+  J39 = calloc(kk7+kk1,sizeof(int*));
+  for(i=0; i<nn7+nn1; i++) {
+    G39[i] = calloc(nn7+nn1, sizeof(int)); GBar39[i] = calloc(nn7+nn1, sizeof(int));
+  }
+  for(i=0; i<kk7+kk1; i++)
+     J39[i] = calloc(kk7+kk1, sizeof(int));
+  //appendBlockMatrix(GG1, GG7, G43, nn1, nn1, nn7, nn7);
+  addSubMatrix(GG1, G39, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GG7, G39, kk7, nn7, 0, 0, kk1, nn1);
+  addSubMatrix(GG1, G39, nn1-kk1, nn1, kk1, 0, kk1+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG7, G39, nn7-kk7, nn7, kk7, 0, kk1+kk7+nn1-kk1, nn7);
+  //appendBlockMatrix(GGBar1, GGBar7, GBar43, nn1, nn1, nn7, nn7);
+  addSubMatrix(GGBar1, GBar39, kk1, nn1, 0, 0, 0, 0);
+  addSubMatrix(GGBar7, GBar39, kk7, nn7, 0, 0, kk1, nn1);
+  addSubMatrix(GGBar1, GBar39, nn1-kk1, nn1, kk1, 0, kk1+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar7, GBar39, nn7-kk7, nn7, kk7, 0, kk1+kk7+nn1-kk1, nn7);
+  appendVector(hh1, hh7, h39, nn1, nn7);
+  Q39 = (QQ7+QQ1);
+  appendVector(DD1, DD7, D39, kk1, kk7);
+  appendBlockMatrix(JJ1, JJ7, J39, kk1, kk1, kk7, kk7);
+  
+  // b66 * phidprime
+  int n40 = nn7+nn2; int k40 = kk7+kk2; int **G40; int **GBar40; int *h40; int Q40; int *D40; int **J40;
+  G40 = calloc(nn7+nn2,sizeof(int*));
+  GBar40 = calloc(nn7+nn2,sizeof(int*));
+  h40 = calloc(nn7+nn2,sizeof(int));
+  D40 = calloc(kk7+kk2,sizeof(int));
+  J40 = calloc(kk7+kk2,sizeof(int*));
+  for(i=0; i<nn7+nn2; i++) {
+    G40[i] = calloc(nn7+nn2, sizeof(int)); GBar40[i] = calloc(nn7+nn2, sizeof(int));
+  }
+  for(i=0; i<kk7+kk2; i++)
+     J40[i] = calloc(kk7+kk2, sizeof(int));
+  //appendBlockMatrix(GG2, GG7, G44, nn2, nn2, nn7, nn7);
+  addSubMatrix(GG2, G40, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GG7, G40, kk7, nn7, 0, 0, kk2, nn2);
+  addSubMatrix(GG1, G40, nn2-kk2, nn2, kk2, 0, kk2+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG7, G40, nn7-kk7, nn7, kk7, 0, kk2+kk7+nn2-kk2, nn7);
+  //appendBlockMatrix(GGBar2, GGBar7, GBar44, nn2, nn2, nn7, nn7);
+  addSubMatrix(GGBar2, GBar40, kk2, nn2, 0, 0, 0, 0);
+  addSubMatrix(GGBar7, GBar40, kk7, nn7, 0, 0, kk2, nn2);
+  addSubMatrix(GGBar1, GBar40, nn2-kk2, nn2, kk2, 0, kk2+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar7, GBar40, nn7-kk7, nn7, kk7, 0, kk2+kk7+nn2-kk2, nn7);
+  appendVector(hh2, hh7, h40, nn2, nn7);
+  Q40 = (QQ7+QQ2);
+  appendVector(DD2, DD7, D40, kk2, kk7);
+  appendBlockMatrix(JJ2, JJ7, J40, kk2, kk2, kk7, kk7);
+  
+  // e6 * phidprime
+  int n41 = nn7+nn3; int k41 = kk7+kk3; int **G41; int **GBar41; int *h41; int Q41; int *D41; int **J41;
+  G41 = calloc(nn7+nn3,sizeof(int*));
+  GBar41 = calloc(nn7+nn3,sizeof(int*));
+  h41 = calloc(nn7+nn3,sizeof(int));
+  D41 = calloc(kk7+kk3,sizeof(int));
+  J41 = calloc(kk7+kk3,sizeof(int*));
+  for(i=0; i<nn7+nn3; i++) {
+    G41[i] = calloc(nn7+nn3, sizeof(int)); GBar41[i] = calloc(nn7+nn3, sizeof(int));
+  }
+  for(i=0; i<kk7+kk3; i++)
+     J41[i] = calloc(kk7+kk3, sizeof(int));
+  //appendBlockMatrix(GG3, GG7, G45, nn3, nn3, nn7, nn7);
+  addSubMatrix(GG3, G41, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GG7, G41, kk7, nn7, 0, 0, kk3, nn3);
+  addSubMatrix(GG3, G41, nn3-kk3, nn3, kk3, 0, kk3+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG7, G41, nn7-kk7, nn7, kk7, 0, kk3+kk7+nn3-kk3, nn7);
+  //appendBlockMatrix(GGBar3, GGBar7, GBar45, nn3, nn3, nn7, nn7);
+  addSubMatrix(GGBar3, GBar41, kk3, nn3, 0, 0, 0, 0);
+  addSubMatrix(GGBar7, GBar41, kk7, nn7, 0, 0, kk3, nn3);
+  addSubMatrix(GGBar3, GBar41, nn3-kk3, nn3, kk3, 0, kk3+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar7, GBar41, nn7-kk7, nn7, kk7, 0, kk3+kk7+nn3-kk3, nn7);
+  appendVector(hh3, hh7, h41, nn3, nn7);
+  Q41 = (QQ7+QQ3);
+  appendVector(DD3, DD7, D41, kk3, kk7);
+  appendBlockMatrix(JJ3, JJ7, J41, kk3, kk3, kk7, kk7);
+
+  // o6 * phidprime
+  int n42 = nn7+nn4; int k42 = kk7+kk4; int **G42; int **GBar42; int *h42; int Q42; int *D42; int **J42;
+  G42 = calloc(nn7+nn4,sizeof(int*));
+  GBar42 = calloc(nn7+nn4,sizeof(int*));
+  h42 = calloc(nn7+nn4,sizeof(int));
+  D42 = calloc(kk7+kk4,sizeof(int));
+  J42 = calloc(kk7+kk4,sizeof(int*));
+  for(i=0; i<nn7+nn4; i++) {
+    G42[i] = calloc(nn7+nn4, sizeof(int)); GBar42[i] = calloc(nn7+nn4, sizeof(int));
+  }
+  for(i=0; i<kk7+kk4; i++)
+     J42[i] = calloc(kk7+kk4, sizeof(int));
+  //appendBlockMatrix(GG4, GG7, G46, nn4, nn4, nn7, nn7);
+  addSubMatrix(GG4, G42, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GG7, G42, kk7, nn7, 0, 0, kk4, nn4);
+  addSubMatrix(GG4, G42, nn4-kk4, nn4, kk4, 0, kk4+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG7, G42, nn7-kk7, nn7, kk7, 0, kk4+kk7+nn4-kk4, nn7);
+  //appendBlockMatrix(GGBar4, GGBar7, GBar46, nn4, nn4, nn7, nn7);
+  addSubMatrix(GGBar4, GBar42, kk4, nn4, 0, 0, 0, 0);
+  addSubMatrix(GGBar7, GBar42, kk7, nn7, 0, 0, kk4, nn4);
+  addSubMatrix(GGBar4, GBar42, nn4-kk4, nn4, kk4, 0, kk4+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar7, GBar42, nn7-kk7, nn7, kk7, 0, kk4+kk7+nn4-kk4, nn7);
+  appendVector(hh4, hh7, h42, nn4, nn7);
+  Q42 = (QQ7+QQ4);
+  appendVector(DD4, DD7, D42, kk4, kk7);
+  appendBlockMatrix(JJ4, JJ7, J42, kk4, kk4, kk7, kk7);
+
+  // k6 * phidprime
+  int n43 = nn7+nn5; int k43 = kk7+kk5; int **G43; int **GBar43; int *h43; int Q43; int *D43; int **J43;
+  G43 = calloc(nn7+nn5,sizeof(int*));
+  GBar43 = calloc(nn7+nn5,sizeof(int*));
+  h43 = calloc(nn7+nn5,sizeof(int));
+  D43 = calloc(kk7+kk5,sizeof(int));
+  J43 = calloc(kk7+kk5,sizeof(int*));
+  for(i=0; i<nn7+nn5; i++) {
+    G43[i] = calloc(nn7+nn5, sizeof(int)); GBar43[i] = calloc(nn7+nn5, sizeof(int));
+  }
+  for(i=0; i<kk7+kk5; i++)
+     J43[i] = calloc(kk7+kk5, sizeof(int));
+  //appendBlockMatrix(GG5, GG7, G47, nn5, nn5, nn7, nn7);
+  addSubMatrix(GG5, G43, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GG7, G43, kk7, nn7, 0, 0, kk5, nn5);
+  addSubMatrix(GG5, G43, nn5-kk5, nn5, kk5, 0, kk5+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG7, G43, nn7-kk7, nn7, kk7, 0, kk5+kk7+nn5-kk5, nn7);
+  //appendBlockMatrix(GGBar5, GGBar7, GBar47, nn5, nn5, nn7, nn7);
+  addSubMatrix(GGBar5, GBar43, kk5, nn5, 0, 0, 0, 0);
+  addSubMatrix(GGBar7, GBar43, kk7, nn7, 0, 0, kk5, nn5);
+  addSubMatrix(GGBar5, GBar43, nn5-kk5, nn5, kk5, 0, kk5+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar7, GBar43, nn7-kk7, nn7, kk7, 0, kk5+kk7+nn5-kk5, nn7);
+  appendVector(hh5, hh7, h43, nn5, nn7);
+  Q43 = (QQ7+QQ5);
+  appendVector(DD5, DD7, D43, kk5, kk7);
+  appendBlockMatrix(JJ5, JJ7, J43, kk5, kk5, kk7, kk7);
+
+  // phiprime * phidprime
+  int n44 = nn7+nn6; int k44 = kk7+kk6; int **G44; int **GBar44; int *h44; int Q44; int *D44; int **J44;
+  G44 = calloc(nn7+nn6,sizeof(int*));
+  GBar44 = calloc(nn7+nn6,sizeof(int*));
+  h44 = calloc(nn7+nn6,sizeof(int));
+  D44 = calloc(kk7+kk6,sizeof(int));
+  J44 = calloc(kk7+kk6,sizeof(int*));
+  for(i=0; i<nn7+nn6; i++) {
+    G44[i] = calloc(nn7+nn6, sizeof(int)); GBar44[i] = calloc(nn7+nn6, sizeof(int));
+  }
+  for(i=0; i<kk7+kk6; i++)
+     J44[i] = calloc(kk7+kk6, sizeof(int));
+  //appendBlockMatrix(GG6, GG7, G48, nn6, nn6, nn7, nn7);
+  addSubMatrix(GG6, G44, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GG7, G44, kk7, nn7, 0, 0, kk6, nn6);
+  addSubMatrix(GG6, G44, nn6-kk6, nn6, kk6, 0, kk6+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG7, G44, nn7-kk7, nn7, kk7, 0, kk6+kk7+nn6-kk6, nn7);
+  //appendBlockMatrix(GGBar6, GGBar7, GBar48, nn6, nn6, nn7, nn7);
+  addSubMatrix(GGBar6, GBar44, kk6, nn6, 0, 0, 0, 0);
+  addSubMatrix(GGBar7, GBar44, kk7, nn7, 0, 0, kk6, nn6);
+  addSubMatrix(GGBar6, GBar44, nn6-kk6, nn6, kk6, 0, kk6+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar7, GBar44, nn7-kk7, nn7, kk7, 0, kk6+kk7+nn6-kk6, nn7);
+  appendVector(hh6, hh7, h44, nn6, nn7);
+  Q44 = (QQ7+QQ6);
+  appendVector(DD6, DD7, D44, kk6, kk7);
+  appendBlockMatrix(JJ6, JJ7, J44, kk6, kk6, kk7, kk7);
+
+  // phidprime * phidprime
+  int n45 = nn7+nn7; int k45 = kk7+kk7; int **G45; int **GBar45; int *h45; int Q45; int *D45; int **J45;
+  G45 = calloc(nn7+nn7,sizeof(int*));
+  GBar45 = calloc(nn7+nn7,sizeof(int*));
+  h45 = calloc(nn7+nn7,sizeof(int));
+  D45 = calloc(kk7+kk7,sizeof(int));
+  J45 = calloc(kk7+kk7,sizeof(int*));
+  for(i=0; i<nn7+nn7; i++) {
+    G45[i] = calloc(nn7+nn7, sizeof(int)); GBar45[i] = calloc(nn7+nn7, sizeof(int));
+  }
+  for(i=0; i<kk7+kk7; i++)
+     J45[i] = calloc(kk7+kk7, sizeof(int));
+  //appendBlockMatrix(GG7, GG7, G49, nn7, nn7, nn7, nn7);
+  addSubMatrix(GG7, G45, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GG7, G45, kk7, nn7, 0, 0, kk7, nn7);
+  addSubMatrix(GG7, G45, nn7-kk7, nn7, kk7, 0, kk7+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GG7, G45, nn7-kk7, nn7, kk7, 0, kk7+kk7+nn7-kk7, nn7);
+  //appendBlockMatrix(GGBar7, GGBar7, GBar49, nn7, nn7, nn7, nn7);
+  addSubMatrix(GGBar7, GBar45, kk7, nn7, 0, 0, 0, 0);
+  addSubMatrix(GGBar7, GBar45, kk7, nn7, 0, 0, kk7, nn7);
+  addSubMatrix(GGBar7, GBar45, nn7-kk7, nn7, kk7, 0, kk7+kk7, 0); // put the out-of-subspace vectors at the end
+  addSubMatrix(GGBar7, GBar45, nn7-kk7, nn7, kk7, 0, kk7+kk7+nn7-kk7, nn7);
+  appendVector(hh7, hh7, h45, nn7, nn7);
+  Q45 = (QQ7+QQ7);
+  appendVector(DD7, DD7, D45, kk7, kk7);
+  appendBlockMatrix(JJ7, JJ7, J45, kk7, kk7, kk7, kk7);
+
+  // b60 * b66 + b66 * b60
+  int n46 = 12; int k46 = 11;
+  int (*(G46[])) = { (int[]) {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+  int (*(GBar46[])) = { (int[]) {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}};
+  int h46[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  int Q46 = 4;
+  int D46[] = {0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4};
+  int (*(J46[])) = { (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+
+  // e6 * o6 + e6 * o6
+  int n47 = 12; int k47 = 11;
+  int (*(G47[])) = { (int[]) {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+  int (*(GBar47[])) = { (int[]) {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}};
+  int h47[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  int Q47 = 0;
+  int D47[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  int (*(J47[])) = { (int[]) {0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}, (int[]) {4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4}, (int[]) {4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 4}, (int[]) {4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 4}, (int[]) {4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4}, (int[]) {4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4}, (int[]) {4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4}, (int[]) {4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4}, (int[]) {4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4}, (int[]) {4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4}, (int[]) {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0}};
+
+
+
+  
+  int *K; int ***G; int ***GBar; int **h; int *Q; int **D; int ***J;
+  double complex Gamma[(int)pow(47,N/12)]; // prefactor in front of resultant state
+  G = calloc(pow(47,N/12),sizeof(int*)); GBar = calloc(pow(47,N/12),sizeof(int*));
+  h = calloc(pow(47,N/12),sizeof(int*));
+  
+  J = calloc(pow(47,N/12),sizeof(int*)); D = calloc(pow(47,N/12),sizeof(int*)); Q = calloc(pow(47,N/12),sizeof(int));
+
+  K = calloc(pow(47,N/12), sizeof(int));
+
+  int origK, origQ, *origD;
+  int **origJ;
+  int **origG, **origGBar;
+  int *origh;
+  double complex origGamma;
+
+  int combination; // a particular combination from the linear combo of stabilizer states making up the tensor factors multiplied together
+  
+
+  for(j=0; j<pow(47,N/12); j++) { // there will be 47^(N/12) combinations when using k=12 tensor factors
+
+    combination = j;
+
+    K[j] = 0.0;
+    
+    for(k=0; k<N/12; k++) {
+      K[j] += (((combination%47)==46)*k47 + ((combination%47)==45)*k46 + ((combination%47)==44)*k45 + ((combination%47)==43)*k44 + ((combination%47)==42)*k43 + ((combination%47)==41)*k42 + ((combination%47)==40)*k41 + ((combination%47)==39)*k40 +
+              ((combination%47)==38)*k39 + ((combination%47)==37)*k38 + ((combination%47)==36)*k37 + ((combination%47)==35)*k36 + ((combination%47)==34)*k35 + ((combination%47)==33)*k34 + ((combination%47)==32)*k33 + ((combination%47)==31)*k32 + ((combination%47)==30)*k31 + ((combination%47)==29)*k30 +
+              ((combination%47)==28)*k29 + ((combination%47)==27)*k28 + ((combination%47)==26)*k27 + ((combination%47)==25)*k26 + ((combination%47)==24)*k25 + ((combination%47)==23)*k24 + ((combination%47)==22)*k23 + ((combination%47)==21)*k22 + ((combination%47)==20)*k21 + ((combination%47)==19)*k20 +
+              ((combination%47)==18)*k19 + ((combination%47)==17)*k18 + ((combination%47)==16)*k17 + ((combination%47)==15)*k16 + ((combination%47)==14)*k15 + ((combination%47)==13)*k14 + ((combination%47)==12)*k13 + ((combination%47)==11)*k12 + ((combination%47)==10)*k11 + ((combination%47)==9)*k10 +
+              ((combination%47)==8)*k9 + ((combination%47)==7)*k8 + ((combination%47)==6)*k7 + ((combination%47)==5)*k6 + ((combination%47)==4)*k5 + ((combination%47)==3)*k4 + ((combination%47)==2)*k3 + ((combination%47)==1)*k2 + ((combination%47)==0)*k1);
+      combination /= 47;
+    }
+    combination = j;
+
+    Gamma[j] = 1.0;
+
+    G[j] = calloc(N, sizeof(int*)); GBar[j] = calloc(N, sizeof(int*));
+    h[j] = calloc(N, sizeof(int));
+
+    if(K[j] > 0) {
+      J[j] = calloc(K[j], sizeof(int*)); D[j] = calloc(K[j], sizeof(int));
+      for(k=0; k<K[j]; k++)
+       J[j][k] = calloc(K[j], sizeof(int));
+    }
+
+    for(k=0; k<N; k++) {
+      G[j][k] = calloc(N, sizeof(int)); GBar[j][k] = calloc(N, sizeof(int));
+    }
+
+    int Kcounter = 0; // Kcounter keeps track of the K<=N that we have added already to the G rows etc. for each combination that is indexed by the digits (base 3) of 'j' in that we go through with 'k'
+    int Kcombo; // Kcombo stores the k<(n1=n2=n3) dimension of the member of the combination that we are currently adding
+    for(k=0; k<N/12; k++) {
+
+      Q[j] += (((combination%47)==46)*Q47 + ((combination%47)==45)*Q46 + ((combination%47)==44)*Q45 + ((combination%47)==43)*Q44 + ((combination%47)==42)*Q43 + ((combination%47)==41)*Q42 + ((combination%47)==40)*Q41 + ((combination%47)==39)*Q40 +
+              ((combination%47)==38)*Q39 + ((combination%47)==37)*Q38 + ((combination%47)==36)*Q37 + ((combination%47)==35)*Q36 + ((combination%47)==34)*Q35 + ((combination%47)==33)*Q34 + ((combination%47)==32)*Q33 + ((combination%47)==31)*Q32 + ((combination%47)==30)*Q31 + ((combination%47)==29)*Q30 +
+              ((combination%47)==28)*Q29 + ((combination%47)==27)*Q28 + ((combination%47)==26)*Q27 + ((combination%47)==25)*Q26 + ((combination%47)==24)*Q25 + ((combination%47)==23)*Q24 + ((combination%47)==22)*Q23 + ((combination%47)==21)*Q22 + ((combination%47)==20)*Q21 + ((combination%47)==19)*Q20 +
+              ((combination%47)==18)*Q19 + ((combination%47)==17)*Q18 + ((combination%47)==16)*Q17 + ((combination%47)==15)*Q16 + ((combination%47)==14)*Q15 + ((combination%47)==13)*Q14 + ((combination%47)==12)*Q13 + ((combination%47)==11)*Q12 + ((combination%47)==10)*Q11 + ((combination%47)==9)*Q10 +
+              ((combination%47)==8)*Q9 + ((combination%47)==7)*Q8 + ((combination%47)==6)*Q7 + ((combination%47)==5)*Q6 + ((combination%47)==4)*Q5 + ((combination%47)==3)*Q4 + ((combination%47)==2)*Q3 + ((combination%47)==1)*Q2 + ((combination%47)==0)*Q1);
+      
+
+      Gamma[j] *= (((combination%47)==46)*coeffe6*coeffo6*sqrt(2.0) + ((combination%47)==45)*coeffb60*coeffb66*sqrt(2.0) + ((combination%47)==44)*coeffphidprime*coeffphidprime + ((combination%47)==43)*coeffphiprime*coeffphidprime + ((combination%47)==42)*coeffk6*coeffphidprime + ((combination%47)==41)*coeffo6*coeffphidprime + ((combination%47)==40)*coeffe6*coeffphidprime + ((combination%47)==39)*coeffb66*coeffphidprime + ((combination%47)==38)*coeffb60*coeffphidprime
+                  + ((combination%47)==37)*coeffphidprime*coeffphiprime + ((combination%47)==36)*coeffphiprime*coeffphiprime + ((combination%47)==35)*coeffk6*coeffphiprime + ((combination%47)==34)*coeffo6*coeffphiprime + ((combination%47)==33)*coeffe6*coeffphiprime + ((combination%47)==32)*coeffb66*coeffphiprime + ((combination%47)==31)*coeffb60*coeffphiprime
+                  + ((combination%47)==30)*coeffphidprime*coeffk6 + ((combination%47)==29)*coeffphiprime*coeffk6 + ((combination%47)==28)*coeffk6*coeffk6 + ((combination%47)==27)*coeffo6*coeffk6 + ((combination%47)==26)*coeffe6*coeffk6 + ((combination%47)==25)*coeffb66*coeffk6 + ((combination%47)==24)*coeffb60*coeffk6
+                  + ((combination%47)==23)*coeffphidprime*coeffo6 + ((combination%47)==22)*coeffphiprime*coeffo6 + ((combination%47)==21)*coeffk6*coeffo6 + ((combination%47)==20)*coeffo6*coeffo6  + ((combination%47)==19)*coeffb66*coeffo6 + ((combination%47)==18)*coeffb60*coeffo6
+                  + ((combination%47)==17)*coeffphidprime*coeffe6 + ((combination%47)==16)*coeffphiprime*coeffe6 + ((combination%47)==15)*coeffk6*coeffe6 + ((combination%47)==14)*coeffe6*coeffe6 + ((combination%47)==13)*coeffb66*coeffe6 + ((combination%47)==12)*coeffb60*coeffe6
+                  + ((combination%47)==11)*coeffphidprime*coeffb66 + ((combination%47)==10)*coeffphiprime*coeffb66 + ((combination%47)==9)*coeffk6*coeffb66 + ((combination%47)==8)*coeffo6*coeffb66 + ((combination%47)==7)*coeffe6*coeffb66 + ((combination%47)==6)*coeffb66*coeffb66
+                  + ((combination%47)==5)*coeffphidprime*coeffb60 + ((combination%47)==4)*coeffphiprime*coeffb60 + ((combination%47)==3)*coeffk6*coeffb60 + ((combination%47)==2)*coeffo6*coeffb60 + ((combination%47)==1)*coeffe6*coeffb60 + ((combination%47)==0)*coeffb60*coeffb60);
+
+      Kcombo = (((combination%47)==46)*k47 + ((combination%47)==45)*k46 + ((combination%47)==44)*k45 + ((combination%47)==43)*k44 + ((combination%47)==42)*k43 + ((combination%47)==41)*k42 + ((combination%47)==40)*k41 + ((combination%47)==39)*k40 +
+              ((combination%47)==38)*k39 + ((combination%47)==37)*k38 + ((combination%47)==36)*k37 + ((combination%47)==35)*k36 + ((combination%47)==34)*k35 + ((combination%47)==33)*k34 + ((combination%47)==32)*k33 + ((combination%47)==31)*k32 + ((combination%47)==30)*k31 + ((combination%47)==29)*k30 +
+              ((combination%47)==28)*k29 + ((combination%47)==27)*k28 + ((combination%47)==26)*k27 + ((combination%47)==25)*k26 + ((combination%47)==24)*k25 + ((combination%47)==23)*k24 + ((combination%47)==22)*k23 + ((combination%47)==21)*k22 + ((combination%47)==20)*k21 + ((combination%47)==19)*k20 +
+              ((combination%47)==18)*k19 + ((combination%47)==17)*k18 + ((combination%47)==16)*k17 + ((combination%47)==15)*k16 + ((combination%47)==14)*k15 + ((combination%47)==13)*k14 + ((combination%47)==12)*k13 + ((combination%47)==11)*k12 + ((combination%47)==10)*k11 + ((combination%47)==9)*k10 +
+              ((combination%47)==8)*k9 + ((combination%47)==7)*k8 + ((combination%47)==6)*k7 + ((combination%47)==5)*k6 + ((combination%47)==4)*k5 + ((combination%47)==3)*k4 + ((combination%47)==2)*k3 + ((combination%47)==1)*k2 + ((combination%47)==0)*k1);
+      for(l=0; l<Kcombo; l++) {
+       // D1 has a different number of rows 'l' than D2 and D3 so you need to use something like 'switch' to check combination%3 without going out of bound of J1
+       switch(combination%47) {
+       case 0:
+         D[j][Kcounter+l] = D1[l];
+         break;
+       case 1:
+         D[j][Kcounter+l] = D2[l];
+         break;
+       case 2:
+         D[j][Kcounter+l] = D3[l];
+         break;
+       case 3:
+         D[j][Kcounter+l] = D4[l];
+           break;
+       case 4:
+         D[j][Kcounter+l] = D5[l];
+         break;
+       case 5:
+         D[j][Kcounter+l] = D6[l];
+         break;
+       case 6:
+         D[j][Kcounter+l] = D7[l];
+         break;
+       case 7:
+         D[j][Kcounter+l] = D8[l];
+         break;
+       case 8:
+         D[j][Kcounter+l] = D9[l];
+         break;
+       case 9:
+         D[j][Kcounter+l] = D10[l];
+         break;
+       case 10:
+         D[j][Kcounter+l] = D11[l];
+         break;
+       case 11:
+         D[j][Kcounter+l] = D12[l];
+         break;
+       case 12:
+         D[j][Kcounter+l] = D13[l];
+         break;
+       case 13:
+         D[j][Kcounter+l] = D14[l];
+           break;
+       case 14:
+         D[j][Kcounter+l] = D15[l];
+         break;
+       case 15:
+         D[j][Kcounter+l] = D16[l];
+         break;
+       case 16:
+         D[j][Kcounter+l] = D17[l];
+         break;
+       case 17:
+         D[j][Kcounter+l] = D18[l];
+         break;
+       case 18:
+         D[j][Kcounter+l] = D19[l];
+         break;
+       case 19:
+         D[j][Kcounter+l] = D20[l];
+         break;
+       case 20:
+         D[j][Kcounter+l] = D21[l];
+         break;
+       case 21:
+         D[j][Kcounter+l] = D22[l];
+         break;
+       case 22:
+         D[j][Kcounter+l] = D23[l];
+         break;
+       case 23:
+         D[j][Kcounter+l] = D24[l];
+           break;
+       case 24:
+         D[j][Kcounter+l] = D25[l];
+         break;
+       case 25:
+         D[j][Kcounter+l] = D26[l];
+         break;
+       case 26:
+         D[j][Kcounter+l] = D27[l];
+         break;
+       case 27:
+         D[j][Kcounter+l] = D28[l];
+         break;
+       case 28:
+         D[j][Kcounter+l] = D29[l];
+         break;
+       case 29:
+         D[j][Kcounter+l] = D30[l];
+         break;
+       case 30:
+         D[j][Kcounter+l] = D31[l];
+         break;
+       case 31:
+         D[j][Kcounter+l] = D32[l];
+         break;
+       case 32:
+         D[j][Kcounter+l] = D33[l];
+         break;
+       case 33:
+         D[j][Kcounter+l] = D34[l];
+           break;
+       case 34:
+         D[j][Kcounter+l] = D35[l];
+         break;
+       case 35:
+         D[j][Kcounter+l] = D36[l];
+         break;
+       case 36:
+         D[j][Kcounter+l] = D37[l];
+         break;
+       case 37:
+         D[j][Kcounter+l] = D38[l];
+         break;
+       case 38:
+         D[j][Kcounter+l] = D39[l];
+         break;
+       case 39:
+         D[j][Kcounter+l] = D40[l];
+         break;
+       case 40:
+         D[j][Kcounter+l] = D41[l];
+         break;
+       case 41:
+         D[j][Kcounter+l] = D42[l];
+         break;
+       case 42:
+         D[j][Kcounter+l] = D43[l];
+         break;
+       case 43:
+         D[j][Kcounter+l] = D44[l];
+           break;
+       case 44:
+         D[j][Kcounter+l] = D45[l];
+         break;
+       case 45:
+         D[j][Kcounter+l] = D46[l];
+         break;
+       case 46:
+         D[j][Kcounter+l] = D47[l];
+         break;
+       default:
+         printf("error");
+         return 1;
+         }
+       for(m=0; m<Kcombo; m++) {
+         // J1 has a different number of rows 'l' than J2 and J3 so you need to use something like 'switch' to check combination%3 without going out of bound of J1
+         switch(combination%47) {
+         case 0:
+           J[j][Kcounter+l][Kcounter+m] = J1[l][m];
+           break;
+         case 1:
+           J[j][Kcounter+l][Kcounter+m] = J2[l][m];
+           break;
+         case 2:
+           J[j][Kcounter+l][Kcounter+m] = J3[l][m];
+           break;
+         case 3:
+           J[j][Kcounter+l][Kcounter+m] = J4[l][m];
+           break;
+         case 4:
+           J[j][Kcounter+l][Kcounter+m] = J5[l][m];
+           break;
+         case 5:
+           J[j][Kcounter+l][Kcounter+m] = J6[l][m];
+           break;
+         case 6:
+           J[j][Kcounter+l][Kcounter+m] = J7[l][m];
+           break;
+         case 7:
+           J[j][Kcounter+l][Kcounter+m] = J8[l][m];
+           break;
+         case 8:
+           J[j][Kcounter+l][Kcounter+m] = J9[l][m];
+           break;
+         case 9:
+           J[j][Kcounter+l][Kcounter+m] = J10[l][m];
+           break;
+         case 10:
+           J[j][Kcounter+l][Kcounter+m] = J11[l][m];
+           break;
+         case 11:
+           J[j][Kcounter+l][Kcounter+m] = J12[l][m];
+           break;
+         case 12:
+           J[j][Kcounter+l][Kcounter+m] = J13[l][m];
+           break;
+         case 13:
+           J[j][Kcounter+l][Kcounter+m] = J14[l][m];
+           break;
+         case 14:
+           J[j][Kcounter+l][Kcounter+m] = J15[l][m];
+           break;
+         case 15:
+           J[j][Kcounter+l][Kcounter+m] = J16[l][m];
+           break;
+         case 16:
+           J[j][Kcounter+l][Kcounter+m] = J17[l][m];
+           break;
+         case 17:
+           J[j][Kcounter+l][Kcounter+m] = J18[l][m];
+           break;
+         case 18:
+           J[j][Kcounter+l][Kcounter+m] = J19[l][m];
+           break;
+         case 19:
+           J[j][Kcounter+l][Kcounter+m] = J20[l][m];
+           break;
+         case 20:
+           J[j][Kcounter+l][Kcounter+m] = J21[l][m];
+           break;
+         case 21:
+           J[j][Kcounter+l][Kcounter+m] = J22[l][m];
+           break;
+         case 22:
+           J[j][Kcounter+l][Kcounter+m] = J23[l][m];
+           break;
+         case 23:
+           J[j][Kcounter+l][Kcounter+m] = J24[l][m];
+           break;
+         case 24:
+           J[j][Kcounter+l][Kcounter+m] = J25[l][m];
+           break;
+         case 25:
+           J[j][Kcounter+l][Kcounter+m] = J26[l][m];
+           break;
+         case 26:
+           J[j][Kcounter+l][Kcounter+m] = J27[l][m];
+           break;
+         case 27:
+           J[j][Kcounter+l][Kcounter+m] = J28[l][m];
+           break;
+         case 28:
+           J[j][Kcounter+l][Kcounter+m] = J29[l][m];
+           break;
+         case 29:
+           J[j][Kcounter+l][Kcounter+m] = J30[l][m];
+           break;
+         case 30:
+           J[j][Kcounter+l][Kcounter+m] = J31[l][m];
+           break;
+         case 31:
+           J[j][Kcounter+l][Kcounter+m] = J32[l][m];
+           break;
+         case 32:
+           J[j][Kcounter+l][Kcounter+m] = J33[l][m];
+           break;
+         case 33:
+           J[j][Kcounter+l][Kcounter+m] = J34[l][m];
+           break;
+         case 34:
+           J[j][Kcounter+l][Kcounter+m] = J35[l][m];
+           break;
+         case 35:
+           J[j][Kcounter+l][Kcounter+m] = J36[l][m];
+           break;
+         case 36:
+           J[j][Kcounter+l][Kcounter+m] = J37[l][m];
+           break;
+         case 37:
+           J[j][Kcounter+l][Kcounter+m] = J38[l][m];
+           break;
+         case 38:
+           J[j][Kcounter+l][Kcounter+m] = J39[l][m];
+           break;
+         case 39:
+           J[j][Kcounter+l][Kcounter+m] = J40[l][m];
+           break;
+         case 40:
+           J[j][Kcounter+l][Kcounter+m] = J41[l][m];
+           break;
+         case 41:
+           J[j][Kcounter+l][Kcounter+m] = J42[l][m];
+           break;
+         case 42:
+           J[j][Kcounter+l][Kcounter+m] = J43[l][m];
+           break;
+         case 43:
+           J[j][Kcounter+l][Kcounter+m] = J44[l][m];
+           break;
+         case 44:
+           J[j][Kcounter+l][Kcounter+m] = J45[l][m];
+           break;
+         case 45:
+           J[j][Kcounter+l][Kcounter+m] = J46[l][m];
+           break;
+         case 46:
+           J[j][Kcounter+l][Kcounter+m] = J47[l][m];
+           break;
+         default:
+           printf("error");
+           return 1;
+         }
+       }
+      }
+
+      for(l=0; l<n1; l++) { // assuming n1=n2=n3
+       h[j][k*n1+l] = (((combination%47)==46)*h47[l] + ((combination%47)==45)*h46[l] + ((combination%47)==44)*h45[l] + ((combination%47)==43)*h44[l] + ((combination%47)==42)*h43[l] + ((combination%47)==41)*h42[l] + ((combination%47)==40)*h41[l] + ((combination%47)==39)*h40[l] +
+                       ((combination%47)==38)*h39[l] + ((combination%47)==37)*h38[l] + ((combination%47)==36)*h37[l] + ((combination%47)==35)*h36[l] + ((combination%47)==34)*h35[l] + ((combination%47)==33)*h34[l] + ((combination%47)==32)*h33[l] + ((combination%47)==31)*h32[l] + ((combination%47)==30)*h31[l] + ((combination%47)==29)*h30[l] +
+                       ((combination%47)==28)*h29[l] + ((combination%47)==27)*h28[l] + ((combination%47)==26)*h27[l] + ((combination%47)==25)*h26[l] + ((combination%47)==24)*h25[l] + ((combination%47)==23)*h24[l] + ((combination%47)==22)*h23[l] + ((combination%47)==21)*h22[l] + ((combination%47)==20)*h21[l] + ((combination%47)==19)*h20[l] +
+                       ((combination%47)==18)*h19[l] + ((combination%47)==17)*h18[l] + ((combination%47)==16)*h17[l] + ((combination%47)==15)*h16[l] + ((combination%47)==14)*h15[l] + ((combination%47)==13)*h14[l] + ((combination%47)==12)*h13[l] + ((combination%47)==11)*h12[l] + ((combination%47)==10)*h11[l] + ((combination%47)==9)*h10[l] +
+                       ((combination%47)==8)*h9[l] + ((combination%47)==7)*h8[l] + ((combination%47)==6)*h7[l] + ((combination%47)==5)*h6[l] + ((combination%47)==4)*h5[l] + ((combination%47)==3)*h4[l] + ((combination%47)==2)*h3[l] + ((combination%47)==1)*h2[l] + ((combination%47)==0)*h1[l]);
+      }
+      // only filling the K[j] first rows of G and GBar here corresponding to the basis for D and J
+      for(l=0; l<Kcombo; l++) {
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         G[j][Kcounter+l][k*n1+m] = (((combination%47)==46)*G47[l][m] + ((combination%47)==45)*G46[l][m] + ((combination%47)==44)*G45[l][m] + ((combination%47)==43)*G44[l][m] + ((combination%47)==42)*G43[l][m] + ((combination%47)==41)*G42[l][m] + ((combination%47)==40)*G41[l][m] + ((combination%47)==39)*G40[l][m] +
+                                     ((combination%47)==38)*G39[l][m] + ((combination%47)==37)*G38[l][m] + ((combination%47)==36)*G37[l][m] + ((combination%47)==35)*G36[l][m] + ((combination%47)==34)*G35[l][m] + ((combination%47)==33)*G34[l][m] + ((combination%47)==32)*G33[l][m] + ((combination%47)==31)*G32[l][m] + ((combination%47)==30)*G31[l][m] + ((combination%47)==29)*G30[l][m] +
+                                     ((combination%47)==28)*G29[l][m] + ((combination%47)==27)*G28[l][m] + ((combination%47)==26)*G27[l][m] + ((combination%47)==25)*G26[l][m] + ((combination%47)==24)*G25[l][m] + ((combination%47)==23)*G24[l][m] + ((combination%47)==22)*G23[l][m] + ((combination%47)==21)*G22[l][m] + ((combination%47)==20)*G21[l][m] + ((combination%47)==19)*G20[l][m] +
+                                     ((combination%47)==18)*G19[l][m] + ((combination%47)==17)*G18[l][m] + ((combination%47)==16)*G17[l][m] + ((combination%47)==15)*G16[l][m] + ((combination%47)==14)*G15[l][m] + ((combination%47)==13)*G14[l][m] + ((combination%47)==12)*G13[l][m] + ((combination%47)==11)*G12[l][m] + ((combination%47)==10)*G11[l][m] + ((combination%47)==9)*G10[l][m] +
+                                     ((combination%47)==8)*G9[l][m] + ((combination%47)==7)*G8[l][m] + ((combination%47)==6)*G7[l][m] + ((combination%47)==5)*G6[l][m] + ((combination%47)==4)*G5[l][m] + ((combination%47)==3)*G4[l][m] + ((combination%47)==2)*G3[l][m] + ((combination%47)==1)*G2[l][m] + ((combination%47)==0)*G1[l][m]);
+         GBar[j][Kcounter+l][k*n1+m] = (((combination%47)==46)*GBar47[l][m] + ((combination%47)==45)*GBar46[l][m] + ((combination%47)==44)*GBar45[l][m] + ((combination%47)==43)*GBar44[l][m] + ((combination%47)==42)*GBar43[l][m] + ((combination%47)==41)*GBar42[l][m] + ((combination%47)==40)*GBar41[l][m] + ((combination%47)==39)*GBar40[l][m] +
+                                        ((combination%47)==38)*GBar39[l][m] + ((combination%47)==37)*GBar38[l][m] + ((combination%47)==36)*GBar37[l][m] + ((combination%47)==35)*GBar36[l][m] + ((combination%47)==34)*GBar35[l][m] + ((combination%47)==33)*GBar34[l][m] + ((combination%47)==32)*GBar33[l][m] + ((combination%47)==31)*GBar32[l][m] + ((combination%47)==30)*GBar31[l][m] + ((combination%47)==29)*GBar30[l][m] +
+                                        ((combination%47)==28)*GBar29[l][m] + ((combination%47)==27)*GBar28[l][m] + ((combination%47)==26)*GBar27[l][m] + ((combination%47)==25)*GBar26[l][m] + ((combination%47)==24)*GBar25[l][m] + ((combination%47)==23)*GBar24[l][m] + ((combination%47)==22)*GBar23[l][m] + ((combination%47)==21)*GBar22[l][m] + ((combination%47)==20)*GBar21[l][m] + ((combination%47)==19)*GBar20[l][m] +
+                                        ((combination%47)==18)*GBar19[l][m] + ((combination%47)==17)*GBar18[l][m] + ((combination%47)==16)*GBar17[l][m] + ((combination%47)==15)*GBar16[l][m] + ((combination%47)==14)*GBar15[l][m] + ((combination%47)==13)*GBar14[l][m] + ((combination%47)==12)*GBar13[l][m] + ((combination%47)==11)*GBar12[l][m] + ((combination%47)==10)*GBar11[l][m] + ((combination%47)==9)*GBar10[l][m] +
+                                        ((combination%47)==8)*GBar9[l][m] + ((combination%47)==7)*GBar8[l][m] + ((combination%47)==6)*GBar7[l][m] + ((combination%47)==5)*GBar6[l][m] + ((combination%47)==4)*GBar5[l][m] + ((combination%47)==3)*GBar4[l][m] + ((combination%47)==2)*GBar3[l][m] + ((combination%47)==1)*GBar2[l][m] + ((combination%47)==0)*GBar1[l][m]);
+       }
+      }
+      Kcounter = Kcounter + Kcombo;
+      
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      //memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
+
+      //memcpy(origJ[j][k], J[j][k], K[j]*sizeof(int));
+      
+      combination /= 47; // shift to the right by one (in base-47 arithmetic)
+    }
+    //printf("!\n");
+
+    // now need to fill the N-Kcounter remaining rows of G and GBar that are outside the spanning basis states of D and J
+    combination = j;
+    for(k=0; k<(N/12); k++) {
+      Kcombo = (((combination%47)==46)*k47 + ((combination%47)==45)*k46 + ((combination%47)==44)*k45 + ((combination%47)==43)*k44 + ((combination%47)==42)*k43 + ((combination%47)==41)*k42 + ((combination%47)==40)*k41 + ((combination%47)==39)*k40 +
+              ((combination%47)==38)*k39 + ((combination%47)==37)*k38 + ((combination%47)==36)*k37 + ((combination%47)==35)*k36 + ((combination%47)==34)*k35 + ((combination%47)==33)*k34 + ((combination%47)==32)*k33 + ((combination%47)==31)*k32 + ((combination%47)==30)*k31 + ((combination%47)==29)*k30 +
+              ((combination%47)==28)*k29 + ((combination%47)==27)*k28 + ((combination%47)==26)*k27 + ((combination%47)==25)*k26 + ((combination%47)==24)*k25 + ((combination%47)==23)*k24 + ((combination%47)==22)*k23 + ((combination%47)==21)*k22 + ((combination%47)==20)*k21 + ((combination%47)==19)*k20 +
+              ((combination%47)==18)*k19 + ((combination%47)==17)*k18 + ((combination%47)==16)*k17 + ((combination%47)==15)*k16 + ((combination%47)==14)*k15 + ((combination%47)==13)*k14 + ((combination%47)==12)*k13 + ((combination%47)==11)*k12 + ((combination%47)==10)*k11 + ((combination%47)==9)*k10 +
+              ((combination%47)==8)*k9 + ((combination%47)==7)*k8 + ((combination%47)==6)*k7 + ((combination%47)==5)*k6 + ((combination%47)==4)*k5 + ((combination%47)==3)*k4 + ((combination%47)==2)*k3 + ((combination%47)==1)*k2 + ((combination%47)==0)*k1);
+      //printf("Kcounter=%d\n", Kcounter);
+      // G and GBar rows that are outside the first 'k' spanning basis states
+      for(l=Kcombo; l<n1; l++) { // assuming n1=n2=n3
+       //printf("l=%d\n", l);
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         /* printf("m=%d\n", m); */
+         /* printf("Kcounter+l=%d\n", Kcounter+l); */
+         /* printf("k*n1+m=%d\n", k*n1+m); */
+         G[j][Kcounter+l-Kcombo][k*n1+m] = (((combination%47)==46)*G47[l][m] + ((combination%47)==45)*G46[l][m] + ((combination%47)==44)*G45[l][m] + ((combination%47)==43)*G44[l][m] + ((combination%47)==42)*G43[l][m] + ((combination%47)==41)*G42[l][m] + ((combination%47)==40)*G41[l][m] + ((combination%47)==39)*G40[l][m] +
+                                     ((combination%47)==38)*G39[l][m] + ((combination%47)==37)*G38[l][m] + ((combination%47)==36)*G37[l][m] + ((combination%47)==35)*G36[l][m] + ((combination%47)==34)*G35[l][m] + ((combination%47)==33)*G34[l][m] + ((combination%47)==32)*G33[l][m] + ((combination%47)==31)*G32[l][m] + ((combination%47)==30)*G31[l][m] + ((combination%47)==29)*G30[l][m] +
+                                     ((combination%47)==28)*G29[l][m] + ((combination%47)==27)*G28[l][m] + ((combination%47)==26)*G27[l][m] + ((combination%47)==25)*G26[l][m] + ((combination%47)==24)*G25[l][m] + ((combination%47)==23)*G24[l][m] + ((combination%47)==22)*G23[l][m] + ((combination%47)==21)*G22[l][m] + ((combination%47)==20)*G21[l][m] + ((combination%47)==19)*G20[l][m] +
+                                     ((combination%47)==18)*G19[l][m] + ((combination%47)==17)*G18[l][m] + ((combination%47)==16)*G17[l][m] + ((combination%47)==15)*G16[l][m] + ((combination%47)==14)*G15[l][m] + ((combination%47)==13)*G14[l][m] + ((combination%47)==12)*G13[l][m] + ((combination%47)==11)*G12[l][m] + ((combination%47)==10)*G11[l][m] + ((combination%47)==9)*G10[l][m] +
+                                     ((combination%47)==8)*G9[l][m] + ((combination%47)==7)*G8[l][m] + ((combination%47)==6)*G7[l][m] + ((combination%47)==5)*G6[l][m] + ((combination%47)==4)*G5[l][m] + ((combination%47)==3)*G4[l][m] + ((combination%47)==2)*G3[l][m] + ((combination%47)==1)*G2[l][m] + ((combination%47)==0)*G1[l][m]);
+         GBar[j][Kcounter+l-Kcombo][k*n1+m] = (((combination%47)==46)*GBar47[l][m] + ((combination%47)==45)*GBar46[l][m] + ((combination%47)==44)*GBar45[l][m] + ((combination%47)==43)*GBar44[l][m] + ((combination%47)==42)*GBar43[l][m] + ((combination%47)==41)*GBar42[l][m] + ((combination%47)==40)*GBar41[l][m] + ((combination%47)==39)*GBar40[l][m] +
+                                        ((combination%47)==38)*GBar39[l][m] + ((combination%47)==37)*GBar38[l][m] + ((combination%47)==36)*GBar37[l][m] + ((combination%47)==35)*GBar36[l][m] + ((combination%47)==34)*GBar35[l][m] + ((combination%47)==33)*GBar34[l][m] + ((combination%47)==32)*GBar33[l][m] + ((combination%47)==31)*GBar32[l][m] + ((combination%47)==30)*GBar31[l][m] + ((combination%47)==29)*GBar30[l][m] +
+                                        ((combination%47)==28)*GBar29[l][m] + ((combination%47)==27)*GBar28[l][m] + ((combination%47)==26)*GBar27[l][m] + ((combination%47)==25)*GBar26[l][m] + ((combination%47)==24)*GBar25[l][m] + ((combination%47)==23)*GBar24[l][m] + ((combination%47)==22)*GBar23[l][m] + ((combination%47)==21)*GBar22[l][m] + ((combination%47)==20)*GBar21[l][m] + ((combination%47)==19)*GBar20[l][m] +
+                                        ((combination%47)==18)*GBar19[l][m] + ((combination%47)==17)*GBar18[l][m] + ((combination%47)==16)*GBar17[l][m] + ((combination%47)==15)*GBar16[l][m] + ((combination%47)==14)*GBar15[l][m] + ((combination%47)==13)*GBar14[l][m] + ((combination%47)==12)*GBar13[l][m] + ((combination%47)==11)*GBar12[l][m] + ((combination%47)==10)*GBar11[l][m] + ((combination%47)==9)*GBar10[l][m] +
+                                        ((combination%47)==8)*GBar9[l][m] + ((combination%47)==7)*GBar8[l][m] + ((combination%47)==6)*GBar7[l][m] + ((combination%47)==5)*GBar6[l][m] + ((combination%47)==4)*GBar5[l][m] + ((combination%47)==3)*GBar4[l][m] + ((combination%47)==2)*GBar3[l][m] + ((combination%47)==1)*GBar2[l][m] + ((combination%47)==0)*GBar1[l][m]);
+       }
+      }
+      Kcounter = Kcounter + (n1-Kcombo);
+
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      
+      combination /= 47;
+    }
+
+    /*printf("G[%d]:\n", j);
+    printMatrix(G[j], N, N);
+    printf("GBar[%d]:\n", j);
+    printMatrix(GBar[j], N, N);
+
+    printf("h[%d]:\n", j);
+    printVector(h[j], N);
+
+    printf("J[%d]:\n", j);
+    printMatrix(J[j], K[j], K[j]);
+    
+    printf("D[%d]:\n", j);
+    printVector(D[j], K[j]);
+
+    printf("Q[%d]=%d\n", j, Q[j]);*/
+
+  }
+  //exit(0);
+
+  while(readPaulicoeffs(&omega[Paulicounter], alpha[Paulicounter], beta[Paulicounter], gamma[Paulicounter], delta[Paulicounter], N)) {
+
+    if((Paulicounter+1) > N) {
+      printf("Error: Number of Paulis is greater than N!\n");
+      return 1;
+    }
+    
+    // Let's break up the Ys into Xs and Zs in the order Z X, as required to pass to measurepauli()
+    // Y_i = -I*Z*X
+    for(i=0; i<N; i++) {
+      if(delta[Paulicounter][i]){
+       omega[Paulicounter] += 3; // -I = I^3
+       beta[Paulicounter][i] = delta[Paulicounter][i];
+       gamma[Paulicounter][i] = delta[Paulicounter][i];
+      }
+    }
+
+    /*printf("*******\n");
+    printf("*******\n");
+    printf("omega=%d\n", omega);
+    printf("X:\n");
+    printVector(gamma, N);
+    printf("Z:\n");
+    printVector(beta, N);
+    printf("*******\n");
+    printf("*******\n");*/
+
+    //for(j=0; j<pow(47,N/12); j++) { // the kets
+
+      /*printf("========\n");
+      printf("before:\n");
+      printf("K=%d\n", K[j]);
+      printf("h:\n");
+      printVector(h[j], N);
+      printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
+      printf("G:\n");
+      printMatrix(G[j], N, N);
+      printf("GBar:\n");
+      printMatrix(GBar[j], N, N);
+      printf("Q=%d\n", Q[j]);
+      printf("D:\n");
+      printVector(D[j], K[j]);
+      printf("J:\n");
+      printMatrix(J[j], K[j], K[j]);*/
+      //Gamma[j] *= measurepauli(N, &K[j], h[j], G[j], GBar[j], &Q[j], &D[j], &J[j], omega, gamma, beta);
+      /*printf("\nafter:\n");
+      printf("K=%d\n", K[j]);
+      printf("h:\n");
+      printVector(h[j], N);
+      printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
+      printf("G:\n");
+      printMatrix(G[j], N, N);
+      printf("GBar:\n");
+      printMatrix(GBar[j], N, N);
+      printf("Q=%d\n", Q[j]);
+      printf("D:\n");
+      printVector(D[j], K[j]);
+      printf("J:\n");
+      printMatrix(J[j], K[j], K[j]);*/
+
+    //}
+
+    Paulicounter++;
+  }
+
+  double complex amplitude = 0.0 + 0.0*I;
+  for(i=0; i<NUMSTABSTATESAMPLES; i++) { // the bras
+    //printf("i=%d\n", i);
+
+    randomstabilizerstate(N, &origK, &origh, &origG, &origGBar, &origQ, &origD, &origJ, Pd);
+
+    origGamma = 1.0 + 0.0*I;
+    
+    for(k=0; k<Paulicounter; k++) {
+      origGamma *= measurepauli(N, &origK, origh, origG, origGBar, &origQ, &origD, &origJ, omega[k], gamma[k], beta[k]);
+      //printf("k=%d\n", k);
+  }
+    /*printf("origK=%d\n", origK);
+    printf("origG:\n");
+    printMatrix(origG, N, N);
+    printf("origGBar:\n");
+    printMatrix(origGBar, N, N);
+    printf("origh:\n");
+    printVector(origh, N);*/
+
+    double complex stabstateaverage = 0.0 + 0.0*I;
+    
+    for(j=0; j<pow(47,N/12); j++) {
+      //printf("j=%d\n", j);
+      double complex newamplitude = innerproduct(N, K[j], h[j], G[j], GBar[j], Q[j], D[j], J[j], N, origK, origh, origG, origGBar, origQ, origD, origJ);
+      stabstateaverage = stabstateaverage + origGamma*Gamma[j]*newamplitude;
+    }
+    amplitude = amplitude + conj(stabstateaverage)*stabstateaverage/((double)(NUMSTABSTATESAMPLES))*pow(2.0,T);
+
+    deallocate_mem(&origG, N);
+    deallocate_mem(&origGBar, N);
+    free(origh);
+    deallocate_mem(&origJ, origK);
+    free(origD);
+  }
+
+  printf("amplitude:\n");
+  if(creal(amplitude+ZEROTHRESHOLD)>0)
+    printf("%.10lf %c %.10lf I\n", cabs(creal(amplitude)), cimag(amplitude+ZEROTHRESHOLD)>0?'+':'-' , cabs(cimag(amplitude)));
+  else
+    printf("%.10lf %c %.10lf I\n", creal(amplitude), cimag(amplitude+ZEROTHRESHOLD)>0?'+':'-' , cabs(cimag(amplitude)));
+  
+  
+
+  for(i=0; i<PdN; i++) 
+    free(Pd[i]);
+  free(Pd);
+
+  return 0;
+}
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits)
+{
+    
+  int newomega, newalpha, newbeta, newgamma, newdelta;
+  int i;
+
+  if(scanf("%d", &newomega) != EOF) {
+    *omega = newomega;
+    for(i=0; i<numqubits; i++) {
+      if(scanf("%d %d %d %d", &newalpha, &newbeta, &newgamma, &newdelta) == EOF) {
+       printf("Error: Too few input coeffs!\n");
+       exit(0);
+      }
+      if(newalpha+newbeta+newgamma+newdelta > 1) {
+       printf("Error: Too many coefficients are non-zero at Pauli %d!\n", i);
+       exit(0);
+      }
+      alpha[i] = newalpha; beta[i] = newbeta; gamma[i] = newgamma; delta[i] = newdelta;
+    }
+    return 1;
+  } else
+    return 0;
+    
+}
diff --git a/strongsim1_relerr.c b/strongsim1_relerr.c
new file mode 100644 (file)
index 0000000..33210a1
--- /dev/null
@@ -0,0 +1,409 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <complex.h>
+#include <time.h>
+#include "matrix.h"
+#include "exponentialsum.h"
+#include "shrinkstar.h"
+#include "extend.h"
+#include "measurepauli.h"
+#include "innerproduct.h"
+#include "randomstabilizerstate.h"
+
+#define ZEROTHRESHOLD (0.00000001)
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits);
+
+// order of matrix elements is [row][column]!!!
+
+int main(int argc, char *argv[])
+{
+
+  if(argc != 2) {
+    printf("strongsim2_rellerr argument: \"number of stabilizer state samples\"\n");
+    exit(0);
+  }
+
+  int NUMSTABSTATESAMPLES = atoi(argv[1]);        // number of stabilizer state samples
+
+  int N;                  // number of qubits
+  scanf("%d", &N);
+
+  //if(N%2 != 0) {
+  //  printf("'N' needs to be a multiple of 2 for a k=2 tensor factor decomposition!\n");
+  //  return 1;
+  //}
+
+  int T;              // number of T gate magic states (set to the first 'K' of the 'N' qubits -- the rest are set to the '0' computational basis state)
+  scanf("%d", &T);
+
+  int omega[N]; // max of N measurements
+  int alpha[N][N], beta[N][N], gamma[N][N], delta[N][N]; // max of N measurements of N Paulis
+  int Paulicounter = 0;
+
+  int i, j, k, l, m;
+
+  FILE *fp;
+  char buff[255];
+
+  srand((unsigned)time(NULL)); // seeding the random number generator for randomstabilizerstate()
+  
+  fp = fopen("Pd.txt", "r");
+
+  if(fscanf(fp, "%s", buff) == EOF) {
+    printf("Error: Pd.txt should start with the number N of P(d) of values tabulated.");
+    return 1;
+  }
+  
+  double** Pd;
+
+  int PdN = atoi(buff);
+
+  Pd = calloc(PdN, sizeof(double*));
+  for(i=0; i<PdN; i++) 
+    Pd[i] = calloc(PdN+1, sizeof(double));
+
+  double tmp;
+  
+  for(i=0; i<PdN; i++) {
+    tmp = 0.0;
+    for(j=0; j<=(i+1); j++) {
+      if(fscanf(fp, "%s", buff) == EOF) {
+       printf("Error: expected more values tabulated for P(d) for N=%d", PdN);
+       return 1;
+      }
+      Pd[i][j] = atof(buff);
+      //printf("%e ", Pd[i][j]);
+      tmp += Pd[i][j];
+    }
+    //printf("\n");
+    //printf("total=%f\n", tmp);
+  }
+
+
+  double complex coeffa = (1.0/sqrt(2.0))*cexp(0.0*PI*I);
+  double complex coeffb = (1.0/sqrt(2.0))*cexp(0.25*PI*I);
+
+  int n1 = 1; int k1 = 0; int (*(G1[])) = { (int[]) {1} }; int (*(GBar1[])) = { (int[]) {1} }; int h1[] = {0}; int Q1 = 0; int D1[] = {0}; int (*(J1[])) = { (int[]) {0} };
+  int n2 = 1; int k2 = 0; int (*(G2[])) = { (int[]) {1} }; int (*(GBar2[])) = { (int[]) {1} }; int h2[] = {1}; int Q2 = 0; int D2[] = {0}; int (*(J2[])) = { (int[]) {0} };
+
+  int *K; int ***G; int ***GBar; int **h; int *Q; int **D; int ***J;
+  double complex Gamma[(int)pow(2,N)]; // prefactor in front of resultant state
+  G = calloc(pow(2,N),sizeof(int*)); GBar = calloc(pow(2,N),sizeof(int*));
+  h = calloc(pow(2,N),sizeof(int*));
+  
+  J = calloc(pow(2,N),sizeof(int*)); D = calloc(pow(2,N),sizeof(int*)); Q = calloc(pow(2,N),sizeof(int));
+
+  K = calloc(pow(2,N), sizeof(int));
+
+  int origK, origQ, *origD;
+  int **origJ;
+  int **origG, **origGBar;
+  int *origh;
+  double complex origGamma;
+
+  int combination; // a particular combination from the linear combo of stabilizer states making up the tensor factors multiplied together
+  
+
+  for(j=0; j<pow(2,N); j++) { // there will be 2^(N) combinations when using k=12 tensor factors
+
+    combination = j;
+
+    K[j] = 0.0;
+    
+    for(k=0; k<N; k++) {
+      K[j] += (((combination%2)==1)*k2 + ((combination%2)==0)*k1);
+      combination /= 2;
+    }
+    combination = j;
+
+    Gamma[j] = 1.0;
+
+    G[j] = calloc(N, sizeof(int*)); GBar[j] = calloc(N, sizeof(int*));
+    h[j] = calloc(N, sizeof(int));
+
+    if(K[j] > 0) {
+      J[j] = calloc(K[j], sizeof(int*)); D[j] = calloc(K[j], sizeof(int));
+      for(k=0; k<K[j]; k++)
+       J[j][k] = calloc(K[j], sizeof(int));
+    }
+
+    for(k=0; k<N; k++) {
+      G[j][k] = calloc(N, sizeof(int)); GBar[j][k] = calloc(N, sizeof(int));
+    }
+
+    int Kcounter = 0; // Kcounter keeps track of the K<=N that we have added already to the G rows etc. for each combination that is indexed by the digits (base 2) of 'j' in that we go through with 'k'
+    int Kcombo; // Kcombo stores the k<(n1=n2) dimension of the member of the combination that we are currently adding
+    for(k=0; k<N; k++) {
+
+      Q[j] += (((combination%2)==1)*Q2 + ((combination%2)==0)*Q1);
+      
+
+      Gamma[j] *= (((combination%2)==1)*coeffb + ((combination%2)==0)*coeffa);
+
+      Kcombo = (((combination%2)==1)*k2 + ((combination%2)==0)*k1);
+      for(l=0; l<Kcombo; l++) {
+       // D1 has a different number of rows 'l' than D2 and D3 so you need to use something like 'switch' to check combination%2 without going out of bound of J1
+       switch(combination%2) {
+       case 0:
+         D[j][Kcounter+l] = D1[l];
+         break;
+       case 1:
+         D[j][Kcounter+l] = D2[l];
+         break;
+       default:
+         printf("error");
+         return 1;
+         }
+       for(m=0; m<Kcombo; m++) {
+         // J1 has a different number of rows 'l' than J2 and J3 so you need to use something like 'switch' to check combination%2 without going out of bound of J1
+         switch(combination%2) {
+         case 0:
+           J[j][Kcounter+l][Kcounter+m] = J1[l][m];
+           break;
+         case 1:
+           J[j][Kcounter+l][Kcounter+m] = J2[l][m];
+           break;
+         default:
+           printf("error");
+           return 1;
+         }
+       }
+      }
+
+      for(l=0; l<n1; l++) { // assuming n1=n2=n3
+       h[j][k*n1+l] = (((combination%2)==1)*h2[l] + ((combination%2)==0)*h1[l]);
+      }
+      // only filling the K[j] first rows of G and GBar here corresponding to the basis for D and J
+      for(l=0; l<Kcombo; l++) {
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         G[j][Kcounter+l][k*n1+m] = (((combination%2)==1)*G2[l][m] + ((combination%2)==0)*G1[l][m]);
+         GBar[j][Kcounter+l][k*n1+m] = (((combination%2)==1)*GBar2[l][m] + ((combination%2)==0)*GBar1[l][m]);
+       }
+      }
+      Kcounter = Kcounter + Kcombo;
+      
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      //memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
+
+      //memcpy(origJ[j][k], J[j][k], K[j]*sizeof(int));
+      
+      combination /= 2; // shift to the right by one (in base-7 arithmetic)
+    }
+    //printf("!\n");
+
+    // now need to fill the N-Kcounter remaining rows of G and GBar that are outside the spanning basis states of D and J
+    combination = j;
+    for(k=0; k<(N); k++) {
+      Kcombo = (((combination%2)==1)*k2 + ((combination%2)==0)*k1);
+      //printf("Kcounter=%d\n", Kcounter);
+      // G and GBar rows that are outside the first 'k' spanning basis states
+      for(l=Kcombo; l<n1; l++) { // assuming n1=n2=n3
+       //printf("l=%d\n", l);
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         /* printf("m=%d\n", m); */
+         /* printf("Kcounter+l=%d\n", Kcounter+l); */
+         /* printf("k*n1+m=%d\n", k*n1+m); */
+         G[j][Kcounter+l-Kcombo][k*n1+m] = (((combination%2)==1)*G2[l][m] + ((combination%2)==0)*G1[l][m]);
+         GBar[j][Kcounter+l-Kcombo][k*n1+m] = (((combination%2)==1)*GBar2[l][m] + ((combination%2)==0)*GBar1[l][m]);
+       }
+      }
+      Kcounter = Kcounter + (n1-Kcombo);
+
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      
+      combination /= 2;
+    }
+
+    /*printf("G[%d]:\n", j);
+    printMatrix(G[j], N, N);
+    printf("GBar[%d]:\n", j);
+    printMatrix(GBar[j], N, N);
+
+    printf("h[%d]:\n", j);
+    printVector(h[j], N);
+
+    printf("J[%d]:\n", j);
+    printMatrix(J[j], K[j], K[j]);
+    
+    printf("D[%d]:\n", j);
+    printVector(D[j], K[j]);
+
+    printf("Q[%d]=%d\n", j, Q[j]);*/
+
+  }
+  //exit(0);
+
+  while(readPaulicoeffs(&omega[Paulicounter], alpha[Paulicounter], beta[Paulicounter], gamma[Paulicounter], delta[Paulicounter], N)) {
+
+    if((Paulicounter+1) > N) {
+      printf("Error: Number of Paulis is greater than N!\n");
+      return 1;
+    }
+    
+    // Let's break up the Ys into Xs and Zs in the order Z X, as required to pass to measurepauli()
+    // Y_i = -I*Z*X
+    for(i=0; i<N; i++) {
+      if(delta[Paulicounter][i]){
+       omega[Paulicounter] += 3; // -I = I^3
+       beta[Paulicounter][i] = delta[Paulicounter][i];
+       gamma[Paulicounter][i] = delta[Paulicounter][i];
+      }
+    }
+
+    /*printf("*******\n");
+    printf("*******\n");
+    printf("omega=%d\n", omega);
+    printf("X:\n");
+    printVector(gamma, N);
+    printf("Z:\n");
+    printVector(beta, N);
+    printf("*******\n");
+    printf("*******\n");*/
+
+    //for(j=0; j<pow(2,N); j++) { // the kets
+
+      /*printf("========\n");
+      printf("before:\n");
+      printf("K=%d\n", K[j]);
+      printf("h:\n");
+      printVector(h[j], N);
+      printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
+      printf("G:\n");
+      printMatrix(G[j], N, N);
+      printf("GBar:\n");
+      printMatrix(GBar[j], N, N);
+      printf("Q=%d\n", Q[j]);
+      printf("D:\n");
+      printVector(D[j], K[j]);
+      printf("J:\n");
+      printMatrix(J[j], K[j], K[j]);*/
+      //Gamma[j] *= measurepauli(N, &K[j], h[j], G[j], GBar[j], &Q[j], &D[j], &J[j], omega[Paulicounter], gamma[Paulicounter], beta[Paulicounter]);
+      /*printf("\nafter:\n");
+      printf("K=%d\n", K[j]);
+      printf("h:\n");
+      printVector(h[j], N);
+      printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
+      printf("G:\n");
+      printMatrix(G[j], N, N);
+      printf("GBar:\n");
+      printMatrix(GBar[j], N, N);
+      printf("Q=%d\n", Q[j]);
+      printf("D:\n");
+      printVector(D[j], K[j]);
+      printf("J:\n");
+      printMatrix(J[j], K[j], K[j]);*/
+
+    //}
+
+    Paulicounter++;
+  }
+
+  double complex amplitude = 0.0 + 0.0*I;
+  for(i=0; i<NUMSTABSTATESAMPLES; i++) { // the bras
+    //printf("i=%d\n", i);
+
+    randomstabilizerstate(N, &origK, &origh, &origG, &origGBar, &origQ, &origD, &origJ, Pd);
+    /*printf("origK=%d\n", origK);
+    printf("origG:\n");
+    printMatrix(origG, N, N);
+    printf("origGBar:\n");
+    printMatrix(origGBar, N, N);
+    printf("origh:\n");
+    printVector(origh, N);
+    printf("origQ=%d\n", origQ);
+    printf("origD:\n");
+    printVector(origD, origK);
+    printf("origJ:\n");
+    printMatrix(origJ, origK, origK);*/
+
+    origGamma = 1.0 + 0.0*I;
+    
+    for(k=Paulicounter-1; k>=0; k--) { // go backwards through the measurements since acting on the bra (doesn't matter if they commute though)
+      origGamma *= measurepauli(N, &origK, origh, origG, origGBar, &origQ, &origD, &origJ, omega[k], gamma[k], beta[k]);
+      //printf("k=%d\n", k);
+    }
+    /*printf("origK=%d\n", origK);
+    printf("origG:\n");
+    printMatrix(origG, N, N);
+    printf("origGBar:\n");
+    printMatrix(origGBar, N, N);
+    printf("origh:\n");
+    printVector(origh, N);*/
+
+    double complex stabstateaverage = 0.0 + 0.0*I;
+    
+    for(j=0; j<pow(2,N); j++) {
+      //printf("j=%d\n", j);
+      /*  printf("K=%d\n", K[j]);
+    printf("G:\n");
+    printMatrix(G[j], N, N);
+    printf("h:\n");
+    printVector(h[j], N);
+    printf("Q=%d\n", Q[j]);
+    printf("D:\n");
+    printVector(D[j], K[j]);
+    printf("J:\n");
+    printMatrix(J[j], K[j], K[j]);*/
+      double complex newamplitude = innerproduct(N, K[j], h[j], G[j], GBar[j], Q[j], D[j], J[j], N, origK, origh, origG, origGBar, origQ, origD, origJ);
+      /*printf("newamplitude = %lf + %lf i\n", creal(newamplitude), cimag(newamplitude));
+      printf("origGamma = %lf + %lf i\n", creal(origGamma), cimag(origGamma));
+      printf("Gamma = %lf + %lf i\n", creal(Gamma[j]), cimag(Gamma[j]));*/
+      stabstateaverage = stabstateaverage + conj(origGamma)*Gamma[j]*newamplitude;
+    }
+    amplitude = amplitude + conj(stabstateaverage)*stabstateaverage/((double complex)(NUMSTABSTATESAMPLES))*cpow(2.0,T);
+
+    deallocate_mem(&origG, N);
+    deallocate_mem(&origGBar, N);
+    free(origh);
+    deallocate_mem(&origJ, origK);
+    free(origD);
+  }
+
+  printf("amplitude:\n");
+  if(creal(amplitude+ZEROTHRESHOLD)>0)
+    printf("%.10lf %c %.10lf I\n", cabs(creal(amplitude)), cimag(amplitude+ZEROTHRESHOLD)>0?'+':'-' , cabs(cimag(amplitude)));
+  else
+    printf("%.10lf %c %.10lf I\n", creal(amplitude), cimag(amplitude+ZEROTHRESHOLD)>0?'+':'-' , cabs(cimag(amplitude)));
+  
+  
+
+  for(i=0; i<PdN; i++) 
+    free(Pd[i]);
+  free(Pd);
+
+  return 0;
+}
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits)
+{
+    
+  int newomega, newalpha, newbeta, newgamma, newdelta;
+  int i;
+
+  if(scanf("%d", &newomega) != EOF) {
+    *omega = newomega;
+    for(i=0; i<numqubits; i++) {
+      if(scanf("%d %d %d %d", &newalpha, &newbeta, &newgamma, &newdelta) == EOF) {
+       printf("Error: Too few input coeffs!\n");
+       exit(0);
+      }
+      if(newalpha+newbeta+newgamma+newdelta > 1) {
+       printf("Error: Too many coefficients are non-zero at Pauli %d!\n", i);
+       exit(0);
+      }
+      alpha[i] = newalpha; beta[i] = newbeta; gamma[i] = newgamma; delta[i] = newdelta;
+    }
+    return 1;
+  } else
+    return 0;
+    
+}
diff --git a/strongsim2.c b/strongsim2.c
new file mode 100644 (file)
index 0000000..3b9b36b
--- /dev/null
@@ -0,0 +1,210 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <complex.h>
+#include "matrix.h"
+#include "exponentialsum.h"
+#include "shrink.h"
+#include "extend.h"
+#include "measurepauli.h"
+#include "innerproduct.h"
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits);
+
+// order of matrix elements is [row][column]!!!
+
+int main()
+{
+
+  int N;              // number of qubits
+  scanf("%d", &N);
+
+  if(N%2 != 0) {
+    printf("'N' needs to be an even number for a k=2 tensor factor decomposition!\n");
+    return 1;
+  }
+
+  int T;              // number of T gate magic states (set to the first 'K' of the 'N' qubits -- the rest are set to the '0' computational basis state)
+  scanf("%d", &T);  
+
+  int omega;
+  int alpha[N], beta[N], gamma[N], delta[N];
+  int Paulicounter = 0;
+
+  int i, j, k, l, m;
+
+
+  int n1 = 2; int k1 = 1; int (*(G1[])) = { (int[]) {1, 1}, (int[]) {0, 1} }; int (*(GBar1[])) = { (int[]) {1, 0}, (int[]) {1, 1} }; int h1[] = {0, 0}; int Q1 = 0; int D1[] = {2}; int (*(J1[])) = { (int[]) {4} };
+  int n2 = 2; int k2 = 1; int (*(G2[])) = { (int[]) {1, 1}, (int[]) {0, 1} }; int (*(GBar2[])) = { (int[]) {1, 0}, (int[]) {1, 1} }; int h2[] = {0, 1}; int Q2 = 0; int D2[] = {0}; int (*(J2[])) = { (int[]) {0} };
+
+  int *K; int ***G; int ***GBar; int **h; int *Q; int **D; int ***J;
+  double complex Gamma[(int)pow(2.0,N/2)]; // prefactor in front of resultant state
+  G = calloc(pow(2,N/2),sizeof(int*)); GBar = calloc(pow(2,N/2),sizeof(int*));
+  h = calloc(pow(2,N/2),sizeof(int*));
+  
+  J = calloc(pow(2,N/2),sizeof(int*)); D = calloc(pow(2,N/2),sizeof(int*)); Q = calloc(pow(2,N/2),sizeof(int));
+
+  K = calloc(pow(2,N/2), sizeof(int));
+
+  double complex origGamma[(int)pow(2,N/2)];
+  int *origK, *origQ, **origD, ***origJ;
+  int ***origG, ***origGBar, **origh;
+
+  origG = calloc(pow(2,N/2),sizeof(int*)); origGBar = calloc(pow(2,N/2),sizeof(int*));
+  origh = calloc(pow(2,N/2),sizeof(int*));
+  
+  origJ = calloc(pow(2,N/2),sizeof(int*)); origD = calloc(pow(2,N/2),sizeof(int*)); origQ = calloc(pow(2,N/2),sizeof(int));
+
+  origK = calloc(pow(2,N/2), sizeof(int));
+
+  int combination; // a particular combination from the linear combo of stabilizer states making up the tensor factors multiplied together
+  
+
+  for(j=0; j<pow(2,N/2); j++) { // there will be 2^(N/2) combinations when using k=2 tensor factors
+
+    K[j] = k1*N/2; // assuming k1=k2
+    origK[j] = K[j];
+
+    combination = j;
+
+    Gamma[j] = 1.0;
+    
+    G[j] = calloc(N, sizeof(int*)); GBar[j] = calloc(N, sizeof(int*));
+    h[j] = calloc(N, sizeof(int));
+
+    if(K[j] > 0) {
+      J[j] = calloc(K[j], sizeof(int*)); D[j] = calloc(K[j], sizeof(int));
+      for(k=0; k<K[j]; k++)
+       J[j][k] = calloc(K[j], sizeof(int));
+    }
+
+    origG[j] = calloc(N, sizeof(int*)); origGBar[j] = calloc(N, sizeof(int*));
+    origh[j] = calloc(N, sizeof(int));
+    
+    if(K[j] > 0) {
+      origJ[j] = calloc(K[j], sizeof(int*)); origD[j] = calloc(K[j], sizeof(int));
+      for(k=0; k<K[j]; k++)
+       origJ[j][k] = calloc(K[j], sizeof(int));
+    }
+
+    for(k=0; k<N/2; k++) {
+
+      Q[j] += (combination & 0x1)*Q2 + (~combination & 0x1)*Q1;
+      
+      Gamma[j] *= (1.0/sqrt(2.0))*((combination & 0x1)*cexp(0.25*PI*I) + (~combination & 0x1)*cexp(0.0*PI*I));
+      
+      G[j][k] = calloc(N, sizeof(int)); GBar[j][k] = calloc(N, sizeof(int));
+      G[j][N/2+k] = calloc(N, sizeof(int)); GBar[j][N/2+k] = calloc(N, sizeof(int));
+
+      origG[j][k] = calloc(N, sizeof(int)); origGBar[j][k] = calloc(N, sizeof(int));
+      origG[j][N/2+k] = calloc(N, sizeof(int)); origGBar[j][N/2+k] = calloc(N, sizeof(int));
+      
+      for(l=0; l<k1; l++) { // assuming k1=k2
+       D[j][k*k1+l] = (combination & 0x1)*D2[l] + (~combination & 0x1)*D1[l];
+       for(m=0; m<k1; m++) // assuming k1=k2
+         J[j][k*k1+l][k*k1+m] = (combination & 0x1)*J2[l][m] + (~combination & 0x1)*J1[l][m];
+      }
+           
+      for(l=0; l<n1; l++) { // assuming n1=n2
+       h[j][k*n1+l] = (combination & 0x1)*h2[l] + (~combination & 0x1)*h1[l];
+       G[j][k][k*n1+l] = (combination & 0x1)*G2[0][l] + (~combination & 0x1)*G1[0][l];
+       G[j][N/2+k][k*n1+l] = (combination & 0x1)*G2[1][l] + (~combination & 0x1)*G1[1][l]; // basis outside of support
+       GBar[j][k][k*n1+l] = (combination & 0x1)*GBar2[0][l] + (~combination & 0x1)*GBar1[0][l];
+       GBar[j][N/2+k][k*n1+l] = (combination & 0x1)*GBar2[1][l] + (~combination & 0x1)*GBar1[1][l]; // basis outside of support
+      }
+      memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
+      memcpy(origG[j][N/2+k], G[j][N/2+k], N*sizeof(int)); memcpy(origGBar[j][N/2+k], GBar[j][N/2+k], N*sizeof(int));
+
+      memcpy(origJ[j][k], J[j][k], K[j]*sizeof(int));
+      
+      combination /= 2; // shift to the right by one (in base-2 arithmetic)
+    }
+
+    memcpy(origh[j], h[j], N*sizeof(int));
+    memcpy(origD[j], D[j], K[j]*sizeof(int));
+
+  }
+  memcpy(origGamma, Gamma, pow(2,N/2)*sizeof(double complex));
+
+  memcpy(origQ, Q, pow(2,N/2)*sizeof(int));
+
+  while(readPaulicoeffs(&omega, alpha, beta, gamma, delta, N)) {
+
+    Paulicounter++;
+    if(Paulicounter > N) {
+      printf("Error: Number of Paulis is greater than N!\n");
+      return 1;
+    }
+    
+    // Let's break up the Ys into Xs and Zs in the order Z X, as required to pass to measurepauli()
+    // Y_i = -I*Z*X
+    for(i=0; i<N; i++) {
+      if(delta[i]){
+       omega += 3; // -I = I^3
+       beta[i] = delta[i];
+       gamma[i] = delta[i];
+      }
+    }
+
+    for(j=0; j<pow(2,N/2); j++) { // the kets
+
+      Gamma[j] *= measurepauli(N, &K[j], h[j], G[j], GBar[j], &Q[j], &D[j], &J[j], omega, gamma, beta);
+
+    }
+
+  }
+
+  double complex amplitude = 0.0 + 0.0*I;
+  for(i=0; i<pow(2,N/2); i++) { // the bras
+    for(j=0; j<pow(2,N/2); j++) {
+      // check to see if second arguments are modified!!! They shouldn't be!
+      double complex newamplitude = innerproduct(N, K[j], h[j], G[j], GBar[j], Q[j], D[j], J[j], N, origK[i], origh[i], origG[i], origGBar[i], origQ[i], origD[i], origJ[i]);
+      amplitude = amplitude + conj(origGamma[i])*Gamma[j]*newamplitude;
+    }
+  }
+
+  printf("amplitude:\n");
+  if(creal(amplitude+0.00000001)>0)
+    printf("%lf %c %lf I\n", cabs(creal(amplitude)), cimag(amplitude)>0?'+':'-' , cabs(cimag(amplitude)));
+  else
+    printf("%lf %c %lf I\n", creal(amplitude), cimag(amplitude)>0?'+':'-' , cabs(cimag(amplitude)));
+  //printf("%lf %c %lf I\n", creal(amplitude), cimag(amplitude)>0?'+':'-' , cabs(cimag(amplitude)));
+
+  return 0;
+
+}
+
+
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits)
+{
+    
+  int newomega, newalpha, newbeta, newgamma, newdelta;
+  int i;
+
+  if(scanf("%d", &newomega) != EOF) {
+    *omega = newomega;
+    for(i=0; i<numqubits; i++) {
+      if(scanf("%d %d %d %d", &newalpha, &newbeta, &newgamma, &newdelta) == EOF) {
+       printf("Error: Too few input coeffs!\n");
+       exit(0);
+      }
+      if(newalpha+newbeta+newgamma+newdelta > 1) {
+       printf("Error: Too many coefficients are non-zero at Pauli %d!\n", i);
+       exit(0);
+      }
+      alpha[i] = newalpha; beta[i] = newbeta; gamma[i] = newgamma; delta[i] = newdelta;
+    }
+    return 1;
+  } else
+    return 0;
+    
+}
+
+
+
+
+
+
+
diff --git a/strongsim2_relerr.c b/strongsim2_relerr.c
new file mode 100644 (file)
index 0000000..ca1f0b8
--- /dev/null
@@ -0,0 +1,396 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <complex.h>
+#include <time.h>
+#include "matrix.h"
+#include "exponentialsum.h"
+#include "shrinkstar.h"
+#include "extend.h"
+#include "measurepauli.h"
+#include "innerproduct.h"
+#include "randomstabilizerstate.h"
+
+#define ZEROTHRESHOLD (0.00000001)
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits);
+
+// order of matrix elements is [row][column]!!!
+
+int main(int argc, char *argv[])
+{
+
+  if(argc != 2) {
+    printf("strongsim2_rellerr argument: \"number of stabilizer state samples\"\n");
+    exit(0);
+  }
+
+  int NUMSTABSTATESAMPLES = atoi(argv[1]);        // number of stabilizer state samples
+
+  int N;                  // number of qubits
+  scanf("%d", &N);
+
+  if(N%2 != 0) {
+    printf("'N' needs to be a multiple of 2 for a k=2 tensor factor decomposition!\n");
+    return 1;
+  }
+
+  int T;              // number of T gate magic states (set to the first 'K' of the 'N' qubits -- the rest are set to the '0' computational basis state)
+  scanf("%d", &T);
+
+  int omega[N]; // max of N measurements
+  int alpha[N][N], beta[N][N], gamma[N][N], delta[N][N]; // max of N measurements of N Paulis
+  int Paulicounter = 0;
+
+  int i, j, k, l, m;
+
+  FILE *fp;
+  char buff[255];
+
+  srand((unsigned)time(NULL)); // seeding the random number generator for randomstabilizerstate()
+  
+  fp = fopen("Pd.txt", "r");
+
+  if(fscanf(fp, "%s", buff) == EOF) {
+    printf("Error: Pd.txt should start with the number N of P(d) of values tabulated.");
+    return 1;
+  }
+  
+  double** Pd;
+
+  int PdN = atoi(buff);
+
+  Pd = calloc(PdN, sizeof(double*));
+  for(i=0; i<PdN; i++) 
+    Pd[i] = calloc(PdN+1, sizeof(double));
+
+  double tmp;
+  
+  for(i=0; i<PdN; i++) {
+    tmp = 0.0;
+    for(j=0; j<=(i+1); j++) {
+      if(fscanf(fp, "%s", buff) == EOF) {
+       printf("Error: expected more values tabulated for P(d) for N=%d", PdN);
+       return 1;
+      }
+      Pd[i][j] = atof(buff);
+      //printf("%e ", Pd[i][j]);
+      tmp += Pd[i][j];
+    }
+    //printf("\n");
+    //printf("total=%f\n", tmp);
+  }
+
+
+  double complex coeffa = (1.0/sqrt(2.0))*cexp(0.0*PI*I);
+  double complex coeffb = (1.0/sqrt(2.0))*cexp(0.25*PI*I);
+
+  int n1 = 2; int k1 = 1; int (*(G1[])) = { (int[]) {1, 1}, (int[]) {0, 1} }; int (*(GBar1[])) = { (int[]) {1, 0}, (int[]) {1, 1} }; int h1[] = {0, 0}; int Q1 = 0; int D1[] = {2}; int (*(J1[])) = { (int[]) {4} };
+  int n2 = 2; int k2 = 1; int (*(G2[])) = { (int[]) {1, 1}, (int[]) {0, 1} }; int (*(GBar2[])) = { (int[]) {1, 0}, (int[]) {1, 1} }; int h2[] = {0, 1}; int Q2 = 0; int D2[] = {0}; int (*(J2[])) = { (int[]) {0} };
+
+  int *K; int ***G; int ***GBar; int **h; int *Q; int **D; int ***J;
+  double complex Gamma[(int)pow(2,N/2)]; // prefactor in front of resultant state
+  G = calloc(pow(2,N/2),sizeof(int*)); GBar = calloc(pow(2,N/2),sizeof(int*));
+  h = calloc(pow(2,N/2),sizeof(int*));
+  
+  J = calloc(pow(2,N/2),sizeof(int*)); D = calloc(pow(2,N/2),sizeof(int*)); Q = calloc(pow(2,N/2),sizeof(int));
+
+  K = calloc(pow(2,N/2), sizeof(int));
+
+  int origK, origQ, *origD;
+  int **origJ;
+  int **origG, **origGBar;
+  int *origh;
+  double complex origGamma;
+
+  int combination; // a particular combination from the linear combo of stabilizer states making up the tensor factors multiplied together
+  
+
+  for(j=0; j<pow(2,N/2); j++) { // there will be 2^(N/2) combinations when using k=12 tensor factors
+
+    combination = j;
+
+    K[j] = 0.0;
+    
+    for(k=0; k<N/2; k++) {
+      K[j] += (((combination%2)==1)*k2 + ((combination%2)==0)*k1);
+      combination /= 2;
+    }
+    combination = j;
+
+    Gamma[j] = 1.0;
+
+    G[j] = calloc(N, sizeof(int*)); GBar[j] = calloc(N, sizeof(int*));
+    h[j] = calloc(N, sizeof(int));
+
+    if(K[j] > 0) {
+      J[j] = calloc(K[j], sizeof(int*)); D[j] = calloc(K[j], sizeof(int));
+      for(k=0; k<K[j]; k++)
+       J[j][k] = calloc(K[j], sizeof(int));
+    }
+
+    for(k=0; k<N; k++) {
+      G[j][k] = calloc(N, sizeof(int)); GBar[j][k] = calloc(N, sizeof(int));
+    }
+
+    int Kcounter = 0; // Kcounter keeps track of the K<=N that we have added already to the G rows etc. for each combination that is indexed by the digits (base 2) of 'j' in that we go through with 'k'
+    int Kcombo; // Kcombo stores the k<(n1=n2) dimension of the member of the combination that we are currently adding
+    for(k=0; k<N/2; k++) {
+
+      Q[j] += (((combination%2)==1)*Q2 + ((combination%2)==0)*Q1);
+      
+
+      Gamma[j] *= (((combination%2)==1)*coeffb + ((combination%2)==0)*coeffa);
+
+      Kcombo = (((combination%2)==1)*k2 + ((combination%2)==0)*k1);
+      for(l=0; l<Kcombo; l++) {
+       // D1 has a different number of rows 'l' than D2 and D3 so you need to use something like 'switch' to check combination%2 without going out of bound of J1
+       switch(combination%2) {
+       case 0:
+         D[j][Kcounter+l] = D1[l];
+         break;
+       case 1:
+         D[j][Kcounter+l] = D2[l];
+         break;
+       default:
+         printf("error");
+         return 1;
+         }
+       for(m=0; m<Kcombo; m++) {
+         // J1 has a different number of rows 'l' than J2 and J3 so you need to use something like 'switch' to check combination%2 without going out of bound of J1
+         switch(combination%2) {
+         case 0:
+           J[j][Kcounter+l][Kcounter+m] = J1[l][m];
+           break;
+         case 1:
+           J[j][Kcounter+l][Kcounter+m] = J2[l][m];
+           break;
+         default:
+           printf("error");
+           return 1;
+         }
+       }
+      }
+
+      for(l=0; l<n1; l++) { // assuming n1=n2=n3
+       h[j][k*n1+l] = (((combination%2)==1)*h2[l] + ((combination%2)==0)*h1[l]);
+      }
+      // only filling the K[j] first rows of G and GBar here corresponding to the basis for D and J
+      for(l=0; l<Kcombo; l++) {
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         G[j][Kcounter+l][k*n1+m] = (((combination%2)==1)*G2[l][m] + ((combination%2)==0)*G1[l][m]);
+         GBar[j][Kcounter+l][k*n1+m] = (((combination%2)==1)*GBar2[l][m] + ((combination%2)==0)*GBar1[l][m]);
+       }
+      }
+      Kcounter = Kcounter + Kcombo;
+      
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      //memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
+
+      //memcpy(origJ[j][k], J[j][k], K[j]*sizeof(int));
+      
+      combination /= 2; // shift to the right by one (in base-7 arithmetic)
+    }
+    //printf("!\n");
+
+    // now need to fill the N-Kcounter remaining rows of G and GBar that are outside the spanning basis states of D and J
+    combination = j;
+    for(k=0; k<(N/2); k++) {
+      Kcombo = (((combination%2)==1)*k2 + ((combination%2)==0)*k1);
+      //printf("Kcounter=%d\n", Kcounter);
+      // G and GBar rows that are outside the first 'k' spanning basis states
+      for(l=Kcombo; l<n1; l++) { // assuming n1=n2=n3
+       //printf("l=%d\n", l);
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         /* printf("m=%d\n", m); */
+         /* printf("Kcounter+l=%d\n", Kcounter+l); */
+         /* printf("k*n1+m=%d\n", k*n1+m); */
+         G[j][Kcounter+l-Kcombo][k*n1+m] = (((combination%2)==1)*G2[l][m] + ((combination%2)==0)*G1[l][m]);
+         GBar[j][Kcounter+l-Kcombo][k*n1+m] = (((combination%2)==1)*GBar2[l][m] + ((combination%2)==0)*GBar1[l][m]);
+       }
+      }
+      Kcounter = Kcounter + (n1-Kcombo);
+
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      
+      combination /= 2;
+    }
+
+    /*printf("G[%d]:\n", j);
+    printMatrix(G[j], N, N);
+    printf("GBar[%d]:\n", j);
+    printMatrix(GBar[j], N, N);
+
+    printf("h[%d]:\n", j);
+    printVector(h[j], N);
+
+    printf("J[%d]:\n", j);
+    printMatrix(J[j], K[j], K[j]);
+    
+    printf("D[%d]:\n", j);
+    printVector(D[j], K[j]);
+
+    printf("Q[%d]=%d\n", j, Q[j]);*/
+
+  }
+  //exit(0);
+
+  while(readPaulicoeffs(&omega[Paulicounter], alpha[Paulicounter], beta[Paulicounter], gamma[Paulicounter], delta[Paulicounter], N)) {
+
+    if((Paulicounter+1) > N) {
+      printf("Error: Number of Paulis is greater than N!\n");
+      return 1;
+    }
+    
+    // Let's break up the Ys into Xs and Zs in the order Z X, as required to pass to measurepauli()
+    // Y_i = -I*Z*X
+    for(i=0; i<N; i++) {
+      if(delta[Paulicounter][i]){
+       omega[Paulicounter] += 3; // -I = I^3
+       beta[Paulicounter][i] = delta[Paulicounter][i];
+       gamma[Paulicounter][i] = delta[Paulicounter][i];
+      }
+    }
+
+    /*printf("*******\n");
+    printf("*******\n");
+    printf("omega=%d\n", omega);
+    printf("X:\n");
+    printVector(gamma, N);
+    printf("Z:\n");
+    printVector(beta, N);
+    printf("*******\n");
+    printf("*******\n");*/
+
+    //for(j=0; j<pow(2,N/2); j++) { // the kets
+
+      /*printf("========\n");
+      printf("before:\n");
+      printf("K=%d\n", K[j]);
+      printf("h:\n");
+      printVector(h[j], N);
+      printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
+      printf("G:\n");
+      printMatrix(G[j], N, N);
+      printf("GBar:\n");
+      printMatrix(GBar[j], N, N);
+      printf("Q=%d\n", Q[j]);
+      printf("D:\n");
+      printVector(D[j], K[j]);
+      printf("J:\n");
+      printMatrix(J[j], K[j], K[j]);*/
+      //Gamma[j] *= measurepauli(N, &K[j], h[j], G[j], GBar[j], &Q[j], &D[j], &J[j], omega[Paulicounter], gamma[Paulicounter], beta[Paulicounter]);
+      /*printf("\nafter:\n");
+      printf("K=%d\n", K[j]);
+      printf("h:\n");
+      printVector(h[j], N);
+      printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
+      printf("G:\n");
+      printMatrix(G[j], N, N);
+      printf("GBar:\n");
+      printMatrix(GBar[j], N, N);
+      printf("Q=%d\n", Q[j]);
+      printf("D:\n");
+      printVector(D[j], K[j]);
+      printf("J:\n");
+      printMatrix(J[j], K[j], K[j]);*/
+
+    //}
+
+    Paulicounter++;
+  }
+
+  double complex amplitude = 0.0 + 0.0*I;
+  for(i=0; i<NUMSTABSTATESAMPLES; i++) { // the bras
+    //printf("i=%d\n", i);
+
+    randomstabilizerstate(N, &origK, &origh, &origG, &origGBar, &origQ, &origD, &origJ, Pd);
+    /*printf("origK=%d\n", origK);
+    printf("origG:\n");
+    printMatrix(origG, N, N);
+    printf("origGBar:\n");
+    printMatrix(origGBar, N, N);
+    printf("origh:\n");
+    printVector(origh, N);
+    printf("origQ=%d\n", origQ);
+    printf("origD:\n");
+    printVector(origD, origK);
+    printf("origJ:\n");
+    printMatrix(origJ, origK, origK);*/
+
+    origGamma = 1.0 + 0.0*I;
+    
+    for(k=Paulicounter-1; k>=0; k--) { // go backwards through the measurements since acting on the bra (doesn't matter if they commute though)
+      origGamma *= measurepauli(N, &origK, origh, origG, origGBar, &origQ, &origD, &origJ, omega[k], gamma[k], beta[k]);
+      //printf("k=%d\n", k);
+    }
+    /*printf("origK=%d\n", origK);
+    printf("origG:\n");
+    printMatrix(origG, N, N);
+    printf("origGBar:\n");
+    printMatrix(origGBar, N, N);
+    printf("origh:\n");
+    printVector(origh, N);*/
+
+    double complex stabstateaverage = 0.0 + 0.0*I;
+    
+    for(j=0; j<pow(2,N/2); j++) {
+      //printf("j=%d\n", j);
+      double complex newamplitude = innerproduct(N, K[j], h[j], G[j], GBar[j], Q[j], D[j], J[j], N, origK, origh, origG, origGBar, origQ, origD, origJ);
+      stabstateaverage = stabstateaverage + conj(origGamma)*Gamma[j]*newamplitude;
+    }
+    amplitude = amplitude + conj(stabstateaverage)*stabstateaverage/((double complex)(NUMSTABSTATESAMPLES))*cpow(2.0,T);
+
+    deallocate_mem(&origG, N);
+    deallocate_mem(&origGBar, N);
+    free(origh);
+    deallocate_mem(&origJ, origK);
+    free(origD);
+  }
+
+  printf("amplitude:\n");
+  if(creal(amplitude+ZEROTHRESHOLD)>0)
+    printf("%.10lf %c %.10lf I\n", cabs(creal(amplitude)), cimag(amplitude+ZEROTHRESHOLD)>0?'+':'-' , cabs(cimag(amplitude)));
+  else
+    printf("%.10lf %c %.10lf I\n", creal(amplitude), cimag(amplitude+ZEROTHRESHOLD)>0?'+':'-' , cabs(cimag(amplitude)));
+  
+  
+
+  for(i=0; i<PdN; i++) 
+    free(Pd[i]);
+  free(Pd);
+
+  return 0;
+}
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits)
+{
+    
+  int newomega, newalpha, newbeta, newgamma, newdelta;
+  int i;
+
+  if(scanf("%d", &newomega) != EOF) {
+    *omega = newomega;
+    for(i=0; i<numqubits; i++) {
+      if(scanf("%d %d %d %d", &newalpha, &newbeta, &newgamma, &newdelta) == EOF) {
+       printf("Error: Too few input coeffs!\n");
+       exit(0);
+      }
+      if(newalpha+newbeta+newgamma+newdelta > 1) {
+       printf("Error: Too many coefficients are non-zero at Pauli %d!\n", i);
+       exit(0);
+      }
+      alpha[i] = newalpha; beta[i] = newbeta; gamma[i] = newgamma; delta[i] = newdelta;
+    }
+    return 1;
+  } else
+    return 0;
+    
+}
diff --git a/strongsim3.c b/strongsim3.c
new file mode 100644 (file)
index 0000000..389a737
--- /dev/null
@@ -0,0 +1,286 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <complex.h>
+#include "matrix.h"
+#include "exponentialsum.h"
+#include "shrink.h"
+#include "extend.h"
+#include "measurepauli.h"
+#include "innerproduct.h"
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits);
+
+// order of matrix elements is [row][column]!!!
+
+int main()
+{
+
+  int N;              // number of qubits
+  scanf("%d", &N);
+
+  if(N%3 != 0) {
+    printf("'N' needs to be a multiple of 3 for a k=3 tensor factor decomposition!\n");
+    return 1;
+  }
+
+  int T;              // number of T gate magic states (set to the first 'K' of the 'N' qubits -- the rest are set to the '0' computational basis state)
+  scanf("%d", &T);  
+
+  int omega;
+  int alpha[N], beta[N], gamma[N], delta[N];
+  int Paulicounter = 0;
+
+  int i, j, k, l, m;
+
+  double complex coeffa = -0.25*(1.0-I)*(-1.0-I+sqrt(2.0))*csqrt(-I);
+  double complex coeffb = 0.25*(-1.0-I)*(1.0-I+sqrt(2.0))*csqrt(I);
+  double complex coeffc = 0.25*(-1.0-I)*(-1.0+I+sqrt(2.0))*csqrt(I);
+
+  int n1 = 3; int k1 = 1; int (*(G1[])) = { (int[]) {1, 1, 1}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1}}; int (*(GBar1[])) = { (int[]) {1, 0, 0}, (int[]) {1, 1, 0}, (int[]) {1, 0, 1}}; int h1[] = {1, 1, 0}; int Q1 = 0; int D1[] = {2}; int (*(J1[])) = { (int[]) {4} };
+  int n2 = 3; int k2 = 3; int (*(G2[])) = { (int[]) {1, 0, 0}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1} }; int (*(GBar2[])) = { (int[]) {1, 0, 0}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1} }; int h2[] = {0, 0, 0}; int Q2 = 2; int D2[] = {2, 2, 0}; int (*(J2[])) = { (int[]) {4, 0, 0}, (int[]) {0, 4, 0}, (int[]) {0, 0, 0} };
+  int n3 = 3; int k3 = 3; int (*(G3[])) = { (int[]) {1, 0, 0}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1} }; int (*(GBar3[])) = { (int[]) {1, 0, 0}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1} }; int h3[] = {0, 0, 0}; int Q3 = 2; int D3[] = {6, 6, 0}; int (*(J3[])) = { (int[]) {4, 4, 4}, (int[]) {4, 4, 4}, (int[]) {4, 4, 0} };
+
+  int *K; int ***G; int ***GBar; int **h; int *Q; int **D; int ***J;
+  double complex Gamma[(int)pow(3,N/3)]; // prefactor in front of resultant state
+  G = calloc(pow(3,N/3),sizeof(int*)); GBar = calloc(pow(3,N/3),sizeof(int*));
+  h = calloc(pow(3,N/3),sizeof(int*));
+  
+  J = calloc(pow(3,N/3),sizeof(int*)); D = calloc(pow(3,N/3),sizeof(int*)); Q = calloc(pow(3,N/3),sizeof(int));
+
+  K = calloc(pow(3,N/3), sizeof(int));
+
+  double complex origGamma[(int)pow(3,N/3)];
+  int *origK, *origQ, **origD, ***origJ;
+  int ***origG, ***origGBar, **origh;
+
+  origG = calloc(pow(3,N/3),sizeof(int*)); origGBar = calloc(pow(3,N/3),sizeof(int*));
+  origh = calloc(pow(3,N/3),sizeof(int*));
+  
+  origJ = calloc(pow(3,N/3),sizeof(int*)); origD = calloc(pow(3,N/3),sizeof(int*)); origQ = calloc(pow(3,N/3),sizeof(int));
+
+  origK = calloc(pow(3,N/3), sizeof(int));
+
+  int combination; // a particular combination from the linear combo of stabilizer states making up the tensor factors multiplied together
+  
+
+  for(j=0; j<pow(3,N/3); j++) { // there will be 3^(N/3) combinations when using k=3 tensor factors
+
+    combination = j;
+
+    K[j] = 0.0;
+    
+    for(k=0; k<N/3; k++) {
+      K[j] += (((combination%3)==2)*k3 + ((combination%3)==1)*k2 + ((combination%3)==0)*k1);
+      combination /= 3;
+    }
+    combination = j;
+    origK[j] = K[j];
+
+    Gamma[j] = 1.0;
+
+    G[j] = calloc(N, sizeof(int*)); GBar[j] = calloc(N, sizeof(int*));
+    h[j] = calloc(N, sizeof(int));
+
+    if(K[j] > 0) {
+      J[j] = calloc(K[j], sizeof(int*)); D[j] = calloc(K[j], sizeof(int));
+      for(k=0; k<K[j]; k++)
+       J[j][k] = calloc(K[j], sizeof(int));
+    }
+
+    origG[j] = calloc(N, sizeof(int*)); origGBar[j] = calloc(N, sizeof(int*));
+    origh[j] = calloc(N, sizeof(int));
+
+    if(K[j] > 0) {
+      origJ[j] = calloc(K[j], sizeof(int*)); origD[j] = calloc(K[j], sizeof(int));
+      for(k=0; k<K[j]; k++)
+       origJ[j][k] = calloc(K[j], sizeof(int));
+    }
+
+    for(k=0; k<N; k++) {
+      G[j][k] = calloc(N, sizeof(int)); GBar[j][k] = calloc(N, sizeof(int));
+      origG[j][k] = calloc(N, sizeof(int)); origGBar[j][k] = calloc(N, sizeof(int));
+    }
+
+    int Kcounter = 0; // Kcounter keeps track of the K<=N that we have added already to the G rows etc. for each combination that is indexed by the digits (base 3) of 'j' in that we go through with 'k'
+    int Kcombo; // Kcombo stores the k<(n1=n2=n3) dimension of the member of the combination that we are currently adding
+    for(k=0; k<N/3; k++) {
+
+      Q[j] += ((combination%3)==2)*Q3 + ((combination%3)==1)*Q2 + ((combination%3)==0)*Q1;
+      
+      Gamma[j] *= (((combination%3)==2)*coeffc + ((combination%3)==1)*coeffb + ((combination%3)==0)*coeffa);
+
+      Kcombo = (((combination%3)==2)*k3 + ((combination%3)==1)*k2 + ((combination%3)==0)*k1);
+      for(l=0; l<Kcombo; l++) {
+         // D1 has a different number of rows 'l' than D2 and D3 so you need to use something like 'switch' to check combination%3 without going out of bound of J1
+         switch(combination%3) {
+         case 0:
+           D[j][Kcounter+l] = D1[l];
+           break;
+         case 1:
+           D[j][Kcounter+l] = D2[l];
+           break;
+         case 2:
+           D[j][Kcounter+l] = D3[l];
+           break;
+         default:
+           printf("error");
+           return 1;
+         }
+       for(m=0; m<Kcombo; m++) {
+         // J1 has a different number of rows 'l' than J2 and J3 so you need to use something like 'switch' to check combination%3 without going out of bound of J1
+         switch(combination%3) {
+         case 0:
+           J[j][Kcounter+l][Kcounter+m] = J1[l][m];
+           break;
+         case 1:
+           J[j][Kcounter+l][Kcounter+m] = J2[l][m];
+           break;
+         case 2:
+           J[j][Kcounter+l][Kcounter+m] = J3[l][m];
+           break;
+         default:
+           printf("error");
+           return 1;
+         }
+       }
+      }
+
+      for(l=0; l<n1; l++) { // assuming n1=n2=n3
+       h[j][k*n1+l] = ((combination%3)==2)*h3[l] + ((combination%3)==1)*h2[l] + ((combination%3)==0)*h1[l];
+      }
+      // only filling the K[j] first rows of G and GBar here corresponding to the basis for D and J
+      for(l=0; l<Kcombo; l++) {
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         G[j][Kcounter+l][k*n1+m] = ((combination%3)==2)*G3[l][m] + ((combination%3)==1)*G2[l][m] + ((combination%3)==0)*G1[l][m];
+         GBar[j][Kcounter+l][k*n1+m] = ((combination%3)==2)*GBar3[l][m] + ((combination%3)==1)*GBar2[l][m] + ((combination%3)==0)*GBar1[l][m];
+       }
+      }
+      Kcounter = Kcounter + Kcombo;
+      
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      //memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
+
+      //memcpy(origJ[j][k], J[j][k], K[j]*sizeof(int));
+      
+      combination /= 3; // shift to the right by one (in base-3 arithmetic)
+    }
+    //printf("!\n");
+
+    // now need to fill the N-Kcounter remaining rows of G and GBar that are outside the spanning basis states of D and J
+    combination = j;
+    for(k=0; k<(N/3); k++) {
+      Kcombo = (((combination%3)==2)*k3 + ((combination%3)==1)*k2 + ((combination%3)==0)*k1);
+      //printf("Kcounter=%d\n", Kcounter);
+      // G and GBar rows that are outside the first 'k' spanning basis states
+      for(l=Kcombo; l<n1; l++) { // assuming n1=n2=n3
+       //printf("l=%d\n", l);
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         /* printf("m=%d\n", m); */
+         /* printf("Kcounter+l=%d\n", Kcounter+l); */
+         /* printf("k*n1+m=%d\n", k*n1+m); */
+         G[j][Kcounter+l-Kcombo][k*n1+m] = ((combination%3)==2)*G3[l][m] + ((combination%3)==1)*G2[l][m] + ((combination%3)==0)*G1[l][m];
+         GBar[j][Kcounter+l-Kcombo][k*n1+m] = ((combination%3)==2)*GBar3[l][m] + ((combination%3)==1)*GBar2[l][m] + ((combination%3)==0)*GBar1[l][m];
+       }
+      }
+      Kcounter = Kcounter + (n1-Kcombo);
+
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      
+      combination /= 3;
+    }
+    for(k=0; k<N; k++) {
+      memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
+    }
+    for(k=0; k<K[j]; k++) {
+      memcpy(origJ[j][k], J[j][k], K[j]*sizeof(int));      
+    }
+
+    memcpy(origh[j], h[j], N*sizeof(int));
+    memcpy(origD[j], D[j], K[j]*sizeof(int));
+
+  }
+  //exit(0);
+  memcpy(origGamma, Gamma, pow(3,N/3)*sizeof(double complex));
+
+  memcpy(origQ, Q, pow(3,N/3)*sizeof(int));
+
+  while(readPaulicoeffs(&omega, alpha, beta, gamma, delta, N)) {
+  
+    Paulicounter++;
+    if(Paulicounter > N) {
+      printf("Error: Number of Paulis is greater than N!\n");
+      return 1;
+    }
+    
+    // Let's break up the Ys into Xs and Zs in the order Z X, as required to pass to measurepauli()
+    // Y_i = -I*Z*X
+    for(i=0; i<N; i++) {
+      if(delta[i]){
+       omega += 3; // -I = I^3
+       beta[i] = delta[i];
+       gamma[i] = delta[i];
+      }
+    }
+
+
+    for(j=0; j<pow(3,N/3); j++) { // the kets
+
+      Gamma[j] *= measurepauli(N, &K[j], h[j], G[j], GBar[j], &Q[j], &D[j], &J[j], omega, gamma, beta);
+
+    }
+
+  }
+
+  double complex amplitude = 0.0 + 0.0*I;
+  for(i=0; i<pow(3,N/3); i++) { // the bras
+    for(j=0; j<pow(3,N/3); j++) {
+      double complex newamplitude = innerproduct(N, K[j], h[j], G[j], GBar[j], Q[j], D[j], J[j], N, origK[i], origh[i], origG[i], origGBar[i], origQ[i], origD[i], origJ[i]);
+      amplitude = amplitude + conj(origGamma[i])*Gamma[j]*newamplitude;
+    }
+  }
+
+  printf("amplitude:\n");
+  if(creal(amplitude+0.00000001)>0)
+    printf("%lf %c %lf I\n", cabs(creal(amplitude)), cimag(amplitude+0.00000001)>0?'+':'-' , cabs(cimag(amplitude)));
+  else
+    printf("%lf %c %lf I\n", creal(amplitude), cimag(amplitude+0.00000001)>0?'+':'-' , cabs(cimag(amplitude)));
+  //printf("%lf %c %lf I\n", creal(amplitude), cimag(amplitude)>0?'+':'-' , cabs(cimag(amplitude)));
+
+  return 0;
+
+}
+
+
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits)
+{
+    
+  int newomega, newalpha, newbeta, newgamma, newdelta;
+  int i;
+
+  if(scanf("%d", &newomega) != EOF) {
+    *omega = newomega;
+    for(i=0; i<numqubits; i++) {
+      if(scanf("%d %d %d %d", &newalpha, &newbeta, &newgamma, &newdelta) == EOF) {
+       printf("Error: Too few input coeffs!\n");
+       exit(0);
+      }
+      if(newalpha+newbeta+newgamma+newdelta > 1) {
+       printf("Error: Too many coefficients are non-zero at Pauli %d!\n", i);
+       exit(0);
+      }
+      alpha[i] = newalpha; beta[i] = newbeta; gamma[i] = newgamma; delta[i] = newdelta;
+    }
+    return 1;
+  } else
+    return 0;
+    
+}
diff --git a/strongsim3_relerr.c b/strongsim3_relerr.c
new file mode 100644 (file)
index 0000000..24ec5b3
--- /dev/null
@@ -0,0 +1,393 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <complex.h>
+#include <time.h>
+#include "matrix.h"
+#include "exponentialsum.h"
+#include "shrinkstar.h"
+#include "extend.h"
+#include "measurepauli.h"
+#include "innerproduct.h"
+#include "randomstabilizerstate.h"
+
+#define ZEROTHRESHOLD (0.00000001)
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits);
+
+// order of matrix elements is [row][column]!!!
+
+int main(int argc, char *argv[])
+{
+
+  if(argc != 2) {
+    printf("strongsim3_rellerr argument: \"number of stabilizer state samples\"\n");
+    exit(0);
+  }
+
+  int NUMSTABSTATESAMPLES = atoi(argv[1]);        // number of stabilizer state samples
+
+  int N;                  // number of qubits
+  scanf("%d", &N);
+
+  if(N%3 != 0) {
+    printf("'N' needs to be a multiple of 3 for a k=3 tensor factor decomposition!\n");
+    return 1;
+  }
+
+  int T;              // number of T gate magic states (set to the first 'K' of the 'N' qubits -- the rest are set to the '0' computational basis state)
+  scanf("%d", &T);
+
+  int omega[N]; // max of N measurements
+  int alpha[N][N], beta[N][N], gamma[N][N], delta[N][N]; // max of N measurements of N Paulis
+  int Paulicounter = 0;
+
+  int i, j, k, l, m;
+
+  FILE *fp;
+  char buff[255];
+
+  srand((unsigned)time(NULL)); // seeding the random number generator for randomstabilizerstate()
+  
+  fp = fopen("Pd.txt", "r");
+
+  if(fscanf(fp, "%s", buff) == EOF) {
+    printf("Error: Pd.txt should start with the number N of P(d) of values tabulated.");
+    return 1;
+  }
+  
+  double** Pd;
+
+  int PdN = atoi(buff);
+
+  Pd = calloc(PdN, sizeof(double*));
+  for(i=0; i<PdN; i++) 
+    Pd[i] = calloc(PdN+1, sizeof(double));
+
+  double tmp;
+  
+  for(i=1; i<PdN; i++) {
+    tmp = 0.0;
+    for(j=0; j<=i; j++) {
+      if(fscanf(fp, "%s", buff) == EOF) {
+       printf("Error: expected more values tabulated for P(d) for N=%d", PdN);
+       return 1;
+      }
+      Pd[i][j] = atof(buff);
+      //printf("%e ", Pd[i][j]);
+      tmp += Pd[i][j];
+    }
+    //printf("\n");
+    //printf("total=%f\n", tmp);
+  }
+
+
+  double complex coeffa = -0.25*(1.0-I)*(-1.0-I+sqrt(2.0))*csqrt(-I);
+  double complex coeffb = 0.25*(-1.0-I)*(1.0-I+sqrt(2.0))*csqrt(I);
+  double complex coeffc = 0.25*(-1.0-I)*(-1.0+I+sqrt(2.0))*csqrt(I);
+
+  int n1 = 3; int k1 = 1; int (*(G1[])) = { (int[]) {1, 1, 1}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1}}; int (*(GBar1[])) = { (int[]) {1, 0, 0}, (int[]) {1, 1, 0}, (int[]) {1, 0, 1}}; int h1[] = {1, 1, 0}; int Q1 = 0; int D1[] = {2}; int (*(J1[])) = { (int[]) {4} };
+  int n2 = 3; int k2 = 3; int (*(G2[])) = { (int[]) {1, 0, 0}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1} }; int (*(GBar2[])) = { (int[]) {1, 0, 0}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1} }; int h2[] = {0, 0, 0}; int Q2 = 2; int D2[] = {2, 2, 0}; int (*(J2[])) = { (int[]) {4, 0, 0}, (int[]) {0, 4, 0}, (int[]) {0, 0, 0} };
+  int n3 = 3; int k3 = 3; int (*(G3[])) = { (int[]) {1, 0, 0}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1} }; int (*(GBar3[])) = { (int[]) {1, 0, 0}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1} }; int h3[] = {0, 0, 0}; int Q3 = 2; int D3[] = {6, 6, 0}; int (*(J3[])) = { (int[]) {4, 4, 4}, (int[]) {4, 4, 4}, (int[]) {4, 4, 0} };
+
+
+  int *K; int ***G; int ***GBar; int **h; int *Q; int **D; int ***J;
+  double complex Gamma[(int)pow(3,N/3)]; // prefactor in front of resultant state
+  G = calloc(pow(3,N/3),sizeof(int*)); GBar = calloc(pow(3,N/3),sizeof(int*));
+  h = calloc(pow(3,N/3),sizeof(int*));
+  
+  J = calloc(pow(3,N/3),sizeof(int*)); D = calloc(pow(3,N/3),sizeof(int*)); Q = calloc(pow(3,N/3),sizeof(int));
+
+  K = calloc(pow(3,N/3), sizeof(int));
+
+  int origK, origQ, *origD;
+  int **origJ;
+  int **origG, **origGBar;
+  int *origh;
+  double complex origGamma;
+
+  int combination; // a particular combination from the linear combo of stabilizer states making up the tensor factors multiplied together
+  
+
+  for(j=0; j<pow(3,N/3); j++) { // there will be 3^(N/3) combinations when using k=12 tensor factors
+
+    combination = j;
+
+    K[j] = 0.0;
+    
+    for(k=0; k<N/3; k++) {
+      K[j] += (((combination%3)==2)*k3 + ((combination%3)==1)*k2 + ((combination%3)==0)*k1);
+      combination /= 3;
+    }
+    combination = j;
+
+    Gamma[j] = 1.0;
+
+    G[j] = calloc(N, sizeof(int*)); GBar[j] = calloc(N, sizeof(int*));
+    h[j] = calloc(N, sizeof(int));
+
+    if(K[j] > 0) {
+      J[j] = calloc(K[j], sizeof(int*)); D[j] = calloc(K[j], sizeof(int));
+      for(k=0; k<K[j]; k++)
+       J[j][k] = calloc(K[j], sizeof(int));
+    }
+
+    for(k=0; k<N; k++) {
+      G[j][k] = calloc(N, sizeof(int)); GBar[j][k] = calloc(N, sizeof(int));
+    }
+
+    int Kcounter = 0; // Kcounter keeps track of the K<=N that we have added already to the G rows etc. for each combination that is indexed by the digits (base 3) of 'j' in that we go through with 'k'
+    int Kcombo; // Kcombo stores the k<(n1=n2=n3) dimension of the member of the combination that we are currently adding
+    for(k=0; k<N/3; k++) {
+
+      Q[j] += (((combination%3)==2)*Q3 + ((combination%3)==1)*Q2 + ((combination%3)==0)*Q1);
+      
+
+      Gamma[j] *= (((combination%3)==2)*coeffc + ((combination%3)==1)*coeffb + ((combination%3)==0)*coeffa);
+
+      Kcombo = (((combination%3)==2)*k3 + ((combination%3)==1)*k2 + ((combination%3)==0)*k1);
+      for(l=0; l<Kcombo; l++) {
+       // D1 has a different number of rows 'l' than D2 and D3 so you need to use something like 'switch' to check combination%3 without going out of bound of J1
+       switch(combination%3) {
+       case 0:
+         D[j][Kcounter+l] = D1[l];
+         break;
+       case 1:
+         D[j][Kcounter+l] = D2[l];
+         break;
+       case 2:
+         D[j][Kcounter+l] = D3[l];
+         break;
+       default:
+         printf("error");
+         return 1;
+         }
+       for(m=0; m<Kcombo; m++) {
+         // J1 has a different number of rows 'l' than J2 and J3 so you need to use something like 'switch' to check combination%3 without going out of bound of J1
+         switch(combination%3) {
+         case 0:
+           J[j][Kcounter+l][Kcounter+m] = J1[l][m];
+           break;
+         case 1:
+           J[j][Kcounter+l][Kcounter+m] = J2[l][m];
+           break;
+         case 2:
+           J[j][Kcounter+l][Kcounter+m] = J3[l][m];
+           break;
+         default:
+           printf("error");
+           return 1;
+         }
+       }
+      }
+
+      for(l=0; l<n1; l++) { // assuming n1=n2=n3
+       h[j][k*n1+l] = (((combination%3)==2)*h3[l] + ((combination%3)==1)*h2[l] + ((combination%3)==0)*h1[l]);
+      }
+      // only filling the K[j] first rows of G and GBar here corresponding to the basis for D and J
+      for(l=0; l<Kcombo; l++) {
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         G[j][Kcounter+l][k*n1+m] = (((combination%3)==2)*G3[l][m] + ((combination%3)==1)*G2[l][m] + ((combination%3)==0)*G1[l][m]);
+         GBar[j][Kcounter+l][k*n1+m] = (((combination%3)==2)*GBar3[l][m] + ((combination%3)==1)*GBar2[l][m] + ((combination%3)==0)*GBar1[l][m]);
+       }
+      }
+      Kcounter = Kcounter + Kcombo;
+      
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      //memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
+
+      //memcpy(origJ[j][k], J[j][k], K[j]*sizeof(int));
+      
+      combination /= 3; // shift to the right by one (in base-7 arithmetic)
+    }
+    //printf("!\n");
+
+    // now need to fill the N-Kcounter remaining rows of G and GBar that are outside the spanning basis states of D and J
+    combination = j;
+    for(k=0; k<(N/3); k++) {
+      Kcombo = (((combination%3)==2)*k3 + ((combination%3)==1)*k2 + ((combination%3)==0)*k1);
+      //printf("Kcounter=%d\n", Kcounter);
+      // G and GBar rows that are outside the first 'k' spanning basis states
+      for(l=Kcombo; l<n1; l++) { // assuming n1=n2=n3
+       //printf("l=%d\n", l);
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         /* printf("m=%d\n", m); */
+         /* printf("Kcounter+l=%d\n", Kcounter+l); */
+         /* printf("k*n1+m=%d\n", k*n1+m); */
+         G[j][Kcounter+l-Kcombo][k*n1+m] = (((combination%3)==2)*G3[l][m] + ((combination%3)==1)*G2[l][m] + ((combination%3)==0)*G1[l][m]);
+         GBar[j][Kcounter+l-Kcombo][k*n1+m] = (((combination%3)==2)*GBar3[l][m] + ((combination%3)==1)*GBar2[l][m] + ((combination%3)==0)*GBar1[l][m]);
+       }
+      }
+      Kcounter = Kcounter + (n1-Kcombo);
+
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      
+      combination /= 3;
+    }
+
+    /*printf("G[%d]:\n", j);
+    printMatrix(G[j], N, N);
+    printf("GBar[%d]:\n", j);
+    printMatrix(GBar[j], N, N);
+
+    printf("h[%d]:\n", j);
+    printVector(h[j], N);
+
+    printf("J[%d]:\n", j);
+    printMatrix(J[j], K[j], K[j]);
+    
+    printf("D[%d]:\n", j);
+    printVector(D[j], K[j]);
+
+    printf("Q[%d]=%d\n", j, Q[j]);*/
+
+  }
+  //exit(0);
+
+  while(readPaulicoeffs(&omega[Paulicounter], alpha[Paulicounter], beta[Paulicounter], gamma[Paulicounter], delta[Paulicounter], N)) {
+
+    if((Paulicounter+1) > N) {
+      printf("Error: Number of Paulis is greater than N!\n");
+      return 1;
+    }
+    
+    // Let's break up the Ys into Xs and Zs in the order Z X, as required to pass to measurepauli()
+    // Y_i = -I*Z*X
+    for(i=0; i<N; i++) {
+      if(delta[Paulicounter][i]){
+       omega[Paulicounter] += 3; // -I = I^3
+       beta[Paulicounter][i] = delta[Paulicounter][i];
+       gamma[Paulicounter][i] = delta[Paulicounter][i];
+      }
+    }
+
+    /*printf("*******\n");
+    printf("*******\n");
+    printf("omega=%d\n", omega);
+    printf("X:\n");
+    printVector(gamma, N);
+    printf("Z:\n");
+    printVector(beta, N);
+    printf("*******\n");
+    printf("*******\n");*/
+
+    //for(j=0; j<pow(3,N/3); j++) { // the kets
+
+      /*printf("========\n");
+      printf("before:\n");
+      printf("K=%d\n", K[j]);
+      printf("h:\n");
+      printVector(h[j], N);
+      printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
+      printf("G:\n");
+      printMatrix(G[j], N, N);
+      printf("GBar:\n");
+      printMatrix(GBar[j], N, N);
+      printf("Q=%d\n", Q[j]);
+      printf("D:\n");
+      printVector(D[j], K[j]);
+      printf("J:\n");
+      printMatrix(J[j], K[j], K[j]);*/
+      //Gamma[j] *= measurepauli(N, &K[j], h[j], G[j], GBar[j], &Q[j], &D[j], &J[j], omega, gamma, beta);
+      /*printf("\nafter:\n");
+      printf("K=%d\n", K[j]);
+      printf("h:\n");
+      printVector(h[j], N);
+      printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
+      printf("G:\n");
+      printMatrix(G[j], N, N);
+      printf("GBar:\n");
+      printMatrix(GBar[j], N, N);
+      printf("Q=%d\n", Q[j]);
+      printf("D:\n");
+      printVector(D[j], K[j]);
+      printf("J:\n");
+      printMatrix(J[j], K[j], K[j]);*/
+
+    //}
+
+    Paulicounter++;
+  }
+
+  double complex amplitude = 0.0 + 0.0*I;
+  for(i=0; i<NUMSTABSTATESAMPLES; i++) { // the bras
+    //printf("i=%d\n", i);
+
+    randomstabilizerstate(N, &origK, &origh, &origG, &origGBar, &origQ, &origD, &origJ, Pd);
+
+    origGamma = 1.0 + 0.0*I;
+    
+    for(k=0; k<Paulicounter; k++) {
+      origGamma *= measurepauli(N, &origK, origh, origG, origGBar, &origQ, &origD, &origJ, omega[k], gamma[k], beta[k]);
+      //printf("k=%d\n", k);
+  }
+    /*printf("origK=%d\n", origK);
+    printf("origG:\n");
+    printMatrix(origG, N, N);
+    printf("origGBar:\n");
+    printMatrix(origGBar, N, N);
+    printf("origh:\n");
+    printVector(origh, N);*/
+
+    double complex stabstateaverage = 0.0 + 0.0*I;
+    
+    for(j=0; j<pow(3,N/3); j++) {
+      //printf("j=%d\n", j);
+      double complex newamplitude = innerproduct(N, K[j], h[j], G[j], GBar[j], Q[j], D[j], J[j], N, origK, origh, origG, origGBar, origQ, origD, origJ);
+      stabstateaverage = stabstateaverage + origGamma*Gamma[j]*newamplitude;
+    }
+    amplitude = amplitude + conj(stabstateaverage)*stabstateaverage/((double)(NUMSTABSTATESAMPLES))*pow(2.0,T);
+
+    deallocate_mem(&origG, N);
+    deallocate_mem(&origGBar, N);
+    free(origh);
+    deallocate_mem(&origJ, origK);
+    free(origD);
+  }
+
+  printf("amplitude:\n");
+  if(creal(amplitude+ZEROTHRESHOLD)>0)
+    printf("%.10lf %c %.10lf I\n", cabs(creal(amplitude)), cimag(amplitude+ZEROTHRESHOLD)>0?'+':'-' , cabs(cimag(amplitude)));
+  else
+    printf("%.10lf %c %.10lf I\n", creal(amplitude), cimag(amplitude+ZEROTHRESHOLD)>0?'+':'-' , cabs(cimag(amplitude)));
+  
+  
+
+  for(i=0; i<PdN; i++) 
+    free(Pd[i]);
+  free(Pd);
+
+  return 0;
+}
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits)
+{
+    
+  int newomega, newalpha, newbeta, newgamma, newdelta;
+  int i;
+
+  if(scanf("%d", &newomega) != EOF) {
+    *omega = newomega;
+    for(i=0; i<numqubits; i++) {
+      if(scanf("%d %d %d %d", &newalpha, &newbeta, &newgamma, &newdelta) == EOF) {
+       printf("Error: Too few input coeffs!\n");
+       exit(0);
+      }
+      if(newalpha+newbeta+newgamma+newdelta > 1) {
+       printf("Error: Too many coefficients are non-zero at Pauli %d!\n", i);
+       exit(0);
+      }
+      alpha[i] = newalpha; beta[i] = newbeta; gamma[i] = newgamma; delta[i] = newdelta;
+    }
+    return 1;
+  } else
+    return 0;
+    
+}
diff --git a/strongsim6.c b/strongsim6.c
new file mode 100644 (file)
index 0000000..65d73fe
--- /dev/null
@@ -0,0 +1,378 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <complex.h>
+#include "matrix.h"
+#include "exponentialsum.h"
+#include "shrink.h"
+#include "extend.h"
+#include "measurepauli.h"
+#include "innerproduct.h"
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits);
+
+// order of matrix elements is [row][column]!!!
+
+int main()
+{
+
+  int N;              // number of qubits
+  scanf("%d", &N);
+
+  if(N%6 != 0) {
+    printf("'N' needs to be a multiple of 6 for a k=6 tensor factor decomposition!\n");
+    return 1;
+  }
+
+  int T;              // number of T gate magic states (set to the first 'K' of the 'N' qubits -- the rest are set to the '0' computational basis state)
+  scanf("%d", &T);  
+
+  int omega;
+  int alpha[N], beta[N], gamma[N], delta[N];
+  int Paulicounter = 0;
+
+  int i, j, k, l, m;
+
+  double complex coeffb60 = (-16.0+12.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(6.0*PI*I/8.0)/8.0*cpow(2.0,3.0);
+  double complex coeffb66 = (96.0-68.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(6.0*PI*I/8.0)/8.0*cpow(2.0,3.0);
+  double complex coeffe6 = (10.0-7.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(6.0*PI*I/8.0)*cpow(2.0,2.5);
+  double complex coeffo6 = (-14.0+10.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(-14.0*PI*I/8.0)*cpow(2.0,2.5);
+  double complex coeffk6 = (7.0-5.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(-8.0*PI*I/8.0)*4.0*csqrt(2.0)*cpow(2.0,0.5);
+  double complex coeffphiprime = (10.0-7.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(2.0*PI*I/8.0)*cpow(2.0,2.5);
+  double complex coeffphidprime = (10.0-7.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(2.0*PI*I/8.0)*cpow(2.0,2.5);
+
+  // b60
+  int n1 = 6; int k1 = 6; int (*(G1[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}}; int (*(GBar1[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}}; int h1[] = {0, 0, 0, 0, 0, 0}; int Q1 = 0; int D1[] = {0, 0, 0, 0, 0, 0}; int (*(J1[])) = { (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0} };
+  // b66
+  int n2 = 6; int k2 = 6; int (*(G2[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}}; int (*(GBar2[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}}; int h2[] = {0, 0, 0, 0, 0, 0}; int Q2 = 4; int D2[] = {4, 4, 4, 4, 4, 4}; int (*(J2[])) = { (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0} };
+  // e6
+  int n3 = 6; int k3 = 5; int (*(G3[])) = { (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0} }; int (*(GBar3[])) = { (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1} }; int h3[] = {1, 0, 0, 0, 0, 0}; int Q3 = 4; int D3[] = {0, 0, 0, 0, 0}; int (*(J3[])) = { (int[]) {0, 4, 4, 4, 4}, (int[]) {4, 0, 4, 4, 4}, (int[]) {4, 4, 0, 4, 4}, (int[]) {4, 4, 4, 0, 4}, (int[]) {4, 4, 4, 4, 0}  };
+  // o6
+  int n4 = 6; int k4 = 5; int (*(G4[])) = { (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0} }; int (*(GBar4[])) = { (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1} }; int h4[] = {0, 0, 0, 0, 0, 0}; int Q4 = 4; int D4[] = {4, 4, 4, 4, 4}; int (*(J4[])) = { (int[]) {0, 4, 4, 4, 4}, (int[]) {4, 0, 4, 4, 4}, (int[]) {4, 4, 0, 4, 4}, (int[]) {4, 4, 4, 0, 4}, (int[]) {4, 4, 4, 4, 0}  };
+  // k6
+  int n5 = 6; int k5 = 1; int (*(G5[])) = { (int[]) {1, 1, 1, 1, 1, 1}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1} }; int (*(GBar5[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1} }; int h5[] = {1, 1, 1, 1, 1, 1}; int Q5 = 6; int D5[] = {2}; int (*(J5[])) = { (int[]) {4} };
+  // phiprime
+  int n6 = 6; int k6 = 5; int (*(G6[])) = { (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0} }; int (*(GBar6[])) = { (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1} }; int h6[] = {1, 0, 0, 0, 0, 0}; int Q6 = 0; int D6[] = {0, 0, 0, 0, 0}; int (*(J6[])) = { (int[]) {0, 4, 0, 0, 4}, (int[]) {4, 0, 4, 0, 0}, (int[]) {0, 4, 0, 4, 0}, (int[]) {0, 0, 4, 0, 4}, (int[]) {4, 0, 0, 4, 0}  };
+  // phidoubleprime
+  int n7 = 6; int k7 = 5; int (*(G7[])) = { (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0} }; int (*(GBar7[])) = { (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1} }; int h7[] = {1, 0, 0, 0, 0, 0}; int Q7 = 0; int D7[] = {0, 0, 0, 0, 0}; int (*(J7[])) = { (int[]) {0, 0, 4, 4, 0}, (int[]) {0, 0, 0, 4, 4}, (int[]) {4, 0, 0, 0, 4}, (int[]) {4, 4, 0, 0, 0}, (int[]) {0, 4, 4, 0, 0}  };
+  
+  int *K; int ***G; int ***GBar; int **h; int *Q; int **D; int ***J;
+  double complex Gamma[(int)pow(7,N/6)]; // prefactor in front of resultant state
+  G = calloc(pow(7,N/6),sizeof(int*)); GBar = calloc(pow(7,N/6),sizeof(int*));
+  h = calloc(pow(7,N/6),sizeof(int*));
+  
+  J = calloc(pow(7,N/6),sizeof(int*)); D = calloc(pow(7,N/6),sizeof(int*)); Q = calloc(pow(7,N/6),sizeof(int));
+
+  K = calloc(pow(7,N/6), sizeof(int));
+
+  double complex origGamma[(int)pow(7,N/6)];
+  int *origK, *origQ, **origD, ***origJ;
+  int ***origG, ***origGBar, **origh;
+
+  origG = calloc(pow(7,N/6),sizeof(int*)); origGBar = calloc(pow(7,N/6),sizeof(int*));
+  origh = calloc(pow(7,N/6),sizeof(int*));
+  
+  origJ = calloc(pow(7,N/6),sizeof(int*)); origD = calloc(pow(7,N/6),sizeof(int*)); origQ = calloc(pow(7,N/6),sizeof(int));
+
+  origK = calloc(pow(7,N/6), sizeof(int));
+
+  int combination; // a particular combination from the linear combo of stabilizer states making up the tensor factors multiplied together
+  
+
+  for(j=0; j<pow(7,N/6); j++) { // there will be 7^(N/6) combinations when using k=3 tensor factors
+
+    combination = j;
+
+    K[j] = 0.0;
+    
+    for(k=0; k<N/6; k++) {
+      K[j] += (((combination%7)==6)*k7 + ((combination%7)==5)*k6 + ((combination%7)==4)*k5 + ((combination%7)==3)*k4 + ((combination%7)==2)*k3 + ((combination%7)==1)*k2 + ((combination%7)==0)*k1);
+      combination /= 7;
+    }
+    combination = j;
+    origK[j] = K[j];
+
+    Gamma[j] = 1.0;
+
+    G[j] = calloc(N, sizeof(int*)); GBar[j] = calloc(N, sizeof(int*));
+    h[j] = calloc(N, sizeof(int));
+
+    if(K[j] > 0) {
+      J[j] = calloc(K[j], sizeof(int*)); D[j] = calloc(K[j], sizeof(int));
+      for(k=0; k<K[j]; k++)
+       J[j][k] = calloc(K[j], sizeof(int));
+    }
+
+    origG[j] = calloc(N, sizeof(int*)); origGBar[j] = calloc(N, sizeof(int*));
+    origh[j] = calloc(N, sizeof(int));
+
+    if(K[j] > 0) {
+      origJ[j] = calloc(K[j], sizeof(int*)); origD[j] = calloc(K[j], sizeof(int));
+      for(k=0; k<K[j]; k++)
+       origJ[j][k] = calloc(K[j], sizeof(int));
+    }
+
+    for(k=0; k<N; k++) {
+      G[j][k] = calloc(N, sizeof(int)); GBar[j][k] = calloc(N, sizeof(int));
+      origG[j][k] = calloc(N, sizeof(int)); origGBar[j][k] = calloc(N, sizeof(int));
+    }
+
+    int Kcounter = 0; // Kcounter keeps track of the K<=N that we have added already to the G rows etc. for each combination that is indexed by the digits (base 3) of 'j' in that we go through with 'k'
+    int Kcombo; // Kcombo stores the k<(n1=n2=n3) dimension of the member of the combination that we are currently adding
+    for(k=0; k<N/6; k++) {
+
+      Q[j] += ((combination%7)==6)*Q7 + ((combination%7)==5)*Q6 + ((combination%7)==4)*Q5 + ((combination%7)==3)*Q4 + ((combination%7)==2)*Q3 + ((combination%7)==1)*Q2 + ((combination%7)==0)*Q1;
+      
+      Gamma[j] *= (((combination%7)==6)*coeffphidprime + ((combination%7)==5)*coeffphiprime + ((combination%7)==4)*coeffk6 + ((combination%7)==3)*coeffo6 + ((combination%7)==2)*coeffe6 + ((combination%7)==1)*coeffb66 + ((combination%7)==0)*coeffb60);
+
+      Kcombo = (((combination%7)==6)*k7 + ((combination%7)==5)*k6 + ((combination%7)==4)*k5 + ((combination%7)==3)*k4 + ((combination%7)==2)*k3 + ((combination%7)==1)*k2 + ((combination%7)==0)*k1);
+      for(l=0; l<Kcombo; l++) {
+       // D1 has a different number of rows 'l' than D2 and D3 so you need to use something like 'switch' to check combination%3 without going out of bound of J1
+       switch(combination%7) {
+       case 0:
+         D[j][Kcounter+l] = D1[l];
+         break;
+       case 1:
+         D[j][Kcounter+l] = D2[l];
+         break;
+       case 2:
+         D[j][Kcounter+l] = D3[l];
+         break;
+       case 3:
+         D[j][Kcounter+l] = D4[l];
+           break;
+       case 4:
+         D[j][Kcounter+l] = D5[l];
+         break;
+       case 5:
+         D[j][Kcounter+l] = D6[l];
+         break;
+       case 6:
+         D[j][Kcounter+l] = D7[l];
+         break;
+       default:
+         printf("error");
+         return 1;
+         }
+       for(m=0; m<Kcombo; m++) {
+         // J1 has a different number of rows 'l' than J2 and J3 so you need to use something like 'switch' to check combination%3 without going out of bound of J1
+         switch(combination%7) {
+         case 0:
+           J[j][Kcounter+l][Kcounter+m] = J1[l][m];
+           break;
+         case 1:
+             J[j][Kcounter+l][Kcounter+m] = J2[l][m];
+             break;
+         case 2:
+           J[j][Kcounter+l][Kcounter+m] = J3[l][m];
+           break;
+         case 3:
+           J[j][Kcounter+l][Kcounter+m] = J4[l][m];
+           break;
+           case 4:
+             J[j][Kcounter+l][Kcounter+m] = J5[l][m];
+             break;
+         case 5:
+           J[j][Kcounter+l][Kcounter+m] = J6[l][m];
+           break;
+         case 6:
+           J[j][Kcounter+l][Kcounter+m] = J7[l][m];
+           break;
+         default:
+           printf("error");
+           return 1;
+         }
+       }
+      }
+
+      for(l=0; l<n1; l++) { // assuming n1=n2=n3
+       h[j][k*n1+l] = ((combination%7)==6)*h7[l] + ((combination%7)==5)*h6[l] + ((combination%7)==4)*h5[l] + ((combination%7)==3)*h4[l] + ((combination%7)==2)*h3[l] + ((combination%7)==1)*h2[l] + ((combination%7)==0)*h1[l];
+      }
+      // only filling the K[j] first rows of G and GBar here corresponding to the basis for D and J
+      for(l=0; l<Kcombo; l++) {
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         G[j][Kcounter+l][k*n1+m] = ((combination%7)==6)*G7[l][m] + ((combination%7)==5)*G6[l][m] + ((combination%7)==4)*G5[l][m] + ((combination%7)==3)*G4[l][m] + ((combination%7)==2)*G3[l][m] + ((combination%7)==1)*G2[l][m] + ((combination%7)==0)*G1[l][m];
+         GBar[j][Kcounter+l][k*n1+m] = ((combination%7)==6)*GBar7[l][m] + ((combination%7)==5)*GBar6[l][m] + ((combination%7)==4)*GBar5[l][m] + ((combination%7)==3)*GBar4[l][m] + ((combination%7)==2)*GBar3[l][m] + ((combination%7)==1)*GBar2[l][m] + ((combination%7)==0)*GBar1[l][m];
+       }
+      }
+      Kcounter = Kcounter + Kcombo;
+      
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      //memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
+
+      //memcpy(origJ[j][k], J[j][k], K[j]*sizeof(int));
+      
+      combination /= 7; // shift to the right by one (in base-7 arithmetic)
+    }
+    //printf("!\n");
+
+    // now need to fill the N-Kcounter remaining rows of G and GBar that are outside the spanning basis states of D and J
+    combination = j;
+    for(k=0; k<(N/6); k++) {
+      Kcombo = (((combination%7)==6)*k7 + ((combination%7)==5)*k6 + ((combination%7)==4)*k5 + ((combination%7)==3)*k4 + ((combination%7)==2)*k3 + ((combination%7)==1)*k2 + ((combination%7)==0)*k1);
+      //printf("Kcounter=%d\n", Kcounter);
+      // G and GBar rows that are outside the first 'k' spanning basis states
+      for(l=Kcombo; l<n1; l++) { // assuming n1=n2=n3
+       //printf("l=%d\n", l);
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         /* printf("m=%d\n", m); */
+         /* printf("Kcounter+l=%d\n", Kcounter+l); */
+         /* printf("k*n1+m=%d\n", k*n1+m); */
+         G[j][Kcounter+l-Kcombo][k*n1+m] = ((combination%7)==6)*G7[l][m] + ((combination%7)==5)*G6[l][m] + ((combination%7)==4)*G5[l][m] + ((combination%7)==3)*G4[l][m] + ((combination%7)==2)*G3[l][m] + ((combination%7)==1)*G2[l][m] + ((combination%7)==0)*G1[l][m];
+         GBar[j][Kcounter+l-Kcombo][k*n1+m] = ((combination%7)==6)*GBar7[l][m] + ((combination%7)==5)*GBar6[l][m] + ((combination%7)==4)*GBar5[l][m] + ((combination%7)==3)*GBar4[l][m] + ((combination%7)==2)*GBar3[l][m] + ((combination%7)==1)*GBar2[l][m] + ((combination%7)==0)*GBar1[l][m];
+       }
+      }
+      Kcounter = Kcounter + (n1-Kcombo);
+
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      
+      combination /= 7;
+    }
+    for(k=0; k<N; k++) {
+      memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
+    }
+    for(k=0; k<K[j]; k++) {
+      memcpy(origJ[j][k], J[j][k], K[j]*sizeof(int));      
+    }
+
+    memcpy(origh[j], h[j], N*sizeof(int));
+    memcpy(origD[j], D[j], K[j]*sizeof(int));
+
+    printf("G[%d]:\n", j);
+    printMatrix(G[j], N, N);
+    printf("GBar[%d]:\n", j);
+    printMatrix(GBar[j], N, N);
+
+    printf("h[%d]:\n", j);
+    printVector(h[j], N);
+
+    printf("J[%d]:\n", j);
+    printMatrix(J[j], K[j], K[j]);
+    
+    printf("D[%d]:\n", j);
+    printVector(D[j], K[j]);
+
+    printf("Q[%d]=%d\n", j, Q[j]);
+
+  }
+  //exit(0);
+  memcpy(origGamma, Gamma, pow(7,N/6)*sizeof(double complex));
+
+  memcpy(origQ, Q, pow(7,N/6)*sizeof(int));
+
+  while(readPaulicoeffs(&omega, alpha, beta, gamma, delta, N)) {
+  
+    Paulicounter++;
+    if(Paulicounter > N) {
+      printf("Error: Number of Paulis is greater than N!\n");
+      return 1;
+    }
+    
+    // Let's break up the Ys into Xs and Zs in the order Z X, as required to pass to measurepauli()
+    // Y_i = -I*Z*X
+    for(i=0; i<N; i++) {
+      if(delta[i]){
+       omega += 3; // -I = I^3
+       beta[i] = delta[i];
+       gamma[i] = delta[i];
+      }
+    }
+
+    printf("*******\n");
+    printf("*******\n");
+    printf("omega=%d\n", omega);
+    printf("X:\n");
+    printVector(gamma, N);
+    printf("Z:\n");
+    printVector(beta, N);
+    printf("*******\n");
+    printf("*******\n");
+
+    for(j=0; j<pow(7,N/6); j++) { // the kets
+
+      printf("========\n");
+      printf("before:\n");
+      printf("K=%d\n", K[j]);
+      printf("h:\n");
+      printVector(h[j], N);
+      printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
+      printf("G:\n");
+      printMatrix(G[j], N, N);
+      printf("GBar:\n");
+      printMatrix(GBar[j], N, N);
+      printf("Q=%d\n", Q[j]);
+      printf("D:\n");
+      printVector(D[j], K[j]);
+      printf("J:\n");
+      printMatrix(J[j], K[j], K[j]);
+      Gamma[j] *= measurepauli(N, &K[j], h[j], G[j], GBar[j], &Q[j], &D[j], &J[j], omega, gamma, beta);
+      printf("\nafter:\n");
+      printf("K=%d\n", K[j]);
+      printf("h:\n");
+      printVector(h[j], N);
+      printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
+      printf("G:\n");
+      printMatrix(G[j], N, N);
+      printf("GBar:\n");
+      printMatrix(GBar[j], N, N);
+      printf("Q=%d\n", Q[j]);
+      printf("D:\n");
+      printVector(D[j], K[j]);
+      printf("J:\n");
+      printMatrix(J[j], K[j], K[j]);
+
+    }
+
+  }
+
+  double complex amplitude = 0.0 + 0.0*I;
+  for(i=0; i<pow(7,N/6); i++) { // the bras
+    for(j=0; j<pow(7,N/6); j++) {
+      double complex newamplitude = innerproduct(N, K[j], h[j], G[j], GBar[j], Q[j], D[j], J[j], N, origK[i], origh[i], origG[i], origGBar[i], origQ[i], origD[i], origJ[i]);
+      amplitude = amplitude + conj(origGamma[i])*Gamma[j]*newamplitude;
+    }
+  }
+
+  printf("amplitude:\n");
+  if(creal(amplitude+0.00000001)>0)
+    printf("%.10lf %c %.10lf I\n", cabs(creal(amplitude)), cimag(amplitude+0.00000001)>0?'+':'-' , cabs(cimag(amplitude)));
+  else
+    printf("%.10lf %c %.10lf I\n", creal(amplitude), cimag(amplitude+0.00000001)>0?'+':'-' , cabs(cimag(amplitude)));
+
+  return 0;
+
+}
+
+
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits)
+{
+    
+  int newomega, newalpha, newbeta, newgamma, newdelta;
+  int i;
+
+  if(scanf("%d", &newomega) != EOF) {
+    *omega = newomega;
+    for(i=0; i<numqubits; i++) {
+      if(scanf("%d %d %d %d", &newalpha, &newbeta, &newgamma, &newdelta) == EOF) {
+       printf("Error: Too few input coeffs!\n");
+       exit(0);
+      }
+      if(newalpha+newbeta+newgamma+newdelta > 1) {
+       printf("Error: Too many coefficients are non-zero at Pauli %d!\n", i);
+       exit(0);
+      }
+      alpha[i] = newalpha; beta[i] = newbeta; gamma[i] = newgamma; delta[i] = newdelta;
+    }
+    return 1;
+  } else
+    return 0;
+    
+}
diff --git a/strongsim6_relerr.c b/strongsim6_relerr.c
new file mode 100644 (file)
index 0000000..31bfb1c
--- /dev/null
@@ -0,0 +1,432 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <complex.h>
+#include <time.h>
+#include "matrix.h"
+#include "exponentialsum.h"
+#include "shrinkstar.h"
+#include "extend.h"
+#include "measurepauli.h"
+#include "innerproduct.h"
+#include "randomstabilizerstate.h"
+
+#define ZEROTHRESHOLD (0.00000001)
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits);
+
+// order of matrix elements is [row][column]!!!
+
+int main(int argc, char *argv[])
+{
+
+  if(argc != 2) {
+    printf("strongsim6_rellerr argument: \"number of stabilizer state samples\"\n");
+    exit(0);
+  }
+
+  int NUMSTABSTATESAMPLES = atoi(argv[1]);        // number of stabilizer state samples
+
+  int N;                  // number of qubits
+  scanf("%d", &N);
+
+  if(N%6 != 0) {
+    printf("'N' needs to be a multiple of 6 for a k=6 tensor factor decomposition!\n");
+    return 1;
+  }
+
+  int T;              // number of T gate magic states (set to the first 'K' of the 'N' qubits -- the rest are set to the '0' computational basis state)
+  scanf("%d", &T);
+
+  int omega[N]; // max of N measurements
+  int alpha[N][N], beta[N][N], gamma[N][N], delta[N][N]; // max of N measurements of N Paulis
+  int Paulicounter = 0;
+
+  int i, j, k, l, m;
+
+  FILE *fp;
+  char buff[255];
+
+  srand((unsigned)time(NULL)); // seeding the random number generator for randomstabilizerstate()
+  
+  fp = fopen("Pd.txt", "r");
+
+  if(fscanf(fp, "%s", buff) == EOF) {
+    printf("Error: Pd.txt should start with the number N of P(d) of values tabulated.");
+    return 1;
+  }
+  
+  double** Pd;
+
+  int PdN = atoi(buff);
+
+  Pd = calloc(PdN, sizeof(double*));
+  for(i=0; i<PdN; i++) 
+    Pd[i] = calloc(PdN+1, sizeof(double));
+
+  double tmp;
+  
+  for(i=1; i<PdN; i++) {
+    tmp = 0.0;
+    for(j=0; j<=i; j++) {
+      if(fscanf(fp, "%s", buff) == EOF) {
+       printf("Error: expected more values tabulated for P(d) for N=%d", PdN);
+       return 1;
+      }
+      Pd[i][j] = atof(buff);
+      //printf("%e ", Pd[i][j]);
+      tmp += Pd[i][j];
+    }
+    //printf("\n");
+    //printf("total=%f\n", tmp);
+  }
+
+
+  double complex coeffb60 = (-16.0+12.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(6.0*PI*I/8.0)/8.0*cpow(2.0,3.0);
+  double complex coeffb66 = (96.0-68.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(6.0*PI*I/8.0)/8.0*cpow(2.0,3.0);
+  double complex coeffe6 = (10.0-7.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(6.0*PI*I/8.0)*cpow(2.0,2.5);
+  double complex coeffo6 = (-14.0+10.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(-14.0*PI*I/8.0)*cpow(2.0,2.5);
+  double complex coeffk6 = (7.0-5.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(-8.0*PI*I/8.0)*4.0*csqrt(2.0)*cpow(2.0,0.5);
+  double complex coeffphiprime = (10.0-7.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(2.0*PI*I/8.0)*cpow(2.0,2.5);
+  double complex coeffphidprime = (10.0-7.0*sqrt(2.0)+0.0*I)*pow(cos(PI/8.0),6)*cexp(2.0*PI*I/8.0)*cpow(2.0,2.5);
+
+  // b60
+  int n1 = 6; int k1 = 6; int (*(G1[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}}; int (*(GBar1[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}}; int h1[] = {0, 0, 0, 0, 0, 0}; int Q1 = 0; int D1[] = {0, 0, 0, 0, 0, 0}; int (*(J1[])) = { (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0} };
+  // b66
+  int n2 = 6; int k2 = 6; int (*(G2[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}}; int (*(GBar2[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}}; int h2[] = {0, 0, 0, 0, 0, 0}; int Q2 = 4; int D2[] = {4, 4, 4, 4, 4, 4}; int (*(J2[])) = { (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0}, (int[]) {0, 0, 0, 0, 0, 0} };
+  // e6
+  int n3 = 6; int k3 = 5; int (*(G3[])) = { (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0} }; int (*(GBar3[])) = { (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1} }; int h3[] = {1, 0, 0, 0, 0, 0}; int Q3 = 4; int D3[] = {0, 0, 0, 0, 0}; int (*(J3[])) = { (int[]) {0, 4, 4, 4, 4}, (int[]) {4, 0, 4, 4, 4}, (int[]) {4, 4, 0, 4, 4}, (int[]) {4, 4, 4, 0, 4}, (int[]) {4, 4, 4, 4, 0}  };
+  // o6
+  int n4 = 6; int k4 = 5; int (*(G4[])) = { (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0} }; int (*(GBar4[])) = { (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1} }; int h4[] = {0, 0, 0, 0, 0, 0}; int Q4 = 4; int D4[] = {4, 4, 4, 4, 4}; int (*(J4[])) = { (int[]) {0, 4, 4, 4, 4}, (int[]) {4, 0, 4, 4, 4}, (int[]) {4, 4, 0, 4, 4}, (int[]) {4, 4, 4, 0, 4}, (int[]) {4, 4, 4, 4, 0}  };
+  // k6
+  int n5 = 6; int k5 = 1; int (*(G5[])) = { (int[]) {1, 1, 1, 1, 1, 1}, (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1} }; int (*(GBar5[])) = { (int[]) {1, 0, 0, 0, 0, 0}, (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1} }; int h5[] = {1, 1, 1, 1, 1, 1}; int Q5 = 6; int D5[] = {2}; int (*(J5[])) = { (int[]) {4} };
+  // phiprime
+  int n6 = 6; int k6 = 5; int (*(G6[])) = { (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0} }; int (*(GBar6[])) = { (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1} }; int h6[] = {1, 0, 0, 0, 0, 0}; int Q6 = 0; int D6[] = {0, 0, 0, 0, 0}; int (*(J6[])) = { (int[]) {0, 4, 0, 0, 4}, (int[]) {4, 0, 4, 0, 0}, (int[]) {0, 4, 0, 4, 0}, (int[]) {0, 0, 4, 0, 4}, (int[]) {4, 0, 0, 4, 0}  };
+  // phidoubleprime
+  int n7 = 6; int k7 = 5; int (*(G7[])) = { (int[]) {1, 1, 0, 0, 0, 0}, (int[]) {1, 0, 1, 0, 0, 0}, (int[]) {1, 0, 0, 1, 0, 0}, (int[]) {1, 0, 0, 0, 1, 0}, (int[]) {1, 0, 0, 0, 0, 1}, (int[]) {1, 0, 0, 0, 0, 0} }; int (*(GBar7[])) = { (int[]) {0, 1, 0, 0, 0, 0}, (int[]) {0, 0, 1, 0, 0, 0}, (int[]) {0, 0, 0, 1, 0, 0}, (int[]) {0, 0, 0, 0, 1, 0}, (int[]) {0, 0, 0, 0, 0, 1}, (int[]) {1, 1, 1, 1, 1, 1} }; int h7[] = {1, 0, 0, 0, 0, 0}; int Q7 = 0; int D7[] = {0, 0, 0, 0, 0}; int (*(J7[])) = { (int[]) {0, 0, 4, 4, 0}, (int[]) {0, 0, 0, 4, 4}, (int[]) {4, 0, 0, 0, 4}, (int[]) {4, 4, 0, 0, 0}, (int[]) {0, 4, 4, 0, 0}  };
+
+
+  int *K; int ***G; int ***GBar; int **h; int *Q; int **D; int ***J;
+  double complex Gamma[(int)pow(7,N/6)]; // prefactor in front of resultant state
+  G = calloc(pow(7,N/6),sizeof(int*)); GBar = calloc(pow(7,N/6),sizeof(int*));
+  h = calloc(pow(7,N/6),sizeof(int*));
+  
+  J = calloc(pow(7,N/6),sizeof(int*)); D = calloc(pow(7,N/6),sizeof(int*)); Q = calloc(pow(7,N/6),sizeof(int));
+
+  K = calloc(pow(7,N/6), sizeof(int));
+
+  int origK, origQ, *origD;
+  int **origJ;
+  int **origG, **origGBar;
+  int *origh;
+  double complex origGamma;
+
+  int combination; // a particular combination from the linear combo of stabilizer states making up the tensor factors multiplied together
+  
+
+  for(j=0; j<pow(7,N/6); j++) { // there will be 7^(N/6) combinations when using k=12 tensor factors
+
+    combination = j;
+
+    K[j] = 0.0;
+    
+    for(k=0; k<N/6; k++) {
+      K[j] += (((combination%7)==6)*k7 + ((combination%7)==5)*k6 + ((combination%7)==4)*k5 + ((combination%7)==3)*k4 + ((combination%7)==2)*k3 + ((combination%7)==1)*k2 + ((combination%7)==0)*k1);
+      combination /= 7;
+    }
+    combination = j;
+
+    Gamma[j] = 1.0;
+
+    G[j] = calloc(N, sizeof(int*)); GBar[j] = calloc(N, sizeof(int*));
+    h[j] = calloc(N, sizeof(int));
+
+    if(K[j] > 0) {
+      J[j] = calloc(K[j], sizeof(int*)); D[j] = calloc(K[j], sizeof(int));
+      for(k=0; k<K[j]; k++)
+       J[j][k] = calloc(K[j], sizeof(int));
+    }
+
+    for(k=0; k<N; k++) {
+      G[j][k] = calloc(N, sizeof(int)); GBar[j][k] = calloc(N, sizeof(int));
+    }
+
+    int Kcounter = 0; // Kcounter keeps track of the K<=N that we have added already to the G rows etc. for each combination that is indexed by the digits (base 3) of 'j' in that we go through with 'k'
+    int Kcombo; // Kcombo stores the k<(n1=n2=n3) dimension of the member of the combination that we are currently adding
+    for(k=0; k<N/6; k++) {
+
+      Q[j] += (((combination%7)==6)*Q7 + ((combination%7)==5)*Q6 + ((combination%7)==4)*Q5 + ((combination%7)==3)*Q4 + ((combination%7)==2)*Q3 + ((combination%7)==1)*Q2 + ((combination%7)==0)*Q1);
+      
+
+      Gamma[j] *= (((combination%7)==6)*coeffphidprime + ((combination%7)==5)*coeffphiprime + ((combination%7)==4)*coeffk6 + ((combination%7)==3)*coeffo6 + ((combination%7)==2)*coeffe6 + ((combination%7)==1)*coeffb66 + ((combination%7)==0)*coeffb60);
+
+      Kcombo = (((combination%7)==6)*k7 + ((combination%7)==5)*k6 + ((combination%7)==4)*k5 + ((combination%7)==3)*k4 + ((combination%7)==2)*k3 + ((combination%7)==1)*k2 + ((combination%7)==0)*k1);
+      for(l=0; l<Kcombo; l++) {
+       // D1 has a different number of rows 'l' than D2 and D3 so you need to use something like 'switch' to check combination%3 without going out of bound of J1
+       switch(combination%7) {
+       case 0:
+         D[j][Kcounter+l] = D1[l];
+         break;
+       case 1:
+         D[j][Kcounter+l] = D2[l];
+         break;
+       case 2:
+         D[j][Kcounter+l] = D3[l];
+         break;
+       case 3:
+         D[j][Kcounter+l] = D4[l];
+           break;
+       case 4:
+         D[j][Kcounter+l] = D5[l];
+         break;
+       case 5:
+         D[j][Kcounter+l] = D6[l];
+         break;
+       case 6:
+         D[j][Kcounter+l] = D7[l];
+         break;
+       default:
+         printf("error");
+         return 1;
+         }
+       for(m=0; m<Kcombo; m++) {
+         // J1 has a different number of rows 'l' than J2 and J3 so you need to use something like 'switch' to check combination%3 without going out of bound of J1
+         switch(combination%7) {
+         case 0:
+           J[j][Kcounter+l][Kcounter+m] = J1[l][m];
+           break;
+         case 1:
+           J[j][Kcounter+l][Kcounter+m] = J2[l][m];
+           break;
+         case 2:
+           J[j][Kcounter+l][Kcounter+m] = J3[l][m];
+           break;
+         case 3:
+           J[j][Kcounter+l][Kcounter+m] = J4[l][m];
+           break;
+         case 4:
+           J[j][Kcounter+l][Kcounter+m] = J5[l][m];
+           break;
+         case 5:
+           J[j][Kcounter+l][Kcounter+m] = J6[l][m];
+           break;
+         case 6:
+           J[j][Kcounter+l][Kcounter+m] = J7[l][m];
+           break;
+         default:
+           printf("error");
+           return 1;
+         }
+       }
+      }
+
+      for(l=0; l<n1; l++) { // assuming n1=n2=n3
+       h[j][k*n1+l] = (((combination%7)==6)*h7[l] + ((combination%7)==5)*h6[l] + ((combination%7)==4)*h5[l] + ((combination%7)==3)*h4[l] + ((combination%7)==2)*h3[l] + ((combination%7)==1)*h2[l] + ((combination%7)==0)*h1[l]);
+      }
+      // only filling the K[j] first rows of G and GBar here corresponding to the basis for D and J
+      for(l=0; l<Kcombo; l++) {
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         G[j][Kcounter+l][k*n1+m] = (((combination%7)==6)*G7[l][m] + ((combination%7)==5)*G6[l][m] + ((combination%7)==4)*G5[l][m] + ((combination%7)==3)*G4[l][m] + ((combination%7)==2)*G3[l][m] + ((combination%7)==1)*G2[l][m] + ((combination%7)==0)*G1[l][m]);
+         GBar[j][Kcounter+l][k*n1+m] = (((combination%7)==6)*GBar7[l][m] + ((combination%7)==5)*GBar6[l][m] + ((combination%7)==4)*GBar5[l][m] + ((combination%7)==3)*GBar4[l][m] + ((combination%7)==2)*GBar3[l][m] + ((combination%7)==1)*GBar2[l][m] + ((combination%7)==0)*GBar1[l][m]);
+       }
+      }
+      Kcounter = Kcounter + Kcombo;
+      
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      //memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
+
+      //memcpy(origJ[j][k], J[j][k], K[j]*sizeof(int));
+      
+      combination /= 7; // shift to the right by one (in base-7 arithmetic)
+    }
+    //printf("!\n");
+
+    // now need to fill the N-Kcounter remaining rows of G and GBar that are outside the spanning basis states of D and J
+    combination = j;
+    for(k=0; k<(N/6); k++) {
+      Kcombo = (((combination%7)==6)*k7 + ((combination%7)==5)*k6 + ((combination%7)==4)*k5 + ((combination%7)==3)*k4 + ((combination%7)==2)*k3 + ((combination%7)==1)*k2 + ((combination%7)==0)*k1);
+      //printf("Kcounter=%d\n", Kcounter);
+      // G and GBar rows that are outside the first 'k' spanning basis states
+      for(l=Kcombo; l<n1; l++) { // assuming n1=n2=n3
+       //printf("l=%d\n", l);
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         /* printf("m=%d\n", m); */
+         /* printf("Kcounter+l=%d\n", Kcounter+l); */
+         /* printf("k*n1+m=%d\n", k*n1+m); */
+         G[j][Kcounter+l-Kcombo][k*n1+m] = (((combination%7)==6)*G7[l][m] + ((combination%7)==5)*G6[l][m] + ((combination%7)==4)*G5[l][m] + ((combination%7)==3)*G4[l][m] + ((combination%7)==2)*G3[l][m] + ((combination%7)==1)*G2[l][m] + ((combination%7)==0)*G1[l][m]);
+         GBar[j][Kcounter+l-Kcombo][k*n1+m] = (((combination%7)==6)*GBar7[l][m] + ((combination%7)==5)*GBar6[l][m] + ((combination%7)==4)*GBar5[l][m] + ((combination%7)==3)*GBar4[l][m] + ((combination%7)==2)*GBar3[l][m] + ((combination%7)==1)*GBar2[l][m] + ((combination%7)==0)*GBar1[l][m]);
+       }
+      }
+      Kcounter = Kcounter + (n1-Kcombo);
+
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      
+      combination /= 7;
+    }
+
+    /*printf("G[%d]:\n", j);
+    printMatrix(G[j], N, N);
+    printf("GBar[%d]:\n", j);
+    printMatrix(GBar[j], N, N);
+
+    printf("h[%d]:\n", j);
+    printVector(h[j], N);
+
+    printf("J[%d]:\n", j);
+    printMatrix(J[j], K[j], K[j]);
+    
+    printf("D[%d]:\n", j);
+    printVector(D[j], K[j]);
+
+    printf("Q[%d]=%d\n", j, Q[j]);*/
+
+  }
+  //exit(0);
+
+  while(readPaulicoeffs(&omega[Paulicounter], alpha[Paulicounter], beta[Paulicounter], gamma[Paulicounter], delta[Paulicounter], N)) {
+
+    if((Paulicounter+1) > N) {
+      printf("Error: Number of Paulis is greater than N!\n");
+      return 1;
+    }
+    
+    // Let's break up the Ys into Xs and Zs in the order Z X, as required to pass to measurepauli()
+    // Y_i = -I*Z*X
+    for(i=0; i<N; i++) {
+      if(delta[Paulicounter][i]){
+       omega[Paulicounter] += 3; // -I = I^3
+       beta[Paulicounter][i] = delta[Paulicounter][i];
+       gamma[Paulicounter][i] = delta[Paulicounter][i];
+      }
+    }
+
+    /*printf("*******\n");
+    printf("*******\n");
+    printf("omega=%d\n", omega);
+    printf("X:\n");
+    printVector(gamma, N);
+    printf("Z:\n");
+    printVector(beta, N);
+    printf("*******\n");
+    printf("*******\n");*/
+
+    //for(j=0; j<pow(7,N/6); j++) { // the kets
+
+      /*printf("========\n");
+      printf("before:\n");
+      printf("K=%d\n", K[j]);
+      printf("h:\n");
+      printVector(h[j], N);
+      printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
+      printf("G:\n");
+      printMatrix(G[j], N, N);
+      printf("GBar:\n");
+      printMatrix(GBar[j], N, N);
+      printf("Q=%d\n", Q[j]);
+      printf("D:\n");
+      printVector(D[j], K[j]);
+      printf("J:\n");
+      printMatrix(J[j], K[j], K[j]);*/
+      //Gamma[j] *= measurepauli(N, &K[j], h[j], G[j], GBar[j], &Q[j], &D[j], &J[j], omega, gamma, beta);
+      /*printf("\nafter:\n");
+      printf("K=%d\n", K[j]);
+      printf("h:\n");
+      printVector(h[j], N);
+      printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
+      printf("G:\n");
+      printMatrix(G[j], N, N);
+      printf("GBar:\n");
+      printMatrix(GBar[j], N, N);
+      printf("Q=%d\n", Q[j]);
+      printf("D:\n");
+      printVector(D[j], K[j]);
+      printf("J:\n");
+      printMatrix(J[j], K[j], K[j]);*/
+
+    //}
+
+    Paulicounter++;
+  }
+
+  double complex amplitude = 0.0 + 0.0*I;
+  for(i=0; i<NUMSTABSTATESAMPLES; i++) { // the bras
+    //printf("i=%d\n", i);
+
+    randomstabilizerstate(N, &origK, &origh, &origG, &origGBar, &origQ, &origD, &origJ, Pd);
+
+    origGamma = 1.0 + 0.0*I;
+    
+    for(k=0; k<Paulicounter; k++) {
+      origGamma *= measurepauli(N, &origK, origh, origG, origGBar, &origQ, &origD, &origJ, omega[k], gamma[k], beta[k]);
+      //printf("k=%d\n", k);
+  }
+    /*printf("origK=%d\n", origK);
+    printf("origG:\n");
+    printMatrix(origG, N, N);
+    printf("origGBar:\n");
+    printMatrix(origGBar, N, N);
+    printf("origh:\n");
+    printVector(origh, N);*/
+
+    double complex stabstateaverage = 0.0 + 0.0*I;
+    
+    for(j=0; j<pow(7,N/6); j++) {
+      //printf("j=%d\n", j);
+      double complex newamplitude = innerproduct(N, K[j], h[j], G[j], GBar[j], Q[j], D[j], J[j], N, origK, origh, origG, origGBar, origQ, origD, origJ);
+      stabstateaverage = stabstateaverage + origGamma*Gamma[j]*newamplitude;
+    }
+    amplitude = amplitude + conj(stabstateaverage)*stabstateaverage/((double)(NUMSTABSTATESAMPLES))*pow(2.0,T);
+
+    deallocate_mem(&origG, N);
+    deallocate_mem(&origGBar, N);
+    free(origh);
+    deallocate_mem(&origJ, origK);
+    free(origD);
+  }
+
+  printf("amplitude:\n");
+  if(creal(amplitude+ZEROTHRESHOLD)>0)
+    printf("%.10lf %c %.10lf I\n", cabs(creal(amplitude)), cimag(amplitude+ZEROTHRESHOLD)>0?'+':'-' , cabs(cimag(amplitude)));
+  else
+    printf("%.10lf %c %.10lf I\n", creal(amplitude), cimag(amplitude+ZEROTHRESHOLD)>0?'+':'-' , cabs(cimag(amplitude)));
+  
+  
+
+  for(i=0; i<PdN; i++) 
+    free(Pd[i]);
+  free(Pd);
+
+  return 0;
+}
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits)
+{
+    
+  int newomega, newalpha, newbeta, newgamma, newdelta;
+  int i;
+
+  if(scanf("%d", &newomega) != EOF) {
+    *omega = newomega;
+    for(i=0; i<numqubits; i++) {
+      if(scanf("%d %d %d %d", &newalpha, &newbeta, &newgamma, &newdelta) == EOF) {
+       printf("Error: Too few input coeffs!\n");
+       exit(0);
+      }
+      if(newalpha+newbeta+newgamma+newdelta > 1) {
+       printf("Error: Too many coefficients are non-zero at Pauli %d!\n", i);
+       exit(0);
+      }
+      alpha[i] = newalpha; beta[i] = newbeta; gamma[i] = newgamma; delta[i] = newdelta;
+    }
+    return 1;
+  } else
+    return 0;
+    
+}
diff --git a/strongsim_relerr.c b/strongsim_relerr.c
new file mode 100644 (file)
index 0000000..24ec5b3
--- /dev/null
@@ -0,0 +1,393 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <complex.h>
+#include <time.h>
+#include "matrix.h"
+#include "exponentialsum.h"
+#include "shrinkstar.h"
+#include "extend.h"
+#include "measurepauli.h"
+#include "innerproduct.h"
+#include "randomstabilizerstate.h"
+
+#define ZEROTHRESHOLD (0.00000001)
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits);
+
+// order of matrix elements is [row][column]!!!
+
+int main(int argc, char *argv[])
+{
+
+  if(argc != 2) {
+    printf("strongsim3_rellerr argument: \"number of stabilizer state samples\"\n");
+    exit(0);
+  }
+
+  int NUMSTABSTATESAMPLES = atoi(argv[1]);        // number of stabilizer state samples
+
+  int N;                  // number of qubits
+  scanf("%d", &N);
+
+  if(N%3 != 0) {
+    printf("'N' needs to be a multiple of 3 for a k=3 tensor factor decomposition!\n");
+    return 1;
+  }
+
+  int T;              // number of T gate magic states (set to the first 'K' of the 'N' qubits -- the rest are set to the '0' computational basis state)
+  scanf("%d", &T);
+
+  int omega[N]; // max of N measurements
+  int alpha[N][N], beta[N][N], gamma[N][N], delta[N][N]; // max of N measurements of N Paulis
+  int Paulicounter = 0;
+
+  int i, j, k, l, m;
+
+  FILE *fp;
+  char buff[255];
+
+  srand((unsigned)time(NULL)); // seeding the random number generator for randomstabilizerstate()
+  
+  fp = fopen("Pd.txt", "r");
+
+  if(fscanf(fp, "%s", buff) == EOF) {
+    printf("Error: Pd.txt should start with the number N of P(d) of values tabulated.");
+    return 1;
+  }
+  
+  double** Pd;
+
+  int PdN = atoi(buff);
+
+  Pd = calloc(PdN, sizeof(double*));
+  for(i=0; i<PdN; i++) 
+    Pd[i] = calloc(PdN+1, sizeof(double));
+
+  double tmp;
+  
+  for(i=1; i<PdN; i++) {
+    tmp = 0.0;
+    for(j=0; j<=i; j++) {
+      if(fscanf(fp, "%s", buff) == EOF) {
+       printf("Error: expected more values tabulated for P(d) for N=%d", PdN);
+       return 1;
+      }
+      Pd[i][j] = atof(buff);
+      //printf("%e ", Pd[i][j]);
+      tmp += Pd[i][j];
+    }
+    //printf("\n");
+    //printf("total=%f\n", tmp);
+  }
+
+
+  double complex coeffa = -0.25*(1.0-I)*(-1.0-I+sqrt(2.0))*csqrt(-I);
+  double complex coeffb = 0.25*(-1.0-I)*(1.0-I+sqrt(2.0))*csqrt(I);
+  double complex coeffc = 0.25*(-1.0-I)*(-1.0+I+sqrt(2.0))*csqrt(I);
+
+  int n1 = 3; int k1 = 1; int (*(G1[])) = { (int[]) {1, 1, 1}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1}}; int (*(GBar1[])) = { (int[]) {1, 0, 0}, (int[]) {1, 1, 0}, (int[]) {1, 0, 1}}; int h1[] = {1, 1, 0}; int Q1 = 0; int D1[] = {2}; int (*(J1[])) = { (int[]) {4} };
+  int n2 = 3; int k2 = 3; int (*(G2[])) = { (int[]) {1, 0, 0}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1} }; int (*(GBar2[])) = { (int[]) {1, 0, 0}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1} }; int h2[] = {0, 0, 0}; int Q2 = 2; int D2[] = {2, 2, 0}; int (*(J2[])) = { (int[]) {4, 0, 0}, (int[]) {0, 4, 0}, (int[]) {0, 0, 0} };
+  int n3 = 3; int k3 = 3; int (*(G3[])) = { (int[]) {1, 0, 0}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1} }; int (*(GBar3[])) = { (int[]) {1, 0, 0}, (int[]) {0, 1, 0}, (int[]) {0, 0, 1} }; int h3[] = {0, 0, 0}; int Q3 = 2; int D3[] = {6, 6, 0}; int (*(J3[])) = { (int[]) {4, 4, 4}, (int[]) {4, 4, 4}, (int[]) {4, 4, 0} };
+
+
+  int *K; int ***G; int ***GBar; int **h; int *Q; int **D; int ***J;
+  double complex Gamma[(int)pow(3,N/3)]; // prefactor in front of resultant state
+  G = calloc(pow(3,N/3),sizeof(int*)); GBar = calloc(pow(3,N/3),sizeof(int*));
+  h = calloc(pow(3,N/3),sizeof(int*));
+  
+  J = calloc(pow(3,N/3),sizeof(int*)); D = calloc(pow(3,N/3),sizeof(int*)); Q = calloc(pow(3,N/3),sizeof(int));
+
+  K = calloc(pow(3,N/3), sizeof(int));
+
+  int origK, origQ, *origD;
+  int **origJ;
+  int **origG, **origGBar;
+  int *origh;
+  double complex origGamma;
+
+  int combination; // a particular combination from the linear combo of stabilizer states making up the tensor factors multiplied together
+  
+
+  for(j=0; j<pow(3,N/3); j++) { // there will be 3^(N/3) combinations when using k=12 tensor factors
+
+    combination = j;
+
+    K[j] = 0.0;
+    
+    for(k=0; k<N/3; k++) {
+      K[j] += (((combination%3)==2)*k3 + ((combination%3)==1)*k2 + ((combination%3)==0)*k1);
+      combination /= 3;
+    }
+    combination = j;
+
+    Gamma[j] = 1.0;
+
+    G[j] = calloc(N, sizeof(int*)); GBar[j] = calloc(N, sizeof(int*));
+    h[j] = calloc(N, sizeof(int));
+
+    if(K[j] > 0) {
+      J[j] = calloc(K[j], sizeof(int*)); D[j] = calloc(K[j], sizeof(int));
+      for(k=0; k<K[j]; k++)
+       J[j][k] = calloc(K[j], sizeof(int));
+    }
+
+    for(k=0; k<N; k++) {
+      G[j][k] = calloc(N, sizeof(int)); GBar[j][k] = calloc(N, sizeof(int));
+    }
+
+    int Kcounter = 0; // Kcounter keeps track of the K<=N that we have added already to the G rows etc. for each combination that is indexed by the digits (base 3) of 'j' in that we go through with 'k'
+    int Kcombo; // Kcombo stores the k<(n1=n2=n3) dimension of the member of the combination that we are currently adding
+    for(k=0; k<N/3; k++) {
+
+      Q[j] += (((combination%3)==2)*Q3 + ((combination%3)==1)*Q2 + ((combination%3)==0)*Q1);
+      
+
+      Gamma[j] *= (((combination%3)==2)*coeffc + ((combination%3)==1)*coeffb + ((combination%3)==0)*coeffa);
+
+      Kcombo = (((combination%3)==2)*k3 + ((combination%3)==1)*k2 + ((combination%3)==0)*k1);
+      for(l=0; l<Kcombo; l++) {
+       // D1 has a different number of rows 'l' than D2 and D3 so you need to use something like 'switch' to check combination%3 without going out of bound of J1
+       switch(combination%3) {
+       case 0:
+         D[j][Kcounter+l] = D1[l];
+         break;
+       case 1:
+         D[j][Kcounter+l] = D2[l];
+         break;
+       case 2:
+         D[j][Kcounter+l] = D3[l];
+         break;
+       default:
+         printf("error");
+         return 1;
+         }
+       for(m=0; m<Kcombo; m++) {
+         // J1 has a different number of rows 'l' than J2 and J3 so you need to use something like 'switch' to check combination%3 without going out of bound of J1
+         switch(combination%3) {
+         case 0:
+           J[j][Kcounter+l][Kcounter+m] = J1[l][m];
+           break;
+         case 1:
+           J[j][Kcounter+l][Kcounter+m] = J2[l][m];
+           break;
+         case 2:
+           J[j][Kcounter+l][Kcounter+m] = J3[l][m];
+           break;
+         default:
+           printf("error");
+           return 1;
+         }
+       }
+      }
+
+      for(l=0; l<n1; l++) { // assuming n1=n2=n3
+       h[j][k*n1+l] = (((combination%3)==2)*h3[l] + ((combination%3)==1)*h2[l] + ((combination%3)==0)*h1[l]);
+      }
+      // only filling the K[j] first rows of G and GBar here corresponding to the basis for D and J
+      for(l=0; l<Kcombo; l++) {
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         G[j][Kcounter+l][k*n1+m] = (((combination%3)==2)*G3[l][m] + ((combination%3)==1)*G2[l][m] + ((combination%3)==0)*G1[l][m]);
+         GBar[j][Kcounter+l][k*n1+m] = (((combination%3)==2)*GBar3[l][m] + ((combination%3)==1)*GBar2[l][m] + ((combination%3)==0)*GBar1[l][m]);
+       }
+      }
+      Kcounter = Kcounter + Kcombo;
+      
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      //memcpy(origG[j][k], G[j][k], N*sizeof(int)); memcpy(origGBar[j][k], GBar[j][k], N*sizeof(int));
+
+      //memcpy(origJ[j][k], J[j][k], K[j]*sizeof(int));
+      
+      combination /= 3; // shift to the right by one (in base-7 arithmetic)
+    }
+    //printf("!\n");
+
+    // now need to fill the N-Kcounter remaining rows of G and GBar that are outside the spanning basis states of D and J
+    combination = j;
+    for(k=0; k<(N/3); k++) {
+      Kcombo = (((combination%3)==2)*k3 + ((combination%3)==1)*k2 + ((combination%3)==0)*k1);
+      //printf("Kcounter=%d\n", Kcounter);
+      // G and GBar rows that are outside the first 'k' spanning basis states
+      for(l=Kcombo; l<n1; l++) { // assuming n1=n2=n3
+       //printf("l=%d\n", l);
+       for(m=0; m<n1; m++) { // assuming n1=n2=n3
+         /* printf("m=%d\n", m); */
+         /* printf("Kcounter+l=%d\n", Kcounter+l); */
+         /* printf("k*n1+m=%d\n", k*n1+m); */
+         G[j][Kcounter+l-Kcombo][k*n1+m] = (((combination%3)==2)*G3[l][m] + ((combination%3)==1)*G2[l][m] + ((combination%3)==0)*G1[l][m]);
+         GBar[j][Kcounter+l-Kcombo][k*n1+m] = (((combination%3)==2)*GBar3[l][m] + ((combination%3)==1)*GBar2[l][m] + ((combination%3)==0)*GBar1[l][m]);
+       }
+      }
+      Kcounter = Kcounter + (n1-Kcombo);
+
+      /* printf("intermediate G[%d]:\n", j); */
+      /* printMatrix(G[j], N, N); */
+      /* printf("intermediate GBar[%d]:\n", j); */
+      /* printMatrix(GBar[j], N, N); */
+      
+      combination /= 3;
+    }
+
+    /*printf("G[%d]:\n", j);
+    printMatrix(G[j], N, N);
+    printf("GBar[%d]:\n", j);
+    printMatrix(GBar[j], N, N);
+
+    printf("h[%d]:\n", j);
+    printVector(h[j], N);
+
+    printf("J[%d]:\n", j);
+    printMatrix(J[j], K[j], K[j]);
+    
+    printf("D[%d]:\n", j);
+    printVector(D[j], K[j]);
+
+    printf("Q[%d]=%d\n", j, Q[j]);*/
+
+  }
+  //exit(0);
+
+  while(readPaulicoeffs(&omega[Paulicounter], alpha[Paulicounter], beta[Paulicounter], gamma[Paulicounter], delta[Paulicounter], N)) {
+
+    if((Paulicounter+1) > N) {
+      printf("Error: Number of Paulis is greater than N!\n");
+      return 1;
+    }
+    
+    // Let's break up the Ys into Xs and Zs in the order Z X, as required to pass to measurepauli()
+    // Y_i = -I*Z*X
+    for(i=0; i<N; i++) {
+      if(delta[Paulicounter][i]){
+       omega[Paulicounter] += 3; // -I = I^3
+       beta[Paulicounter][i] = delta[Paulicounter][i];
+       gamma[Paulicounter][i] = delta[Paulicounter][i];
+      }
+    }
+
+    /*printf("*******\n");
+    printf("*******\n");
+    printf("omega=%d\n", omega);
+    printf("X:\n");
+    printVector(gamma, N);
+    printf("Z:\n");
+    printVector(beta, N);
+    printf("*******\n");
+    printf("*******\n");*/
+
+    //for(j=0; j<pow(3,N/3); j++) { // the kets
+
+      /*printf("========\n");
+      printf("before:\n");
+      printf("K=%d\n", K[j]);
+      printf("h:\n");
+      printVector(h[j], N);
+      printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
+      printf("G:\n");
+      printMatrix(G[j], N, N);
+      printf("GBar:\n");
+      printMatrix(GBar[j], N, N);
+      printf("Q=%d\n", Q[j]);
+      printf("D:\n");
+      printVector(D[j], K[j]);
+      printf("J:\n");
+      printMatrix(J[j], K[j], K[j]);*/
+      //Gamma[j] *= measurepauli(N, &K[j], h[j], G[j], GBar[j], &Q[j], &D[j], &J[j], omega, gamma, beta);
+      /*printf("\nafter:\n");
+      printf("K=%d\n", K[j]);
+      printf("h:\n");
+      printVector(h[j], N);
+      printf("Gamma[%d]=%lf+%lf\n", j, creal(Gamma[j]), cimag(Gamma[j]));
+      printf("G:\n");
+      printMatrix(G[j], N, N);
+      printf("GBar:\n");
+      printMatrix(GBar[j], N, N);
+      printf("Q=%d\n", Q[j]);
+      printf("D:\n");
+      printVector(D[j], K[j]);
+      printf("J:\n");
+      printMatrix(J[j], K[j], K[j]);*/
+
+    //}
+
+    Paulicounter++;
+  }
+
+  double complex amplitude = 0.0 + 0.0*I;
+  for(i=0; i<NUMSTABSTATESAMPLES; i++) { // the bras
+    //printf("i=%d\n", i);
+
+    randomstabilizerstate(N, &origK, &origh, &origG, &origGBar, &origQ, &origD, &origJ, Pd);
+
+    origGamma = 1.0 + 0.0*I;
+    
+    for(k=0; k<Paulicounter; k++) {
+      origGamma *= measurepauli(N, &origK, origh, origG, origGBar, &origQ, &origD, &origJ, omega[k], gamma[k], beta[k]);
+      //printf("k=%d\n", k);
+  }
+    /*printf("origK=%d\n", origK);
+    printf("origG:\n");
+    printMatrix(origG, N, N);
+    printf("origGBar:\n");
+    printMatrix(origGBar, N, N);
+    printf("origh:\n");
+    printVector(origh, N);*/
+
+    double complex stabstateaverage = 0.0 + 0.0*I;
+    
+    for(j=0; j<pow(3,N/3); j++) {
+      //printf("j=%d\n", j);
+      double complex newamplitude = innerproduct(N, K[j], h[j], G[j], GBar[j], Q[j], D[j], J[j], N, origK, origh, origG, origGBar, origQ, origD, origJ);
+      stabstateaverage = stabstateaverage + origGamma*Gamma[j]*newamplitude;
+    }
+    amplitude = amplitude + conj(stabstateaverage)*stabstateaverage/((double)(NUMSTABSTATESAMPLES))*pow(2.0,T);
+
+    deallocate_mem(&origG, N);
+    deallocate_mem(&origGBar, N);
+    free(origh);
+    deallocate_mem(&origJ, origK);
+    free(origD);
+  }
+
+  printf("amplitude:\n");
+  if(creal(amplitude+ZEROTHRESHOLD)>0)
+    printf("%.10lf %c %.10lf I\n", cabs(creal(amplitude)), cimag(amplitude+ZEROTHRESHOLD)>0?'+':'-' , cabs(cimag(amplitude)));
+  else
+    printf("%.10lf %c %.10lf I\n", creal(amplitude), cimag(amplitude+ZEROTHRESHOLD)>0?'+':'-' , cabs(cimag(amplitude)));
+  
+  
+
+  for(i=0; i<PdN; i++) 
+    free(Pd[i]);
+  free(Pd);
+
+  return 0;
+}
+
+int readPaulicoeffs(int *omega, int *alpha, int *beta, int *gamma, int *delta, int numqubits)
+{
+    
+  int newomega, newalpha, newbeta, newgamma, newdelta;
+  int i;
+
+  if(scanf("%d", &newomega) != EOF) {
+    *omega = newomega;
+    for(i=0; i<numqubits; i++) {
+      if(scanf("%d %d %d %d", &newalpha, &newbeta, &newgamma, &newdelta) == EOF) {
+       printf("Error: Too few input coeffs!\n");
+       exit(0);
+      }
+      if(newalpha+newbeta+newgamma+newdelta > 1) {
+       printf("Error: Too many coefficients are non-zero at Pauli %d!\n", i);
+       exit(0);
+      }
+      alpha[i] = newalpha; beta[i] = newbeta; gamma[i] = newgamma; delta[i] = newdelta;
+    }
+    return 1;
+  } else
+    return 0;
+    
+}
diff --git a/test.bash b/test.bash
new file mode 100644 (file)
index 0000000..cc380ed
--- /dev/null
+++ b/test.bash
@@ -0,0 +1,30 @@
+#!/bin/bash
+# simple Bash script to check if stabilizer rank code works
+
+# choose the number of qubits and T gates on those qubits
+# NOTE: numqubits must be a multiple of your gauss sum tensor multiple!
+# e.g. if you test gausssums_multipleof6 then numqubits=6*n for some integer n
+numqubits=6
+numTgates=6
+
+numruns=20
+
+echo "Starting test of $numruns random $numqubits-Pauli expectation values..."
+for i in $(seq 1 $numruns)
+do
+# sleep for 1 second for the pseudorandom number generator
+sleep 1;a=$(stdbuf -oL ./randominputPauli $numqubits $numTgates > inputfullPauli.txt && ./strongsim < inputfullPauli.txt | tail -1)
+b=$(stdbuf -oL ./multipauli < inputfullPauli.txt | tail -n1)
+are=$(echo "$a" | cut -f 1 -d " " | cut -c 1-5);
+aim=$(echo "$a" | cut -f 3 -d " " | cut -c 1-5); aimsign=$(echo $a | cut -f 2 -d " "); bimsign=$(echo $a | cut -f 2 -d " ");
+bre=$(echo "$b" | cut -f 1 -d " " | cut -c 1-5);
+bim=$(echo "$b" | cut -f 3 -d " " | cut -c 1-5); echo "$i: $are $aimsign $aim and $bre $bimsign $bim"
+if [ "$are" == "$bre" ] && [ "$aim" == "$bim" ] && [ "$aimsign" == "$bimsign" ]
+then
+continue
+else
+echo "NOT EQUAL!"
+break
+fi
+done
+echo "Test passed!"
diff --git a/test2.bash b/test2.bash
new file mode 100644 (file)
index 0000000..d5ed868
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/bash
+# simple Bash diagnostic script to check if non-zero relative error stabilizer rank code works
+
+# choose the number of qubits and T gates on those qubits
+# NOTE: numqubits must be a multiple of your gauss sum tensor multiple!
+# e.g. if you test gausssums_multipleof6 then numqubits=6*n for some integer n
+numqubits=6
+numTgates=6
+# choose the number of commuting Pauli measurements you want to generate in each run
+# (note: can't be greater than $numqubits)
+numPaulis=6
+
+# number of random stabilizer states to use for stochastic sampling
+numsamples=1000
+
+# since this is a stochastic calculation, we need a threshold to determine when the calculation is withing close enough relative error 
+threshold=0.005 # absolute value threshold difference between computed and exact value
+
+numruns=20
+
+echo "Starting test of $numruns random $numqubits-Pauli expectation values calculated by averaging $numsamples random stabilizer states and comparing to threshold $threshold..."
+
+for i in $(seq 1 $numruns)
+do
+# sleep for 1 second for the pseudorandom number generator
+sleep 1; a=$(stdbuf -oL ./randominputcommutingHermitianPauli2 $numqubits $numTgates $numPaulis > inputPauli.txt && ./strongsim_relerr $numsamples < inputPauli.txt | tail -1)
+b=$(stdbuf -oL ./multipauli < inputPauli.txt | tail -n1)
+are=$(echo "$a" | cut -f 1 -d " " | cut -c 1-5);
+aim=$(echo "$a" | cut -f 3 -d " " | cut -c 1-5); aimsign=$(echo $a | cut -f 2 -d " "); bimsign=$(echo $a | cut -f 2 -d " ");
+bre=$(echo "$b" | cut -f 1 -d " " | cut -c 1-5);
+bim=$(echo "$b" | cut -f 3 -d " " | cut -c 1-5); echo "$i: $are $aimsign $aim and $bre $bimsign $bim"
+rediff=$( printf 'sqrt((%f - %f)^2)\n' "$are" "$bre" | bc -l )
+imdiff=$( printf 'sqrt((%f - %f)^2)\n' "$aim" "$bim" | bc -l )
+if (( $(echo "$rediff < $threshold" |bc -l) )) && (( $(echo "$imdiff < $threshold" |bc -l) )) && [ "$aimsign" == "$bimsign" ]
+then
+    continue
+  else
+    echo "NOT EQUAL!"
+    break
+fi
+done
+echo "Test passed!"
diff --git a/timing.bash b/timing.bash
new file mode 100644 (file)
index 0000000..4ee6c55
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+# Bash script to get some timing analysis:
+for j in 10 12 14 16 18
+do
+for i in {1..1000}
+do
+./randominputcommutingHermitianPauli $j $j > inputfull.txt && /usr/bin/time -o tmp.txt -a --format=%e ./strongsim < inputfull.txt > /dev/null
+sleep 1
+done
+echo "" >> tmp.txt
+done