├── Reciprocal-channel approximation for approximation of Density Evolution Iterative Decoding Threshold ├── LUT.mat ├── RCA_apprx.m ├── RCA_threshold.m └── main.m ├── Covariance-Evolution ├── AWGN-channel Example │ ├── compute_ab.c │ ├── compute_ab.mexw64 │ ├── me_multin.m │ └── me_snr.m ├── LICENSE ├── Main.m ├── Octopus.mat ├── README.md ├── calc.p ├── channel.p └── dec.mexw64 ├── Covariance_Evolution_of_LIST_BP_under_q-ary_channel ├── Covariance_Evolution_of_LIST_BP_under_q-ary_channel.pdf └── lm2nb_threshold.m ├── GA ├── Phi.m ├── decompose.m ├── deopt.m ├── initial.m ├── inv_Phi_2.m ├── ir_GA.m ├── ir_GA2.m ├── left_win.m ├── main.m ├── price_evalution.m ├── price_evalution2.m ├── rate_redress2.m ├── search_index.m ├── var.m └── var_nodes.m ├── GaussianApproximation ├── IrregularLDPC.m ├── RegularLDPC.m ├── derivative_phi.m ├── phi.m └── phi_inverse.m ├── Octopus.png ├── QuantDmc-4 ├── 05eng.png ├── 075eng.png ├── LICENSE ├── README.txt ├── example │ ├── biAwgnQuantization.m │ ├── binaryDmcPerformance.m │ ├── binaryDmcPerformance.mat │ ├── binaryDmcPerformanceData.m │ ├── multipleOptimal.m │ ├── nonbinaryDmcPerformance.m │ ├── nonbinaryDmcPerformance.mat │ ├── nonbinaryDmcPerformanceData.m │ └── verify.m ├── quantDmc │ ├── biAwgn2Dmc.m │ ├── channelSort.m │ ├── clib │ │ ├── mmatrix.c │ │ ├── mmatrix.h │ │ └── quantBiDmc.c │ ├── contents.m │ ├── joint2MI.m │ ├── jointDistribution.m │ ├── mexify.m │ ├── quantBiDmc.m │ ├── quantBiDmc.mexa64 │ ├── quantBiDmc.mexmaci64 │ ├── quantBiDmc.mexw64 │ ├── quantBiDmcMulti.m │ ├── quantDmcGreedy.m │ ├── quantDmcKLmeans.m │ └── randomDmc.m └── startup.m ├── Quantized Density-evolution ├── Density evolution of LDPC by Andrew Eckford.pdf ├── README.txt ├── chan_mess.m ├── de_irregular.m ├── de_regular.m ├── irregular.m ├── license.txt ├── new_chk_overflow.m ├── new_fft_convolve_chk.m ├── new_flog2wrap.m ├── new_wrap2flog.m ├── new_xchk.m ├── new_xvar.m ├── regular.m ├── threshold_tst.m └── xconvert.m ├── README.md ├── Reciprocal-channel approximation for approximation of Density Evolution Iterative Decoding Threshold ├── Octopus.png ├── README.md └── ReportDETresh.pdf ├── Reported Thresholds and BER Performance for LDPC.pdf ├── application of proposed methods.jpg ├── density_evolution_ga_python ├── README.md ├── __init__.py ├── config.py ├── config.yml ├── de_testing.py ├── de_utils.py ├── density_evolution.py ├── ga_continuous.py ├── ga_continuous_parallel.py ├── ga_discrete.py ├── ga_discrete_parallel.py └── multiprocessing_illustration.py ├── hgen.m ├── phi.m ├── phi_1.m ├── profgen.m └── rand_proto.m / Reciprocal-channel approximation for approximation of Density Evolution Iterative Decoding Threshold/LUT.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/ Reciprocal-channel approximation for approximation of Density Evolution Iterative Decoding Threshold/LUT.mat -------------------------------------------------------------------------------- / Reciprocal-channel approximation for approximation of Density Evolution Iterative Decoding Threshold/RCA_apprx.m: -------------------------------------------------------------------------------- 1 | function [flag] = RCA_apprx(HB,SNR,p,R,snr_R,infor,iter) 2 | 3 | s = 2*10^(SNR/10); 4 | 5 | iter_num = iter; 6 | mvout_threshold = 30; 7 | 8 | [m,n] = size(HB); 9 | HBTmp = HB; 10 | 11 | mu0 = ones(1,n) * s; 12 | mu0 (1:p) = zeros(1,p); 13 | mu = zeros(m,n); 14 | mv = zeros(m,n); 15 | 16 | for j = 1:n 17 | mv(:,j) = mu0(j) * HBTmp(:,j); 18 | end 19 | mvout = mu0; 20 | muout = zeros(m,1); 21 | flag = 0; 22 | for l = 1:iter_num 23 | 24 | for i = 1:m 25 | idx = find(HB(i,:) ~= 0); 26 | mvidx = mv(i,idx); 27 | mvtmp = interp1(snr_R,R,mvidx); 28 | muout(i) = sum(HB(i,idx).*mvtmp); 29 | for j = 1:length(idx) 30 | mu(i,idx(j)) = muout(i) - mvtmp(j); 31 | end 32 | end 33 | mu(mu>50) = 50; 34 | 35 | for j = 1:n 36 | idx = find(HB(:,j) ~= 0); 37 | muidx = mu(idx,j); 38 | mutmp = interp1(snr_R,R,muidx); 39 | mvout(j) = mu0(j) + sum(HB(idx,j).*mutmp); 40 | for i = 1:length(idx) 41 | mv(idx(i),j) = mvout(j) - mutmp(i); 42 | end 43 | end 44 | mv(mv>50) = 50; 45 | 46 | if(min(mvout(1:infor))>mvout_threshold) 47 | flag = 1; 48 | break; 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- / Reciprocal-channel approximation for approximation of Density Evolution Iterative Decoding Threshold/RCA_threshold.m: -------------------------------------------------------------------------------- 1 | function snr_out = RCA_threshold(B,snr_start,p,infor,iter) 2 | load('LUT.mat'); 3 | snr_step_array = [10, 1, 0.1, 0.01]; 4 | snr = snr_start; 5 | 6 | for istep = 1:length(snr_step_array) 7 | snr_step = snr_step_array(istep); 8 | go = 1; 9 | while(go) 10 | snr = snr - snr_step; 11 | 12 | [flag] = RCA_apprx(B,snr,p,R,snr_R,infor,iter); 13 | if flag == 0 14 | go = 0; 15 | snr_out = snr + snr_step; 16 | end 17 | end 18 | snr = snr + snr_step; 19 | end 20 | end 21 | 22 | -------------------------------------------------------------------------------- / Reciprocal-channel approximation for approximation of Density Evolution Iterative Decoding Threshold/main.m: -------------------------------------------------------------------------------- 1 | Protograph=[ 2 | 2 1 0 0 0 0 1 0 1 0 1 1 0 1 0 0 3 | 2 1 1 0 0 0 0 0 1 1 0 0 1 0 1 1 4 | 1 0 1 1 0 0 0 0 1 0 1 0 1 0 1 0 5 | 1 0 0 1 1 0 0 1 0 1 0 1 0 0 1 1 6 | 2 0 0 0 1 1 0 1 0 0 1 1 0 1 0 1 7 | 2 0 0 0 0 1 1 1 0 1 0 0 1 1 0 0 8 | ]; % example of Octopus MET QC-LDPC Codes R=2/3, 0.1 dB gain compare AR4JA codes 9 | [C V]=size(Protograph); 10 | iterations=250; %iterations numbers 11 | Snr_start = 2; % starting search point snr value 12 | Punctured_VN =1; %Number of Punctured Nodes from 1st columns in protograph 13 | InfVNs=V-C; %Number of information variable nodes which consider in approximation 14 | %if it some cascade construction (check nodes important) should be set by hand 15 | Rate=(V-C)/(V-Punctured_VN) %Rate of code only for EB_No_result 16 | M=2; % Modulation 2 bpsk, 4 qpsk 17 | snr_result = RCA_threshold(Protograph,Snr_start,Punctured_VN,InfVNs,iterations) 18 | EB_No_result= snr_result-10*log10(log2(M)*Rate) 19 | -------------------------------------------------------------------------------- /Covariance-Evolution/AWGN-channel Example/compute_ab.c: -------------------------------------------------------------------------------- 1 | /* 2 | * compute_ab.c 3 | * 4 | * See below 5 | * 6 | * Copyright (C) 2009 Tom Richardson 7 | * 8 | * Wrapped into matlab: Yury Polyanskiy 9 | */ 10 | 11 | static char * help_msg = "\n\ 12 | * function [a b] = compute_ab(k, R) \n\ 13 | * This function computes the LDPC scaling parameters (a,b) for a given\n\ 14 | * data size k and rate R. \n\ 15 | *\n\ 16 | * The usage of (a,b) is: WER(SNR) = Q(a*(10*log10(SNR)-b));\n\ 17 | * Note: limitations: 250 <= k <= 10000, 25/74 <= R <= 25/32\n"; 18 | 19 | 20 | #include "mex.h" 21 | #include "matrix.h" 22 | #include 23 | #include 24 | #include 25 | 26 | double Qdata[] = { 27 | 1.64741,4.37417,32,25,10, 28 | 1.7823,4.39283,32,25,20, 29 | 2.73602,4.23319,32,25,40, 30 | 4.62843,4.22278,32,25,100, 31 | 6.40456,4.11633,32,25,200, 32 | 10.5233,4.11227,32,25,400, 33 | 1.77178,3.83057,34,25,10, 34 | 2.35475,3.72985,34,25,20, 35 | 3.12746,3.54719,34,25,40, 36 | 4.865,3.48064,34,25,100, 37 | 7.83115,3.4784,34,25,200, 38 | 11.6305,3.4492,34,25,400, 39 | 1.78154,3.10672,36,25,10, 40 | 2.2443,3.01614,36,25,20, 41 | 3.20881,3.04292,36,25,40, 42 | 5.27143,3.00499,36,25,100, 43 | 7.72024,2.98124,36,25,200, 44 | 10.8001,2.95346,36,25,400, 45 | 1.91845,2.70442,38,25,10, 46 | 2.29064,2.60278,38,25,20, 47 | 3.30915,2.57697,38,25,40, 48 | 5.33661,2.55343,38,25,100, 49 | 7.38134,2.52523,38,25,200, 50 | 10.0935,2.49549,38,25,400, 51 | 1.81146,2.31754,40,25,10, 52 | 2.34017,2.23708,40,25,20, 53 | 3.09574,2.13417,40,25,40, 54 | 5.4329,2.0844,40,25,100, 55 | 7.88705,2.06081,40,25,200, 56 | 10.9385,2.00164,40,25,400, 57 | 1.77572,1.91878,42,25,10, 58 | 2.39381,1.84634,42,25,20, 59 | 3.22597,1.73751,42,25,40, 60 | 5.36644,1.71465,42,25,100, 61 | 6.78258,1.64867,42,25,200, 62 | 10.4735,1.66151,42,25,400, 63 | 1.89117,1.59822,44,25,10, 64 | 2.53221,1.53728,44,25,20, 65 | 3.16796,1.40632,44,25,40, 66 | 5.37753,1.4069,44,25,100, 67 | 7.75319,1.36131,44,25,200, 68 | 11.2761,1.36596,44,25,400, 69 | 1.80817,1.23207,46,25,10, 70 | 2.49785,1.19559,46,25,20, 71 | 3.51756,1.16054,46,25,40, 72 | 5.57619,1.10975,46,25,100, 73 | 7.7055,1.06553,46,25,200, 74 | 10.8983,1.05042,46,25,400, 75 | 1.97638,1.03702,48,25,10, 76 | 2.38761,0.879989,48,25,20, 77 | 3.46179,0.857227,48,25,40, 78 | 5.82853,0.825244,48,25,100, 79 | 8.09585,0.783093,48,25,200, 80 | 12.0788,0.770085,48,25,400, 81 | 1.86676,0.754931,50,25,10, 82 | 2.58492,0.689422,50,25,20, 83 | 3.48458,0.608158,50,25,40, 84 | 5.99078,0.534573,50,25,100, 85 | 8.0175,0.488617,50,25,200, 86 | 11.8174,0.469132,50,25,400, 87 | 1.81518,0.487696,52,25,10, 88 | 2.43107,0.385302,52,25,20, 89 | 3.28604,0.258776,52,25,40, 90 | 5.51571,0.224051,52,25,100, 91 | 8.90916,0.216781,52,25,200, 92 | 12.5695,0.1848,52,25,400, 93 | 1.82939,0.236548,54,25,10, 94 | 2.51242,0.145907,54,25,20, 95 | 3.44233,0.0442195,54,25,40, 96 | 5.75171,0.0109963,54,25,100, 97 | 8.52972,-0.0375244,54,25,200, 98 | 12.5976,-0.0521179,54,25,400, 99 | 1.79078,-0.0217274,56,25,10, 100 | 2.47329,-0.0930272,56,25,20, 101 | 3.49786,-0.183913,56,25,40, 102 | 5.91739,-0.231223,56,25,100, 103 | 8.39529,-0.262209,56,25,200, 104 | 12.5628,-0.28216,56,25,400, 105 | 1.88899,-0.156296,58,25,10, 106 | 2.46691,-0.304364,58,25,20, 107 | 3.69912,-0.3562,58,25,40, 108 | 6.40493,-0.4022,58,25,100, 109 | 8.37809,-0.476277,58,25,200, 110 | 11.9779,-0.507924,58,25,400, 111 | 1.72595,-0.419539,60,25,10, 112 | 2.5904,-0.472487,60,25,20, 113 | 3.63603,-0.5761,60,25,40, 114 | 5.93633,-0.647782,60,25,100, 115 | 8.68311,-0.681829,60,25,200, 116 | 13.1691,-0.704235,60,25,400, 117 | 2.00796,-0.469754,62,25,10, 118 | 2.05649,-0.756879,62,25,20, 119 | 3.4608,-0.761793,62,25,40, 120 | 6.09034,-0.850691,62,25,100, 121 | 8.8754,-0.867034,62,25,200, 122 | 12.9577,-0.903798,62,25,400, 123 | 1.86804,-0.747658,64,25,10, 124 | 2.70444,-0.831951,64,25,20, 125 | 3.29555,-1.00959,64,25,40, 126 | 5.85237,-1.03588,64,25,100, 127 | 8.4459,-1.08069,64,25,200, 128 | 12.8935,-1.10355,64,25,400, 129 | 1.89483,-0.943391,66,25,10, 130 | 2.54966,-1.04475,66,25,20, 131 | 3.67842,-1.11365,66,25,40, 132 | 5.89775,-1.2075,66,25,100, 133 | 9.54893,-1.22467,66,25,200, 134 | 14.1153,-1.25599,66,25,400, 135 | 1.96293,-1.04485,68,25,10, 136 | 2.60835,-1.20094,68,25,20, 137 | 3.77648,-1.26874,68,25,40, 138 | 6.55415,-1.35325,68,25,100, 139 | 9.17148,-1.39756,68,25,200, 140 | 13.8715,-1.4355,68,25,400, 141 | 1.90733,-1.22753,70,25,10, 142 | 2.35522,-1.38685,70,25,20, 143 | 3.68205,-1.44182,70,25,40, 144 | 6.29001,-1.52611,70,25,100, 145 | 9.16421,-1.57885,70,25,200, 146 | 14.2846,-1.59307,70,25,400, 147 | 1.9763,-1.31647,72,25,10, 148 | 2.51301,-1.52869,72,25,20, 149 | 3.67062,-1.58159,72,25,40, 150 | 6.4886,-1.64355,72,25,100, 151 | 9.39234,-1.71058,72,25,200, 152 | 13.2467,-1.73076,72,25,400, 153 | 1.85956,-1.53614,74,25,10, 154 | 2.66185,-1.66955,74,25,20, 155 | 3.44503,-1.78944,74,25,40, 156 | 6.16869,-1.80959,74,25,100, 157 | 9.66082,-1.85092,74,25,200, 158 | 11.9337,-1.8857,74,25,400, 159 | }; 160 | 161 | /* 162 | * fit parameters to get estimate of Q function parameters 163 | * for given info block lenght and rate 164 | * must be in range 10*25 < k < 400*25, 25/74 < r < 25/32 165 | */ 166 | int getQcoeff(double infoblockLength,double rate,double *a,double *b){ 167 | int nest, k1; 168 | double asample1,asample2,lsample1,lsample2,a1scaled, a2scaled, alpha, alb, blb, aub, bub; 169 | int nSampleLength = 6; /* number of lengths sampled */ 170 | 171 | if(rate>=25.0/32.0) return -1; 172 | if(rate<=25.0/74.0) return -1; 173 | 174 | if(infoblockLength<10*25.0) return -1; 175 | if(infoblockLength>400*25.0) return -1; 176 | 177 | nest = (int)floor(25.0/rate); 178 | nest-=nest%2; 179 | 180 | 181 | /* linear interpolate parameters */ 182 | 183 | k1 = nSampleLength*((nest-32)/2); 184 | if(infoblockLength>20*25) k1++; 185 | if(infoblockLength>40*25) k1++; 186 | if(infoblockLength>100*25) k1++; 187 | if(infoblockLength>200*25) k1++; 188 | /* increment according to sampled lengths */ 189 | 190 | /* get parameters by interpolation (with scaling for a) */ 191 | asample1 = Qdata[5*k1]; lsample1 = Qdata[5*k1+4]; 192 | asample2 = Qdata[5*(k1+1)]; lsample2 = Qdata[5*(k1+1)+4]; 193 | a1scaled = asample1/sqrt(lsample1); 194 | a2scaled = asample2/sqrt(lsample2); 195 | /* interpolate linearly */ 196 | alpha = ((infoblockLength/25.0) - lsample1)/(lsample2-lsample1); 197 | alb = (alpha*a2scaled + (1-alpha)*a1scaled) *sqrt(infoblockLength/25.0); 198 | blb = alpha*Qdata[5*(k1+1)+1] + (1-alpha)*Qdata[5*(k1)+1]; 199 | 200 | /* now upper length bounds */ 201 | k1+=nSampleLength; 202 | 203 | asample1 = Qdata[5*k1]; lsample1 = Qdata[5*k1+4]; 204 | asample2 = Qdata[5*(k1+1)]; lsample2 = Qdata[5*(k1+1)+4]; 205 | a1scaled = asample1/sqrt(lsample1); 206 | a2scaled = asample2/sqrt(lsample2); 207 | /* interpolate linearly */ 208 | alpha = ((infoblockLength/25.0) - lsample1)/(lsample2-lsample1); 209 | aub = (alpha*a2scaled + (1-alpha)*a1scaled) *sqrt(infoblockLength/25.0); 210 | bub = alpha*Qdata[5*(k1+1)+1] + (1-alpha)*Qdata[5*(k1)+1]; 211 | 212 | /* now interpolate over rate */ 213 | alpha = (rate - 25.0/(nest+2)) /( (25.0/nest) - (25.0/(nest+2)) ); 214 | *a = alb*alpha+(1-alpha)*aub; 215 | *b = blb*alpha+(1-alpha)*bub; 216 | return 0; 217 | } 218 | 219 | /* simple Q function approximation (3% error bound) */ 220 | double Q(double x){ 221 | if(x<0) return 1.0-Q(-x); 222 | double xsq=x*x; 223 | return exp(-xsq/2.0)/(1.64*x+sqrt(0.76*xsq+4)); 224 | } 225 | 226 | /* estimated FER given a,b,snr */ 227 | double Qest(double a,double b,double snr){ 228 | return Q(a*(snr-b)); 229 | } 230 | 231 | 232 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 233 | { 234 | double k; 235 | double R = 1/2; 236 | double a,b; 237 | 238 | if( (nrhs > 2) || !nrhs) goto usage; 239 | 240 | /* 241 | * The first param is integer, but matlab works with doubles by default 242 | */ 243 | if(!mxIsDouble(prhs[0])) goto nondouble; 244 | 245 | if(nrhs == 2){ 246 | if(!mxIsDouble(prhs[1])) goto nondouble; 247 | R = *mxGetPr(prhs[1]); 248 | } 249 | k = *mxGetPr(prhs[0]); 250 | 251 | #if DEBUG>1 252 | mexPrintf(" +++ compute_ab: nlhs = %d, k = %g, R= %.3g ", nlhs, k, R); 253 | #endif 254 | 255 | if(getQcoeff(k,R,&a,&b)){ 256 | /* 257 | * Note: my code relies on compute_ab() returning NAN for 258 | * unsupported rates 259 | */ 260 | mexPrintf("Warning: getQcoeff() failed. k,R out of range?\n"); 261 | a = b = NAN; 262 | } 263 | 264 | if(nlhs == 0){ 265 | int i; 266 | mexPrintf(" +++ compute_ab: a = %.6g, b = %.6g\n", a, b); 267 | for(i=0;i<50;i++) 268 | mexPrintf(" SNR = %g dB:\t\tWER %g\n",-2.0+0.2*i,Qest(a,b,-2.0+0.2*i)); 269 | } 270 | if(nlhs > 0){ 271 | plhs[0] = mxCreateNumericMatrix(1,1, mxDOUBLE_CLASS, mxREAL); 272 | if(!plhs[0]) goto oom; 273 | *mxGetPr(plhs[0]) = a; 274 | } 275 | if(nlhs > 1){ 276 | plhs[1] = mxCreateNumericMatrix(1,1, mxDOUBLE_CLASS, mxREAL); 277 | if(!plhs[1]) goto oom; 278 | *mxGetPr(plhs[1]) = b; 279 | } 280 | return; 281 | oom: 282 | mexPrintf("ERR: OOM\n"); 283 | return; 284 | 285 | nondouble: 286 | mexPrintf("ERR: nondouble arguments\n"); 287 | goto helpmsg; 288 | usage: 289 | mexPrintf("ERR: usage\n"); 290 | helpmsg: 291 | mexPrintf("%s\n", help_msg); 292 | return; 293 | } 294 | -------------------------------------------------------------------------------- /Covariance-Evolution/AWGN-channel Example/compute_ab.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/Covariance-Evolution/AWGN-channel Example/compute_ab.mexw64 -------------------------------------------------------------------------------- /Covariance-Evolution/AWGN-channel Example/me_multin.m: -------------------------------------------------------------------------------- 1 | function lm = me_multin(Ns, epsil, A); 2 | % Returns ldpc achevability data for a given (n,epsil,A) 3 | cap = log2(1+A^2)/2; 4 | Pdb = 20*log10(A); 5 | 6 | lm = []; 7 | for n = Ns; 8 | % these are absolute bounds on rate 9 | Rmin = 25/74; Rmax = 25/32; 10 | Rmax = min(Rmax, cap); 11 | % Step 1: find minimal acceptable rate 12 | Ptry = +Inf; 13 | Rnext = Rmin; Rstep = 0.1; 14 | while ~(Ptry <= Pdb) 15 | Rtry = Rnext; 16 | Ktry = floor(n*Rtry); 17 | [a b] = compute_ab(Ktry, Rtry); 18 | Ptry = (-norminv(epsil))/a + b; 19 | %% disp(sprintf(' Rtry = %.3g, Ktry = %d, Ptry = %.3g', Rtry, Ktry, Ptry)); 20 | Rnext = Rnext + Rstep; 21 | if(Rnext > Rmax) 22 | if (Rstep == 0.1) 23 | Rnext = Rmin; 24 | Rstep = 0.01; 25 | else 26 | disp(sprintf(['me_multin(n = %d, epsil = %g, P = %.2g dB:' ... 27 | ' could not find minrate'], n, epsil, Pdb)); 28 | Rtry = Inf; 29 | break; 30 | end 31 | end 32 | end 33 | if(Rtry == Inf) 34 | lm = [lm NaN]; 35 | continue; 36 | end 37 | Rmin = Rtry; 38 | Kmin = Ktry; 39 | Pmin = Ptry; 40 | % Step 2: find maximal acceptable rate 41 | 42 | Ptry = -Inf; 43 | Rnext = Rmax; Rstep = 0.1; 44 | while ~(Ptry >= Pdb) 45 | Rtry = Rnext; 46 | Ktry = ceil(n*Rtry); 47 | [a b] = compute_ab(Ktry, Rtry); 48 | Ptry = (-norminv(epsil))/a + b; 49 | Rnext = Rnext - Rstep; 50 | if(Rnext < Rmin) 51 | if (Rstep == 0.1) 52 | Rnext = Rmax; 53 | Rstep = 0.01; 54 | else 55 | disp(sprintf(['me_multin(n = %d, epsil = %g, P = %.2g dB:' ... 56 | ' could not find maxrate'], n, epsil, Pdb)); 57 | Rtry = Inf; 58 | break; 59 | end 60 | end 61 | end 62 | if(Rtry == Inf) 63 | lm = [lm NaN]; 64 | continue; 65 | end 66 | Rmax = Rtry; 67 | Kmax = Ktry; 68 | Pmax = Ptry; 69 | % Step 3: proceed by binary division 70 | 71 | disp(sprintf(['me_multin(n = %d, eps = %g, P = %.2g dB: R = (%.3g, %.3g), '... 72 | 'K = (%d, %d), P = (%.3g, %.3g)'], ... 73 | n, epsil, Pdb, Rmin, Rmax, Kmin, Kmax, Pmin, Pmax)); 74 | 75 | while (Kmax - Kmin) > 1 76 | Rtry = (Rmin + Rmax)/2; 77 | Ktry = floor(Rtry*n); 78 | [a b] = compute_ab(Ktry, Rtry); 79 | Ptry = (-norminv(epsil))/a + b; 80 | %% disp(sprintf(' Rtry = %.3g, Ktry = %d, Ptry = %.3g', Rtry, Ktry, Ptry)); 81 | if(Ptry == NaN) break; end 82 | if(Ptry > Pdb) 83 | Rmax = Rtry; Kmax = Ktry; 84 | else 85 | Rmin = Rtry; Kmin = Ktry; 86 | end 87 | end 88 | reason = 'PREC OK:'; 89 | if(Ptry == NaN) 90 | reason = 'NAN BREAK:'; 91 | end 92 | disp(sprintf(' %s lm = %d', reason, Kmin)); 93 | lm = [lm Kmin]; 94 | end 95 | -------------------------------------------------------------------------------- /Covariance-Evolution/AWGN-channel Example/me_snr.m: -------------------------------------------------------------------------------- 1 | % Copyright (C) 2009 Tom Richardson 2 | %Wrapped into matlab: Yury Polyanskiy 3 | %Linear approximation based prediction of waterfall using Covariance Evolution 4 | %for Richardson's MET-LDPC code protograph under AWGN-channel 5 | %still doesn't have complete theoretical proof, but base on same idea as Yury Bound 6 | %(Partial exist for BSC using Exit-like approach) 7 | 8 | function [snr ebno] = me_snr(n, R, Pe) 9 | % Gets the snr (and ebno) for the Multi-Edge LDPC of rate R and blocklength n 10 | % note: ebno is defined similar to the gen_dolinar: 11 | % SNR = 2*ebno*R <=> ebno = SNR/2/R 12 | % 13 | % Note: all output values are NOT in db 14 | 15 | % hardcoded constraints in compute_ab 16 | k = n*R; 17 | if (k < 250) || (k > 10000) || (R < 25/74) || (R>25/32) 18 | disp(sprintf('me_snr: n=%d, R=%g, Pe=%g: ERROR: (k,R) out of range', n, R, Pe)); 19 | snr = NaN; 20 | ebno = NaN; 21 | return; 22 | end 23 | [a b] = compute_ab(k, R); 24 | snr_db = (-norminv(Pe))/a + b; 25 | 26 | snr = 10^(snr_db/10); 27 | ebno = snr/2/R; 28 | 29 | -------------------------------------------------------------------------------- /Covariance-Evolution/Main.m: -------------------------------------------------------------------------------- 1 | %protograph 2 | protograph=[ 3 | 1 0 0 0 0 1 0 1 0 1 1 0 1 0 0 2 4 | 1 1 0 0 0 0 0 1 1 0 0 1 0 1 1 2 5 | 0 1 1 0 0 0 0 1 0 1 0 1 0 1 0 1 6 | 0 0 1 1 0 0 1 0 1 0 1 0 0 1 1 1 7 | 0 0 0 1 1 0 1 0 0 1 1 0 1 0 1 2 8 | 0 0 0 0 1 1 1 0 1 0 0 1 1 0 0 2 9 | ]; 10 | 11 | savefile=['Octopus.mat']; % file to store result 12 | eps=0.2; % erasure probability 13 | invstep=4; % step^-1 is the step size for Diff Eq. 14 | Var=false; % flag to compute the variance 15 | [nc,nv]=size(protograph); 16 | puncture_mask=ones(1,nv); 17 | puncture_mask(16)=0; %choice symbols for puncturing 18 | 19 | 20 | input.proto=protograph; 21 | input.puncture_mask=puncture_mask; 22 | input.eps=eps; 23 | input.nv=nv; 24 | input.nc=nc; 25 | input.Var=Var; 26 | input.step=invstep; 27 | input.savefile=savefile; 28 | calc(input) -------------------------------------------------------------------------------- /Covariance-Evolution/Octopus.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/Covariance-Evolution/Octopus.mat -------------------------------------------------------------------------------- /Covariance-Evolution/README.md: -------------------------------------------------------------------------------- 1 | # Covariance-Evolution 2 | 3 | Covariance Evolution Implementation for BEC-channel with Octopus protograph. After paper published, i'll disclosure full version of source code. 4 | 5 | 6 | Example of waterfall prediction for rate and length adaptive (25/32factor*deta 8 | x=x-deta; 9 | y=y+deta; 10 | tmp(j:j+1)=[x y]; 11 | matrix=[matrix;tmp]; 12 | end 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | for j=2:LL-2 15 | [m,n]=size(matrix); 16 | for ii=1:m 17 | x=matrix(ii,j); 18 | y=matrix(ii,j+1);tmp=matrix(ii,:); 19 | while x>factor*deta 20 | x=x-deta; 21 | y=y+deta; 22 | tmp(j:j+1)=[x y]; 23 | matrix=[matrix;tmp]; 24 | end 25 | end 26 | end 27 | 28 | 29 | j=LL-1;m_last=[]; 30 | [m,n]=size(matrix); 31 | for ii=1:m 32 | x=matrix(ii,j); 33 | y=matrix(ii,j+1);tmp=matrix(ii,:); 34 | while x>factor*deta 35 | x=x-deta; 36 | y=y+deta; 37 | tmp(j:j+1)=[x y]; 38 | matrix=[matrix;tmp];m_last=[m_last;tmp]; 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /GA/deopt.m: -------------------------------------------------------------------------------- 1 | function [FVr_bestmem,S_bestval,I_nfeval,FM_pop] = deopt(S_struct,var_people) 2 | global var_index 3 | %-----This is just for notational convenience and to keep the code uncluttered.-------- 4 | I_NP = S_struct.I_NP; 5 | F_weight = S_struct.F_weight; 6 | F_CR = S_struct.F_CR; 7 | I_D = S_struct.I_D; 8 | I_itermax = S_struct.I_itermax; 9 | I_strategy = S_struct.I_strategy; 10 | iter_GA = S_struct.iter_GA 11 | %-----Initialize population and some arrays------------------------------- 12 | FM_pop = var_people;last_sigma=0; 13 | 14 | FM_popold = zeros(size(FM_pop)); % toggle population 15 | FVr_bestmem = zeros(1,I_D);% best population member ever 16 | FVr_bestmemit = zeros(1,I_D);% best population member in iteration 17 | I_nfeval = 0; % number of function evaluations 18 | 19 | %------Evaluate the best member after initialization---------------------- 20 | 21 | I_best_index = 1; % start with first population member 22 | S_val(1) =price_evalution(FM_pop(I_best_index,:),iter_GA); 23 | S_bestval = S_val(1); % best objective function value so far 24 | I_nfeval = I_nfeval + 1; 25 | for k=2:I_NP % check the remaining members% 26 | S_val(k) =price_evalution(FM_pop(k,:),iter_GA); 27 | I_nfeval = I_nfeval + 1; 28 | if (left_win(S_val(k),S_bestval) == 1) 29 | I_best_index = k; % save its location 30 | S_bestval = S_val(k); 31 | end 32 | end 33 | FVr_bestmemit = FM_pop(I_best_index,:); % best member of current iteration 34 | S_bestvalit = S_bestval; % best value of current iteration 35 | 36 | FVr_bestmem = FVr_bestmemit; % best member ever 37 | 38 | %------DE-Minimization--------------------------------------------- 39 | %------FM_popold is the population which has to compete. It is-------- 40 | %------static through one iteration. FM_pop is the newly-------------- 41 | %------emerging population.---------------------------------------- 42 | 43 | FM_pm1 = zeros(I_NP,I_D); % initialize population matrix 1 44 | FM_pm2 = zeros(I_NP,I_D); % initialize population matrix 2 45 | FM_pm3 = zeros(I_NP,I_D); % initialize population matrix 3 46 | FM_pm4 = zeros(I_NP,I_D); % initialize population matrix 4 47 | FM_pm5 = zeros(I_NP,I_D); % initialize population matrix 5 48 | FM_bm = zeros(I_NP,I_D); % initialize FVr_bestmember matrix 49 | FM_ui = zeros(I_NP,I_D); % intermediate population of perturbed vectors 50 | FM_mui = zeros(I_NP,I_D); % mask for intermediate population 51 | FM_mpo = zeros(I_NP,I_D); % mask for old population 52 | FVr_rot = (0:1:I_NP-1); % rotating index array (size I_NP) 53 | FVr_rotd = (0:1:I_D-1); % rotating index array (size I_D) 54 | FVr_rt = zeros(I_NP); % another rotating index array 55 | FVr_rtd = zeros(I_D); % rotating index array for exponential crossover 56 | FVr_a1 = zeros(I_NP); % index array 57 | FVr_a2 = zeros(I_NP); % index array 58 | FVr_a3 = zeros(I_NP); % index array 59 | FVr_a4 = zeros(I_NP); % index array 60 | FVr_a5 = zeros(I_NP); % index array 61 | FVr_ind = zeros(4); 62 | 63 | I_iter = 1; 64 | while ((I_iter < I_itermax)) 65 | FM_popold = FM_pop; % save the old population 66 | S_struct.FM_pop = FM_pop; 67 | S_struct.FVr_bestmem = FVr_bestmem; 68 | 69 | FVr_ind = randperm(4); % index pointer array 70 | 71 | FVr_a1 = randperm(I_NP); % shuffle locations of vectors 72 | FVr_rt = rem(FVr_rot+FVr_ind(1),I_NP); % rotate indices by ind(1) positions 73 | FVr_a2 = FVr_a1(FVr_rt+1); % rotate vector locations 74 | FVr_rt = rem(FVr_rot+FVr_ind(2),I_NP); 75 | FVr_a3 = FVr_a2(FVr_rt+1); 76 | FVr_rt = rem(FVr_rot+FVr_ind(3),I_NP); 77 | FVr_a4 = FVr_a3(FVr_rt+1); 78 | FVr_rt = rem(FVr_rot+FVr_ind(4),I_NP); 79 | FVr_a5 = FVr_a4(FVr_rt+1); 80 | 81 | FM_pm1 = FM_popold(FVr_a1,:); % shuffled population 1 82 | FM_pm2 = FM_popold(FVr_a2,:); % shuffled population 2 83 | FM_pm3 = FM_popold(FVr_a3,:); % shuffled population 3 84 | FM_pm4 = FM_popold(FVr_a4,:); % shuffled population 4 85 | FM_pm5 = FM_popold(FVr_a5,:); % shuffled population 5 86 | 87 | for k=1:I_NP % population filled with the best member 88 | FM_bm(k,:) = FVr_bestmemit; % of the last iteration 89 | end 90 | 91 | FM_mui = rand(I_NP,I_D) < F_CR; % all random numbers < F_CR are 1, 0 otherwise 92 | FM_mpo = FM_mui < 0.5; % inverse mask to FM_mui 93 | 94 | if (I_strategy == 1) % DE/rand/1 95 | FM_ui = FM_pm3 + F_weight*(FM_pm1 - FM_pm2); % differential variation 96 | FM_ui = FM_popold.*FM_mpo + FM_ui.*FM_mui; % crossover 97 | FM_origin = FM_pm3; 98 | elseif (I_strategy == 2) % DE/local-to-best/1 99 | FM_ui = FM_popold + F_weight*(FM_bm-FM_popold) + F_weight*(FM_pm1 - FM_pm2); 100 | FM_ui = FM_popold.*FM_mpo + FM_ui.*FM_mui; 101 | FM_origin = FM_popold; 102 | elseif (I_strategy == 3) % DE/best/1 with jitter 103 | FM_ui = FM_bm + (FM_pm1 - FM_pm2).*((1-0.9999)*rand(I_NP,I_D)+F_weight); 104 | FM_ui = FM_popold.*FM_mpo + FM_ui.*FM_mui; 105 | FM_origin = FM_bm; 106 | elseif (I_strategy == 4) % DE/rand/1 with per-vector-dither 107 | f1 = ((1-F_weight)*rand(I_NP,1)+F_weight); 108 | for k=1:I_D 109 | FM_pm5(:,k)=f1; 110 | end 111 | FM_ui = FM_pm3 + (FM_pm1 - FM_pm2).*FM_pm5; % differential variation 112 | FM_origin = FM_pm3; 113 | FM_ui = FM_popold.*FM_mpo + FM_ui.*FM_mui; % crossover 114 | elseif (I_strategy == 5) % DE/rand/1 with per-vector-dither 115 | f1 = ((1-F_weight)*rand+F_weight); 116 | FM_ui = FM_pm3 + (FM_pm1 - FM_pm2)*f1; % differential variation 117 | FM_origin = FM_pm3; 118 | FM_ui = FM_popold.*FM_mpo + FM_ui.*FM_mui; % crossover 119 | else % either-or-algorithm 120 | if (rand < 0.5); % Pmu = 0.5 121 | FM_ui = FM_pm3 + F_weight*(FM_pm1 - FM_pm2);% differential variation 122 | FM_origin = FM_pm3; 123 | else % use F-K-Rule: K = 0.5(F+1) 124 | FM_ui = FM_pm3 + 0.5*(F_weight+1.0)*(FM_pm1 + FM_pm2 - 2*FM_pm3); 125 | end 126 | FM_ui = FM_popold.*FM_mpo + FM_ui.*FM_mui; % crossover 127 | end 128 | 129 | %-----Optional parent+child %selection----------------------------------------- 130 | %-----Select which vectors are allowed to enter the new population------------ 131 | for k=1:I_NP 132 | FM_ui(k,:)=abs(FM_ui(k,:));tmp=sum(FM_ui(k,:)); 133 | if tmp<1 134 | S_tempval= price_evalution2(FM_ui(k,:),iter_GA,S_val(k)); 135 | I_nfeval = I_nfeval + 1; 136 | if S_tempval>S_val(k) 137 | FM_pop(k,:) = FM_ui(k,:); % replace old vector with new one (for new iteration) 138 | S_val(k) = S_tempval; % save value in "cost array" 139 | %----we update S_bestval only in case of success to save time----------- 140 | if S_tempval>S_bestval 141 | S_bestval = S_tempval; % new best value 142 | FVr_bestmem = FM_ui(k,:); % new best parameter vector ever 143 | end 144 | end 145 | end %if 146 | end % for k = 1:NP 147 | 148 | FVr_bestmemit = FVr_bestmem; % freeze the best member of this iteration for the coming 149 | if S_bestval>last_sigma 150 | I_iter = I_iter + 1 151 | s=sprintf('%dx%d_iter_sigma.txt',I_NP,I_D); 152 | fid = fopen(s,'a'); 153 | fprintf(fid,'\n'); 154 | fprintf(fid,'%s %6.3E\n','iter =',I_iter); 155 | fprintf(fid,'%s %6.8E\n','sigma =',S_bestval); 156 | fclose(fid); 157 | save rate09 S_bestval FVr_bestmem FM_pop var_index 158 | end 159 | last_sigma=S_bestval; 160 | end %---end while ((I_iter < I_itermax) ... 161 | -------------------------------------------------------------------------------- /GA/initial.m: -------------------------------------------------------------------------------- 1 | function [var_people]=initial(R,IT_MAX,pe_limit) 2 | global fixed_Rate 3 | global var_index 4 | global ch_index 5 | global sigma_n 6 | global struct 7 | 8 | digits(100); 9 | x=[10 200]; 10 | y(1)=log10(sqrt(pi/x(1))*exp(-x(1)/4)*(1-10.0/7.0/x(1))); 11 | y(2)=log10(sqrt(pi/x(2))*exp(-x(2)/4)*(1-10.0/7.0/x(2))); 12 | struct.x=x; 13 | struct.y=y; 14 | %IT_MAX=40; %Number of iteration in decoder 15 | %pe_limit= 1e-10; % BER level of error 16 | fixed_Rate=R; % Rate 17 | 18 | first=2;last=20;number=6;% Maximal, Minimal Column Weight, Number of weight 19 | [var_index0]=var_nodes(first,last,number); 20 | [var_index]=search_index(var_index0,R); 21 | save var_index04 var_index R 22 | load var_index04 23 | number=length(var_index); 24 | [var_people]=var(number);sigma_n=0.4237; 25 | 26 | 27 | 28 | 29 | 30 | 31 | % var_no=[0.2339 0.2123 0.1468 0.1027 0.3043]; 32 | %var_index=[2 3 4 6 7 14 15 16 39 40]; 33 | % var_index=[2 3 6 7 19 20]; 34 | 35 | -------------------------------------------------------------------------------- /GA/inv_Phi_2.m: -------------------------------------------------------------------------------- 1 | function [x]=inv_Phi_2(y,start) 2 | start=10; 3 | x=start;inv_delta= 10;inv_limit= 10000; 4 | while xinv_limit 11 | y_ref=sqrt(pi/x)*exp(-x/4)*(1-10.0/7.0/x); 12 | if(y_ref>y) break; end 13 | x=x+inv_delta/10; 14 | end 15 | 16 | while xinv_limit 23 | y_ref=sqrt(pi/x)*exp(-x/4)*(1-10.0/7.0/x); 24 | if(y_ref>y) break; end 25 | x=x+inv_delta/1000; 26 | end 27 | 28 | while xinv_limit 35 | y_ref=sqrt(pi/x)*exp(-x/4)*(1-10.0/7.0/x); 36 | if(y_ref>y) break; end 37 | x=x+inv_delta/100000; 38 | end -------------------------------------------------------------------------------- /GA/ir_GA.m: -------------------------------------------------------------------------------- 1 | function [sigma_n]=ir_GA(sigma_n,sigma_PRECISION,iter_GA) 2 | global IT_MAX 3 | global pe_limit 4 | global var_degree 5 | global ch_degree 6 | global change_point 7 | global var_index 8 | global ch_index 9 | change_point=10; 10 | alpha=-0.4527;beta=0.0218;gama=0.86;Phi_star=exp(alpha*change_point^gama+beta); 11 | count=0;flag=0; 12 | while (1) 13 | iter_mu0=-1; 14 | var_ch=4/sigma_n^2; mu0=var_ch/2; 15 | pe(1)=0.5*erfc(sqrt(mu0)/2); 16 | pp(1)=pe(1); kk=var_index-1; 17 | h_sr=Phi(mu0);mv(var_index)=mu0; 18 | for iteration=1:IT_MAX 19 | if iteration>1 20 | mv(var_index)=mu0+kk.*muu(iteration-1); 21 | end 22 | h=Phi(mv(var_index));h_sr=var_degree(var_index)*h'; 23 | y(ch_index)=1-(1-h_sr).^(ch_index-1); 24 | for j=1:length(ch_index) 25 | if(y(ch_index(j))1) &(pe(iteration)>=pe(iteration-1)) 39 | iter_mu0=-1; 40 | break; 41 | end 42 | end 43 | if (count<2) 44 | if ((iter_mu0==-1) &(sigma_PRECISION>0)) | ((iter_mu0==1 & sigma_PRECISION<0)) 45 | sigma_PRECISION=-sigma_PRECISION/2; count=count+1; 46 | end 47 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 48 | else 49 | if ((iter_mu0==-1) &(sigma_PRECISION>0))|((iter_mu0==1) & (sigma_PRECISION<0)) 50 | sigma_PRECISION=-sigma_PRECISION/10; flag=flag+1; 51 | end 52 | end 53 | 54 | if flag>=iter_GA 55 | break 56 | end 57 | sigma_n=sigma_n+sigma_PRECISION; 58 | end 59 | 60 | -------------------------------------------------------------------------------- /GA/ir_GA2.m: -------------------------------------------------------------------------------- 1 | function [iter_mu0]=ir_GA2(sigma_n) 2 | global IT_MAX 3 | global pe_limit 4 | global var_degree 5 | global ch_degree 6 | global change_point 7 | global var_index 8 | global ch_index 9 | change_point=10; 10 | alpha=-0.4527;beta=0.0218;gama=0.86;Phi_star=exp(alpha*change_point^gama+beta); 11 | 12 | iter_mu0=-1; 13 | var_ch=4/sigma_n^2; mu0=var_ch/2; 14 | pe(1)=0.5*erfc(sqrt(mu0)/2); 15 | pp(1)=pe(1); kk=var_index-1; 16 | h_sr=Phi(mu0);mv(var_index)=mu0; 17 | for iteration=1:IT_MAX 18 | if iteration>1 19 | mv(var_index)=mu0+kk.*muu(iteration-1); 20 | end 21 | h=Phi(mv(var_index));h_sr=var_degree(var_index)*h'; 22 | y(ch_index)=1-(1-h_sr).^(ch_index-1); 23 | for j=1:length(ch_index) 24 | if(y(ch_index(j))1) &(pe(iteration)>=pe(iteration-1)) 38 | iter_mu0=-1; 39 | break; 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /GA/left_win.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Function: I_z = left_win(S_x,S_y) 3 | % Author: Rainer Storn 4 | % Description: left_win(S_x,S_y) takes structures S_x and S_y as an argument. 5 | % The function returns 1 if the left structure of the input structures, 6 | % i.e. S_x, wins. If the right structure, S_y, wins, the result is 0. 7 | % Parameters: S_x.I_nc (I) Number of constraints (must be the same for x and y). 8 | % S_x.I_no (I) Number of objectives (must be the same for x and y). 9 | % S_x.FVr_ca (I) Constraint array containing the constraint violation values. 10 | % If the value is 0 the constraint is met. If it is > 0 it is 11 | % still violated. 12 | % S_x.FVr_oa (I) Objective array containing cost values which are supposed to be 13 | % minimized. 14 | % Return value: I_z (O) If S_x wins over S_y then I_z=1 else I_z=0. 15 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 | 17 | function I_z = left_win(S_x,S_y); 18 | I_z = 1; %start with I_z=1 19 | 20 | %----deal with the constraints first. If constraints are not met------ 21 | %----S_x can't win.--------------------------------------------------- 22 | if S_x>S_y 23 | I_z=1; 24 | else 25 | I_z=0; 26 | end -------------------------------------------------------------------------------- /GA/main.m: -------------------------------------------------------------------------------- 1 | clear all 2 | clc 3 | global var_degree 4 | global ch_degree 5 | global count 6 | global fixed_Rate 7 | global var_index 8 | global ch_index 9 | global IT_MAX 10 | global pe_limit 11 | R=0.5; % rate of code 12 | IT_MAX=40; %Number of iteration in BP decoder 13 | pe_limit= 1e-10; % BER level of error 14 | count=0; 15 | [var_people]=initial(R,IT_MAX,pe_limit); 16 | 17 | [I_NP,I_D]=size(var_people); 18 | I_itermax = 50;iter_GA=4; % Setting for differential evolution iteration of DE 19 | % F_weight DE-stepsize F_weight ex [0, 2] 20 | F_weight = 0.80; 21 | % F_CR crossover probabililty constant ex [0, 1] 22 | F_CR = 0.8; 23 | 24 | % Type of differential evolution (DE) optimization strategy 25 | % https://en.wikipedia.org/wiki/Differential_evolution 26 | %1 DE/rand/1 ; 27 | %2 DE/local-to-best/1 28 | %3 DE/best/1 with jitter 29 | %4 DE/rand/1 with per-vector-dither 30 | %for detail 94 line in deopt.m 31 | I_strategy = 3; 32 | S_struct.I_NP = I_NP; 33 | S_struct.F_weight = F_weight; 34 | S_struct.F_CR = F_CR; 35 | S_struct.I_D = I_D; 36 | S_struct.I_itermax = I_itermax; 37 | S_struct.I_strategy = I_strategy; 38 | S_struct.iter_GA = iter_GA; 39 | 40 | [FVr_x,sigma,I_nf,FM_pop] = deopt(S_struct,var_people) 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /GA/price_evalution.m: -------------------------------------------------------------------------------- 1 | function [sigma_n]= price_evalution(var,iter_GA) 2 | global var_degree 3 | global var_index 4 | global fixed_Rate 5 | global ch_index 6 | global ch_degree 7 | global sigma_n 8 | global count 9 | 10 | tt=1-sum(var);var=[tt,var]; 11 | var_degree(var_index)=var; 12 | [ch_degree,ch_index]=rate_redress2(var_degree(var_index),fixed_Rate,var_index); 13 | sigma_PRECISION=0.1; 14 | [sigma_n]=ir_GA(sigma_n,sigma_PRECISION,iter_GA); 15 | sigma_n 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | count=count+1; 25 | % Eb_N0_dB=0.4822; %SNR per bit, Eb/N0=1/R/N0=1/R/(2var)=1/(2R*var)-->1/var=2R*(Eb/N0) 26 | % var_ch=8*R*10^(Eb_N0_dB/10); %LLR��� var_ch=4/var=4*2R*(Eb/N0)=8R*Eb/N0 27 | % sigma_n=sqrt(4/var_ch); %sigma_n=sqrt(var) 28 | % sigma_n=0.9460; %Eb_N0_dB=10*log10(1/(sigma_n*sigma_n*2*R)) 29 | % 1-sum(ch_degree(ch_index)./ch_index)/sum(var_degree(var_index)./var_index); -------------------------------------------------------------------------------- /GA/price_evalution2.m: -------------------------------------------------------------------------------- 1 | function [sigma_n]= price_evalution2(var,iter_GA,sigma_n) 2 | global var_degree 3 | global var_index 4 | global fixed_Rate 5 | global ch_index 6 | global ch_degree 7 | 8 | tt=1-sum(var);var=[tt,var]; 9 | var_degree(var_index)=var; 10 | [ch_degree,ch_index]=rate_redress2(var_degree(var_index),fixed_Rate,var_index); 11 | sigma_n=sigma_n+0.0001; 12 | [flag]=ir_GA2(sigma_n); 13 | if flag==1 14 | sigma_PRECISION=0.1; 15 | [sigma_n]=ir_GA(sigma_n,sigma_PRECISION,iter_GA); 16 | sigma_n 17 | else 18 | sigma_n=0.3; 19 | end 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | % Eb_N0_dB=0.4822; %SNR per bit, Eb/N0=1/R/N0=1/R/(2var)=1/(2R*var)-->1/var=2R*(Eb/N0) 34 | % var_ch=8*R*10^(Eb_N0_dB/10); %LLR��� var_ch=/var=*2R*(Eb/N0)=8R*Eb/N0 35 | % sigma_n=sqrt(/var_ch); %sigma_n=sqrt(var) 36 | % sigma_n=0.9460; %Eb_N0_dB=10*log10(1/(sigma_n*sigma_n*2*R)) 37 | % 1-sum(ch_degree(ch_index)./ch_index)/sum(var_degree(var_index)./var_index); 38 | 39 | -------------------------------------------------------------------------------- /GA/rate_redress2.m: -------------------------------------------------------------------------------- 1 | function [ch_degree,ch_index,dc_av]=rate_redress2(var_map,fixed_Rate,var_index) 2 | 3 | vv=var_map./var_index; 4 | dc_av=1/((1-fixed_Rate)*sum(vv)); 5 | ch_index(1)=floor(dc_av);ch_index(2)=ch_index(1)+1; 6 | ch_degree(ch_index(1))=ch_index(1)*ch_index(2)/dc_av-ch_index(1); 7 | ch_degree(ch_index(2))=1-ch_degree(ch_index(1)); 8 | -------------------------------------------------------------------------------- /GA/search_index.m: -------------------------------------------------------------------------------- 1 | function [var_index_out]=search_index(var_index0,fixed_Rate) 2 | global var_degree 3 | global var_index 4 | global ch_degree 5 | global ch_index 6 | [M,N]=size(var_index0);sigma_n=0.2; 7 | degree=rand(1,N);var_index=var_index0(1,:);var_degree=[];var_degree(var_index)=degree/sum(degree); 8 | [ch_degree,ch_index,dc_av]=rate_redress2(var_degree(var_index),fixed_Rate,var_index); 9 | sigma_PRECISION=0.1; 10 | [sigma_n]=ir_GA(sigma_n,sigma_PRECISION,4); 11 | for loop=1:10 12 | for i=2:M 13 | degree=rand(1,N); 14 | var_degree=[];var_degree(var_index)=degree/sum(degree);var_index=var_index0(i,:); 15 | [ch_degree,ch_index,dc_av]=rate_redress2(var_degree(var_index),fixed_Rate,var_index); 16 | sigma_n2=sigma_n+0.0001; 17 | iter_mu0=ir_GA2(sigma_n2); 18 | if iter_mu0==1 19 | sigma_PRECISION=0.1; 20 | [sigma_n]=ir_GA(sigma_n,sigma_PRECISION,5) 21 | var_index_out=var_index; 22 | end 23 | end 24 | for i=2:M 25 | degree=abs(randn(1,N)); 26 | var_degree=[];var_degree(var_index)=degree/sum(degree);var_index=var_index0(i,:); 27 | [ch_degree,ch_index,dc_av]=rate_redress2(var_degree(var_index),fixed_Rate,var_index); 28 | sigma_n2=sigma_n+0.0001; 29 | iter_mu0=ir_GA2(sigma_n2); 30 | if iter_mu0==1 31 | sigma_PRECISION=0.1; 32 | [sigma_n]=ir_GA(sigma_n,sigma_PRECISION,5) 33 | var_index_out=var_index; 34 | end 35 | end 36 | end 37 | 38 | -------------------------------------------------------------------------------- /GA/var.m: -------------------------------------------------------------------------------- 1 | function [var_profile]=var(number) 2 | L=40*(number+1); 3 | var_profile=zeros(L,number-1); 4 | for i=1:L 5 | var=rand(1,number);var=var/sum(var); 6 | var_profile(i,:)=var(2:end); 7 | if mod(i,2) 8 | var=randn(1,number);var=abs(var);var=var/sum(var); 9 | var_profile(i,:)=var(2:end); 10 | end 11 | end -------------------------------------------------------------------------------- /GA/var_nodes.m: -------------------------------------------------------------------------------- 1 | function [var]=var_nodes(first,last,number) 2 | var=[]; 3 | if number==6 4 | tp(1)=first; 5 | tp(2)=first+1; 6 | for k=first+2:last/2-1 7 | tp(3) =k; 8 | for q=k+1:last/2 9 | tp(4)=q; 10 | for tt=q+1:last-1 11 | tp(5)=tt; tp(6)=last; 12 | var=[var;tp]; 13 | end 14 | end 15 | end 16 | end 17 | 18 | 19 | if number==5 20 | tp(1)=first; 21 | tp(2)=first+1; 22 | for k=first+2:last/2 23 | tp(3) =k; 24 | for q=k+1:last-1 25 | tp(4)=q;tp(5)=last; 26 | var=[var;tp]; 27 | end 28 | end 29 | end 30 | 31 | %%%%%%%%%%%%%%%%%%%% 32 | if number==4 33 | tp(1)=first; 34 | for k=first+1:last-2 35 | tp(2) =k; 36 | for q=k+1:last-1 37 | tp(3)=q;tp(4)=last; 38 | var=[var;tp]; 39 | end 40 | end 41 | end 42 | 43 | 44 | if number==3 45 | tp(1) =first; 46 | for q=first+1:last-1 47 | tp(2)=q; tp(3)=last; 48 | var=[var;tp]; 49 | end 50 | 51 | end 52 | 53 | if number==2 54 | tp(1) =first;tp(2)=last; 55 | var=[var;tp]; 56 | end 57 | 58 | -------------------------------------------------------------------------------- /GaussianApproximation/IrregularLDPC.m: -------------------------------------------------------------------------------- 1 | clear 2 | max_iter = 1e3; 3 | %dv = 6; 4 | vn_degree = [1 2 3 5]; %dv - 1 5 | vn_edge_portion = [0.332 0.247 0.110 0.311]; 6 | cn_degree = [5 6]; %dc - 1 7 | cn_edge_portion = [0.766 0.234]; 8 | 9 | %dv = 11; 10 | % vn_degree = [1 2 3 10]; %dv - 1 11 | % vn_edge_portion = [0.239 0.295 0.033 0.433]; 12 | % cn_degree = [6 7]; %dc - 1 13 | % cn_edge_portion = [0.43 0.57]; 14 | 15 | %dv = 30 16 | % vn_degree = [1 2 5 6 7 8 9 27 29]; %dv - 1 17 | % vn_edge_portion = [0.196 0.24 0.002 0.055 0.166 0.041 0.011 0.002 0.287]; 18 | % cn_degree = [7 8 9]; %dc - 1 19 | % cn_edge_portion = [0.007 0.991 0.002]; 20 | 21 | Ecn = zeros(length(cn_degree), 1); 22 | Evn = zeros(length(vn_degree), 1); 23 | sigma = 0.75; 24 | sigma_inc = 1e-3; 25 | Pe = 1e-5; 26 | iter = 1; 27 | while(iter <= max_iter) 28 | if iter == 1 29 | for k = 1 : length(cn_degree) 30 | [Ecn(k), ~] = phi_inverse(1 - (1 - phi(2/sigma^2))^cn_degree(k)); 31 | end 32 | Ave_CN = cn_edge_portion * Ecn; 33 | Evn = (2/sigma^2 + vn_degree * Ave_CN)'; 34 | current_Pe = vn_edge_portion * (1 - normcdf(sqrt(Evn/2))); 35 | if current_Pe < Pe 36 | sigma = sigma + sigma_inc; 37 | iter = 1; 38 | else 39 | iter = iter + 1; 40 | end 41 | else 42 | weighted_sum = 0; 43 | for k = 1 : length(vn_degree) 44 | weighted_sum = weighted_sum + vn_edge_portion(k) * phi(Evn(k)); 45 | end 46 | tmp = 1 - weighted_sum; 47 | for k = 1 : length(cn_degree) 48 | [Ecn(k), ~] = phi_inverse(1 - tmp^cn_degree(k)); 49 | end 50 | Ave_CN = cn_edge_portion * Ecn; 51 | Evn = (2/sigma^2 + vn_degree * Ave_CN)'; 52 | current_Pe = vn_edge_portion * (1 - normcdf(sqrt(Evn/2))); 53 | if current_Pe < Pe 54 | sigma = sigma + sigma_inc; 55 | iter = 1; 56 | else 57 | iter = iter + 1; 58 | end 59 | end 60 | if iter > max_iter 61 | disp(['Gaussian Approximation is finished. The threshold sigma = ' num2str(sigma - sigma_inc)]); 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /GaussianApproximation/RegularLDPC.m: -------------------------------------------------------------------------------- 1 | max_iter = 1e3; 2 | dc = 4; 3 | dv = 3; 4 | sigma = 0.75; 5 | sigma_inc = 1e-4; 6 | Pe = 1e-6; 7 | iter = 1; 8 | while(iter <= max_iter) 9 | if iter == 1 10 | [u_cn, ~] = phi_inverse(1 - (1 - phi(2/sigma^2))^(dc - 1)); 11 | u_vn = 2/sigma^2 + (dv - 1) * u_cn; 12 | current_Pe = 1 - normcdf(sqrt(u_vn/2)); 13 | if current_Pe < Pe 14 | sigma = sigma + sigma_inc; 15 | iter = 1; 16 | else 17 | iter = iter + 1; 18 | end 19 | else 20 | [u_cn, ~] = phi_inverse(1 - (1 - phi(u_vn))^(dc - 1)); 21 | u_vn = (dv - 1) * u_cn + 2/sigma^2; 22 | current_Pe = 1 - normcdf(sqrt(u_vn/2)); 23 | if current_Pe < Pe 24 | sigma = sigma + sigma_inc; 25 | iter = 1; 26 | else 27 | iter = iter + 1; 28 | end 29 | end 30 | if iter > max_iter 31 | disp(['Gaussian Approximation is finished. The threshold sigma = ' num2str(sigma - sigma_inc)]); 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /GaussianApproximation/derivative_phi.m: -------------------------------------------------------------------------------- 1 | function dx = derivative_phi(x) 2 | if (x >= 0) && (x <= 10) 3 | dx = -0.4527 * 0.86 * x^(-0.14) * phi(x); 4 | else 5 | dx = exp(-x/4)*sqrt(pi/x)*(-1/2/x*(1 - 10/7/x) - 1/4*(1 - 10/7/x) + 10/7/x/x); 6 | end 7 | end -------------------------------------------------------------------------------- /GaussianApproximation/phi.m: -------------------------------------------------------------------------------- 1 | function y = phi(x) 2 | if (x >= 0) && (x <= 10) 3 | y = exp(-0.4527*x^0.86 + 0.0218); 4 | else 5 | y = sqrt(pi/x) * exp(-x/4) * (1 - 10/7/x); 6 | end -------------------------------------------------------------------------------- /GaussianApproximation/phi_inverse.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/GaussianApproximation/phi_inverse.m -------------------------------------------------------------------------------- /Octopus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/Octopus.png -------------------------------------------------------------------------------- /QuantDmc-4/05eng.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/QuantDmc-4/05eng.png -------------------------------------------------------------------------------- /QuantDmc-4/075eng.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/QuantDmc-4/075eng.png -------------------------------------------------------------------------------- /QuantDmc-4/LICENSE: -------------------------------------------------------------------------------- 1 | This software is subject to the MIT-like license below. This means you can 2 | do almost anything with this software, if you maintain the copyright notice. 3 | In addition, If you use this software and write and academic paper, please 4 | cite one of our publications, for example: 5 | 6 | B. M. Kurkoski and H. Yagi, "Quantization of binary-input discrete 7 | memoryless channels," IEEE Transactions on Information Theory, vol. 60, 8 | no. 8, pp. 4544-4552, August 2014. http://dx.doi.org/10.1109/TIT.2014.2327016 9 | "References" for more details 10 | 11 | Copyright (c) Brian M. Kurkoski 12 | 13 | KL-means clustering algorithm (c) Jiuyang (Alan) Zhang 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a 16 | copy of this software and associated documentation files (the "Software"), 17 | to deal in the Software without restriction, including without limitation 18 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 19 | and/or sell copies of the Software, and to permit persons to whom the 20 | Software is furnished to do so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in 23 | all copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 28 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 30 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 31 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /QuantDmc-4/README.txt: -------------------------------------------------------------------------------- 1 | QuantDMC - Matlab library for quantizing discrete memoryless channels. 2 | 3 | This software contains implementations of the algorithms for quantizing 4 | discrete memoryless channels, where mutual information is the objective 5 | function. The main library features are Matlab implementations of: 6 | 7 | * Dynamic programming algorithm, for finding optimal quantizers for 8 | binary-input DMCs [1], 9 | * KL-means algorithm, for efficiently finding good quantizers for arbitrary 10 | DMCs [2], 11 | * Greedy combining algorithm, an earlier algorithm for arbitrary DMCs, 12 | which can sometimes outperform KL-means algorithm at the expense of 13 | higher complexity [3]. 14 | 15 | If you use this software and write a paper, please cite relevant publications: 16 | 17 | [1] B. M. Kurkoski and H. Yagi, "Quantization of binary-input discrete 18 | memoryless channels," IEEE Transactions on Information Theory, vol. 60, 19 | no. 8, pp. 4544-4552, August 2014. http://dx.doi.org/10.1109/TIT.2014.2327016 20 | 21 | [2] A. Zhang and B. M. Kurkoski, "KL Means Algorithm for Quantization of 22 | Discrete Memroyless Channels," Proceedings of International Symposium on 23 | Information Theory, July 2016. 24 | 25 | [3] B. M. Kurkoski, K. Yamaguchi and K. Kobayashi, "Noise Thresholds for 26 | Discrete LDPC Decoding Mappings," Proceedings of IEEE Global 27 | Communications Conference, December 2008. 28 | 29 | This software is provided under an MIT license to supplement papers on 30 | quantization of discrete memoryless channels. See LICENSE for details. 31 | 32 | 33 | INSTALLATION 34 | 35 | Download the zip file from 36 | http://www.kurkoski.org/source 37 | 38 | To install, extract the tar file: 39 | % unzip QuantDmc-N.zip 40 | where N is the version number. 41 | 42 | In Matlab, cd to the directory and STARTUP modifies your search path: 43 | >> cd QuantDmc-N 44 | >> startup 45 | >> help quantDmc 46 | 47 | The library includes a MEX function and binaries for some platforms. 48 | If your platform is not included, compile using: 49 | >> mexify 50 | 51 | To run an example 52 | >> cd example 53 | >> biAwgnQuantization 54 | 55 | Get help: 56 | >> help quantDmc 57 | 58 | 59 | VERSION HISTORY 60 | 61 | Version 4, 2016 March 11 62 | 63 | * Added QUANTDMCKLMEANS function to implement the KL means clustering 64 | algorithm for quantizing non-binary input DMCs. 65 | * Added QUANTDMCGREEDY function to implement the greedy combining 66 | algorithm for quantizing non-binary input DMCs 67 | * Modified CHANNELSORT to accept non-normalized input, so that 68 | ChannelSort(rand(2,M)) produces a random channel. 69 | * Changed filenames. Functions have leading lowercase. Now uses 70 | "Bi" in filename to identify binary-input quantization algorithms. 71 | * Added examples using QUANTDMCKLMEANS, QUANTDMCGREEDY 72 | * Removed LDPC decoding functions. 73 | 74 | 75 | Version 3, 2012 June 21 76 | 77 | * Added functions QdeConvergence and QdeThreshold to find noise 78 | threshold for quantized messages LDPC decoder using maximization of 79 | mutual information. 80 | 81 | 82 | Version 2, 2012 May 31 83 | 84 | * Added BiAwgn2Dmc and ExBiAwgn 85 | * The mexify function is more robust to path changes 86 | * Fixed a bug that prevented compiling with Microsoft Visual C++ (use 87 | DBL_MAX/DBL_MIN from float.h instead of a fixed constant and use 88 | log(x) / log(2) instead of log2(x) ). 89 | 90 | 91 | Version 1, 2012 May 23 92 | 93 | * Initial release. Contains Matlab and C/MEX functions to find the 94 | optimal quantizer for a DMC in the sense of maximizing mutual 95 | information. 96 | 97 | -------------------------------------------------------------------------------- /QuantDmc-4/example/biAwgnQuantization.m: -------------------------------------------------------------------------------- 1 | % biAwgnQuantization - Quantizes a DMC created from a binary-input AWGN channel 2 | % 3 | % Makes a plot of how a binary-input AWGN channel is quantized to K=8 levels, 4 | % when the AWGN channel has first been finely quantized to M=30 levels. 5 | % 6 | % QuantDMC (c) Brian Kurkoski and contributors 7 | % Distributed under an MIT-like license; see the file LICENSE 8 | 9 | function biAwgnQuantization 10 | 11 | addpath('../quantDmc'); 12 | 13 | M = 30; 14 | K = 8; 15 | var = [0.1 0.35 0.6]; 16 | 17 | clf 18 | 19 | for ii = 1:length(var) 20 | %Create a fine DMC with M outputs from an AWGN channel 21 | [P,FineQuantizer,Boundary] = biAwgn2Dmc(var(ii),M); 22 | 23 | %perform quantization 24 | Q = quantBiDmcMulti(P,K); 25 | Q = Q{1}; 26 | 27 | 28 | %Make the plot 29 | % 30 | %The narrow vertical lines show the fine quantizer boundaries 31 | % 32 | %The colors indicate fine channel outputs that quantize to the same 33 | %quantizer channel output 34 | 35 | subplot(3,1,ii); 36 | hold on 37 | 38 | t = linspace(-3,3,1001); 39 | Delta = t(2) - t(1); 40 | 41 | Boundary(1) = t(1); %replace +/- Inf with real numbers 42 | Boundary(end) = t(end); 43 | for jj = 1:length(Q) 44 | x0 = Boundary(jj); 45 | x1 = Boundary(jj+1); 46 | 47 | s = linspace(x0,x1,round((x1-x0)/Delta)); 48 | patchY = [gaussmax(s,var(ii)) 0 0]; 49 | patchX = [s x1 x0]; 50 | 51 | colors = {'r' , 'g', 'm', 'b'}; 52 | quantizerNumber = find(Q(:,jj) == 1); 53 | useColor = mod(quantizerNumber,length(colors)) + 1; 54 | patch(patchX,patchY,colors{useColor}) 55 | end 56 | 57 | plot(t,gauss(t,-1,var(ii)),'k-','linewidth',2); 58 | hold on 59 | plot(t,gauss(t, 1,var(ii)),'k-','linewidth',2); 60 | ylim([0 1.4]); 61 | grid on 62 | title(sprintf('AWGN var = %g, M=%d DMC outputs, K=%d quantizer outputs',var(ii),M,K)) 63 | ylabel('Prob. distribution on AWGN output') 64 | end 65 | xlabel('AWGN channel output') 66 | 67 | 68 | function g=gauss(t,mean,var) 69 | k = 1 / (sqrt(2*pi*var) ); 70 | g = k * exp( - (t - mean) .^ 2 / (2 * var) ) ; 71 | 72 | 73 | function g=gaussmax(t,var) 74 | 75 | k = 1 / (sqrt(2*pi*var) ); 76 | mean = 1; 77 | g1 = k * exp( - (t - mean) .^ 2 / (2 * var) ) ; 78 | mean = -1; 79 | g0 = k * exp( - (t - mean) .^ 2 / (2 * var) ) ; 80 | g = max([g0 ; g1]); 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /QuantDmc-4/example/binaryDmcPerformance.m: -------------------------------------------------------------------------------- 1 | %binaryDmcPerformance - Comapres three algorithms quantizing a binary-input DMC 2 | % 3 | % This function plots the mutual information gap for three quantization 4 | % algorithms, versus number of outputs K. Data is loaded 5 | % form the file BINARYDMCPERFORMANCE.MAT. 6 | % 7 | % A DMC is constructed by fine quantization of binary-input AWGN channel. 8 | % Quantization this DMC using the following three algorithms are compared: 9 | % * quantBiDmc, Dynamic programming, optimal for binary-input channels 10 | % * quantDmcGreedy, the greedy combining algorithm 11 | % * quantDmcKLmeans, KL-means based quantization. 12 | % 13 | % Refer to the function BINARYDMCPERFORMANCEDATA contains the will geneate 14 | % BINARYDMCPERFORMANCEPLOT.MAT, but this is time consuming. 15 | % 16 | % QuantDMC (c) Brian Kurkoski and contributors 17 | % Distributed under an MIT-like license; see the file LICENSE 18 | 19 | clear all 20 | addpath('../quantDmc'); 21 | 22 | load binaryDmcPerformance 23 | 24 | figure(1); 25 | clf 26 | 27 | plot(Klist,IXZopt,'go-'); 28 | p = 6; 29 | ha = text(Klist(p),IXZopt(p),'Optimal Quantizer','Color',[0 1 0],'FontName','Arial','HorizontalAlignment','right','VerticalAlignment','top') 30 | hold on 31 | 32 | plot(Klist,IXZgreedy,'rx-'); 33 | p = 2; 34 | ha = text(Klist(p),IXZgreedy(p),'Greedy Quantizer','Color',[1 0 0],'FontName','Arial','HorizontalAlignment','left','VerticalAlignment','bottom') 35 | 36 | plot(Klist,IXZklmeans,'bs-'); 37 | p = 3; 38 | ha = text(Klist(p),IXZklmeans(p),' KL Means Quantization','Color',[0 0 1],'FontName','Arial','HorizontalAlignment','left','VerticalAlignment','bottom') 39 | 40 | xlabel('Number of Quantizer Outputs, K') 41 | ylabel('Mutual Information Gap \Delta, log scale') 42 | title(sprintf('Quantization of a Random Binary-Input DMC with %d Outputs',M)); 43 | 44 | yl = ylim; 45 | ylim([1E-3 yl(2)]); 46 | xl = xlim; 47 | set(gca,'xtick',xl(1):1:xl(2)); 48 | set(gca,'Color','none') 49 | set(gca,'FontName','Arial') 50 | set(gca,'YScale','log') 51 | grid on 52 | -------------------------------------------------------------------------------- /QuantDmc-4/example/binaryDmcPerformance.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/QuantDmc-4/example/binaryDmcPerformance.mat -------------------------------------------------------------------------------- /QuantDmc-4/example/binaryDmcPerformanceData.m: -------------------------------------------------------------------------------- 1 | %binaryDmcPerformanceData - Generates data comparing three algorithms quantizing a binary-input DMC 2 | % 3 | % Generates the data file BINARYDMCPERFORMANCE.MAT. 4 | % 5 | % See BINARYDMCPERFORMANCE for details. 6 | % 7 | % QuantDMC (c) Brian Kurkoski and contributors 8 | % Distributed under an MIT-like license; see the file LICENSE 9 | 10 | clear all 11 | addpath('../quantDmc'); 12 | 13 | M = 128; 14 | px = [0.5 0.5]; 15 | 16 | Klist = 5:10; 17 | iter = 100; 18 | 19 | Klist = 2:20; 20 | iter = 1000; 21 | 22 | for kk = 1:length(Klist) 23 | K = Klist(kk); 24 | 25 | pygx = biAwgn2Dmc(1,M); 26 | pxy = jointDistribution(pygx,px); 27 | IXY = joint2MI(pxy); 28 | [Q,IXZ1] = quantBiDmc(pygx,K); 29 | [Q,IXZ2] = quantDmcGreedy(pygx,K); 30 | 31 | IXZ3 = zeros(1,iter); 32 | for ii = 1:iter 33 | [Q,IXZ3(ii)] = quantDmcKLmeans(pygx,K); 34 | end 35 | 36 | IXZopt(kk) = IXY - IXZ1; 37 | IXZgreedy(kk) = IXY - IXZ2; 38 | IXZklmeans(kk) = IXY - mean(IXZ3); 39 | end 40 | 41 | save binaryDmcPerformance -------------------------------------------------------------------------------- /QuantDmc-4/example/multipleOptimal.m: -------------------------------------------------------------------------------- 1 | % multipleOptimal - Simple example DMC with two optimal quantizers 2 | % 3 | % Example using QUANTMIDMCMULTI, which produces multpile optimal quantizers, 4 | % if they exist, for the binary-input DMC. 5 | % 6 | % The DMC below has two optimal but distinct quantizers, it is Example 1 from: 7 | % 8 | % B. Kurkoski and H. Yagi, "Concatenation of a discrete memoryless channel 9 | % and a quantizer," in Proceedings of the IEEE Information Theory Workshop, 10 | % (Cairo, Egypt), pp. 160-164, January 2010. 11 | % 12 | % QuantDMC (c) Brian Kurkoski and contributors 13 | % Distributed under an MIT-like license; see the file LICENSE 14 | 15 | clear all 16 | addpath('../quantDmc'); 17 | 18 | P(1,:) = [0.001 0.01 0.02 0.04 0.2 0.729]; 19 | P(2,:) = [0.729 0.2 0.04 0.02 0.01 0.001]; 20 | 21 | [Q,mi] = quantBiDmcMulti(P,4); 22 | 23 | fprintf('Channel:\n'); 24 | P 25 | 26 | fprintf('This channel has %d optimal quantizers:\n',length(Q)); 27 | for ii = 1:length(Q) 28 | fprintf('Q{%d}=\n',ii); 29 | disp(Q{ii}); 30 | fprintf('with mutual information %g.\n\n',mi(ii) ); 31 | end 32 | -------------------------------------------------------------------------------- /QuantDmc-4/example/nonbinaryDmcPerformance.m: -------------------------------------------------------------------------------- 1 | %nonbinaryDmcPerformanceData - Generates data comparing two algorithms quantizing DMCs 2 | % 3 | % Plots performance comparisons of QUANTDMCKLMEANS and QUANTDMCGREEDY, 4 | % using randomly generated DMCs with J=3 and J=6 outputs. 5 | % 6 | % QuantDMC (c) Brian Kurkoski and contributors 7 | % Distributed under an MIT-like license; see the file LICENSE 8 | 9 | clear all 10 | addpath('../quantDmc'); 11 | 12 | load nonbinaryDmcPerformance 13 | 14 | for jj = 1:length(Jlist) 15 | J = Jlist(jj); 16 | px = ones(1,J)/J; 17 | for kk = 1:length(Klist) 18 | limit = mean(IXY{jj,kk}); 19 | IXZgreedy(jj,kk) = limit - mean(IXZ2{jj,kk}); 20 | IXZklmeans(jj,kk) = limit - mean(IXZ3{jj,kk}); 21 | end 22 | end 23 | 24 | figure(3); 25 | clf; 26 | hold on 27 | for jj = 1:length(Jlist) 28 | plot(Klist,IXZgreedy(jj,:),'rx-'); 29 | if jj == 1 30 | ha = addlabel(sprintf('Greedy Quantizer, J=%d',Jlist(jj)),1,38); 31 | else 32 | ha = addlabel(sprintf('J=%d',Jlist(jj)),1,33); 33 | end 34 | ha.FontName = 'Arial'; 35 | 36 | plot(Klist,IXZklmeans(jj,:),'bs-'); 37 | if jj == 1; 38 | ha = addlabel(sprintf('KL Means Quantization, J=%d',Jlist(jj)),3,30); 39 | else 40 | ha = addlabel(sprintf('J=%d',Jlist(jj)),3,33); 41 | end 42 | ha.FontName = 'Arial'; 43 | end 44 | nicecolor 45 | 46 | xlabel('Number of Quantizer Outputs, K') 47 | ylabel('Mutual Information Gap') 48 | ylabel('Mutual Information Gap \Delta, log scale') 49 | 50 | title(sprintf('quantization of a random DMC with %d outputs',M)); 51 | 52 | yl = ylim; 53 | ylim([1E-3 3E-1]) 54 | set(gca,'xtick',Klist); 55 | xlim([Klist(1)-2 Klist(end)+2]); 56 | 57 | set(gca,'Color','none') 58 | set(gca,'FontName','Arial') 59 | set(gca,'YScale','log') 60 | 61 | -------------------------------------------------------------------------------- /QuantDmc-4/example/nonbinaryDmcPerformance.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/QuantDmc-4/example/nonbinaryDmcPerformance.mat -------------------------------------------------------------------------------- /QuantDmc-4/example/nonbinaryDmcPerformanceData.m: -------------------------------------------------------------------------------- 1 | %nonbinaryDmcPerformanceData - Generates data comparing three algorithms quantizing a binary-input DMC 2 | % 3 | % See NONBINARYDMCPERFORMANCEPLOT for more details 4 | % 5 | % QuantDMC (c) Brian Kurkoski and contributors 6 | % Distributed under an MIT-like license; see the file LICENSE 7 | 8 | clear all 9 | addpath('../quantDmc'); 10 | 11 | Jlist = [3 6]; 12 | M = 512; 13 | 14 | Klist = 6:3:54; %suitable for M=128 15 | Klist = 6:4:70; %suitable for M=512 16 | iter = 50; 17 | 18 | IXY = cell( length(Jlist), length(Klist) ); 19 | IXZ2 = cell( length(Jlist), length(Klist) ); 20 | IXZ3 = cell( length(Jlist), length(Klist) ); 21 | 22 | for ii = 1:iter 23 | tic 24 | for jj = 1:length(Jlist) 25 | J = Jlist(jj) 26 | px = ones(1,J)/J; 27 | for kk = 1:length(Klist) 28 | 29 | K = Klist(kk); 30 | pygx = rand(J,M); 31 | for j = 1:J 32 | pygx(j,:) = pygx(j,:) / sum(pygx(j,:)); 33 | end 34 | 35 | [Q,IXZ2{jj,kk}(end+1)] = quantDmcGreedy(pygx,K); 36 | [Q,IXZ3{jj,kk}(end+1)] = quantDmcKLmeans(pygx,K); 37 | pxy = jointDistribution(pygx,px); 38 | IXY{jj,kk}(end+1) = joint2MI(pxy); 39 | end 40 | 41 | end 42 | toc 43 | end 44 | save nonbinaryDmcPerformance 45 | 46 | 47 | -------------------------------------------------------------------------------- /QuantDmc-4/example/verify.m: -------------------------------------------------------------------------------- 1 | % VERIFY - Compares the output of QUANTBIDMC and QUANTBIDMCMULTI 2 | % 3 | % QuantDMC contains two implementations of the quantizer for binary-input 4 | % DMCs: QUANTBIDMC is MEX-based and faster, but outputs only one optimal 5 | % quantizer. QUANTBIDMCMULTI is Matlab-based and slower, but outputs all 6 | % optimal quantizers. 7 | % 8 | % QuantDMC (c) Brian Kurkoski and contributors 9 | % Distributed under an MIT-like license; see the file LICENSE 10 | 11 | clear all 12 | addpath('../quantDmc'); 13 | 14 | ntest = 100; 15 | 16 | Mlist = [3 4 5 6 7]; 17 | Mo = min(Mlist)-1; 18 | Mo = 0; 19 | 20 | %identicalQuantizer = zeros(max(Mlist)); 21 | maxMiError = -Inf * ones(max(Mlist)-Mo,max(Mlist)-1); 22 | clf 23 | 24 | for M = Mlist 25 | lg = {'none'}; 26 | for K = 2:M-1 27 | lg{end+1} = ['K=', num2str(K)]; 28 | for ii = 1:ntest 29 | 30 | P = randomDmc(2,M); 31 | 32 | [Q1,mi1] = quantBiDmcMulti(P,K); 33 | Q1 = Q1{1}; %just select the first quantizer 34 | mi1 = mi1(1); 35 | [Q2,mi2] = quantBiDmc(P,K); 36 | 37 | if any(Q1(:) ~= Q2(:)) 38 | error('Quantizers do not match'); 39 | end 40 | 41 | maxMiError(M-Mo,K) = max( abs(mi1-mi2) , maxMiError(M-Mo,K) ); 42 | end 43 | 44 | plot(maxMiError,'o-') 45 | xlabel('DMC outputs M'); 46 | ylabel('maximum error in mutual information') 47 | legend(lg,2) 48 | xlim([min(Mlist) , max(Mlist)]) 49 | set(gca,'xtick',Mlist); 50 | drawnow; 51 | 52 | end 53 | end 54 | 55 | fprintf('All quantizers are identical (%d tests performed).\n',ntest) 56 | 57 | maxMiError 58 | -------------------------------------------------------------------------------- /QuantDmc-4/quantDmc/biAwgn2Dmc.m: -------------------------------------------------------------------------------- 1 | function [P,Quantizer,Boundary] = BiAwgn2Dmc(var,quantStep) 2 | %BIAWGN2DMC Creates a two-input DMC from a quantized AWGN channel 3 | % 4 | % P = BIAWGN2DMC(VAR,M) 5 | % 6 | % Uses AWGN noise with variance VAR (defaults to 0.4) 7 | % quantized to M levels between +2 and -2 (defaults to 20). 8 | % 9 | % P is a 2-by-M matrix, where: 10 | % P(j,m) = Pr( Y=m | X=j ) 11 | % for a DMC with inputs X and outputs Y. 12 | % 13 | % 14 | % P = BIAWGN2DMC(VAR,QUANT) 15 | % 16 | % Instead uses QUANT bin centers, where QUANT is a vector 17 | % 18 | % If VAR is a 1x2 vector then VAR(1) is used for -1 and VAR(2) 19 | % is used for +1. 20 | % 21 | % [P,QUANTIZER,BOUNDARY] = BIAWGN2DMC 22 | % QUANTIZER is the 1-by-M vector used for the quantizer bin centers 23 | % BOUNDARY is the 1-by-M+1 vector used for the quantizer bin edges 24 | % 25 | % 26 | % QuantDMC is (c) 2010-2012 Brian Kurkoski 27 | % Distributed under an MIT-like license; see the file LICENSE 28 | % 29 | 30 | input = [-1 1]; 31 | 32 | if nargin < 1 33 | var = 0.4; 34 | end 35 | 36 | if nargin < 2 37 | quantStep = 20; 38 | end 39 | 40 | if length(quantStep) == 1 41 | Quantizer = linspace(-2,2,quantStep); 42 | else 43 | Quantizer = sort(quantStep(:)'); 44 | end 45 | 46 | if length(var) == 1 47 | var = [var var]; 48 | end 49 | 50 | Boundary = (Quantizer(1:end-1) + Quantizer(2:end))/2; 51 | Boundary = [-Inf Boundary Inf]; 52 | 53 | for ii = 1:2 54 | for jj = 1:length(Boundary)-1; 55 | t = Qf( (Boundary(jj) - input(ii) ) / sqrt(var(ii)) ) ... 56 | - Qf( (Boundary(jj+1) - input(ii) ) / sqrt(var(ii)) ); 57 | P(ii,jj) = t; 58 | end 59 | end 60 | 61 | 62 | %Gaussian Q function 63 | function out = Qf(x) 64 | 65 | out = 0.5 .* erfc(x ./ sqrt(2) ); 66 | -------------------------------------------------------------------------------- /QuantDmc-4/quantDmc/channelSort.m: -------------------------------------------------------------------------------- 1 | function Pout = channelSort(Pin) 2 | %channelSort - Sort the outputs of a binary-input DMC. 3 | % 4 | % With DMC PIN, where rows sum to 1, POUT = CHANNELSORT(PIN) 5 | % gives the sorted channel. 6 | % 7 | % PIN is a DMC conditional distribution, and POUT is sorted to 8 | % satisfy the condition: 9 | % 10 | % Pr(Y=1|X=1) Pr(Y=2|X=1) Pr(Y=M|X=1) 11 | % ------------- < ------------- < ... < ------------- 12 | % Pr(Y=1|X=2) Pr(Y=2|X=2) Pr(Y=M|X=2) 13 | % 14 | % which corresponds to 15 | % 16 | % POUT(1,1) / POUT(2,1) < POUT(1,2) / POUT(2,2) < ... < POUT(1,M) / POUT(2,M) 17 | % 18 | % for a 2-by-M matrix PIN, POUT. 19 | % 20 | % Additionally, POUT is normalized so each row sums to one. A random 21 | % channel can be generated by: 22 | % 23 | % CHANNELSORT(RAND(2,M)) 24 | % 25 | % QuantDMC (c) Brian Kurkoski and contributors 26 | % Distributed under an MIT-like license; see the file LICENSE 27 | 28 | [J M] = size(Pin); 29 | assert(J==2,'Pin must have two rows') 30 | 31 | Pin(1,:) = Pin(1,:) / sum(Pin(1,:)); 32 | Pin(2,:) = Pin(2,:) / sum(Pin(2,:)); 33 | 34 | [~,ind] = sort( Pin(1,:) ./ Pin(2,:) ); 35 | Pout = Pin(:,ind); 36 | -------------------------------------------------------------------------------- /QuantDmc-4/quantDmc/clib/mmatrix.h: -------------------------------------------------------------------------------- 1 | 2 | /* MWORD is set to be a double */ 3 | #define MMAXFLOAT DBL_MAX /* previously used this const: 3.40282347E+38F */ 4 | #define MMINFLOAT DBL_MIN /* 1.17549435E-38F */ 5 | typedef double MWORD; 6 | 7 | #define EPS 2.7105053E-19F /*guardband by 1E+1*/ 8 | 9 | #define MEX 1 10 | 11 | #if MEX==1 12 | #include "mex.h" 13 | #endif 14 | 15 | #define VARNAMELEN 30 /*maximum length for variable names*/ 16 | 17 | 18 | typedef struct { 19 | int nr; /* number of rows */ 20 | int nc; /* number of colums */ 21 | MWORD **elt; /* pointer to rows */ 22 | MWORD *cols; /* pointer to contents of matrix */ 23 | char name[VARNAMELEN+1]; 24 | int type; /* 0 for MWORDs, 1 for MWORD interpretted as strings */ 25 | int init; /* 0 if rows/contents not yet malloc'd, 1 otherwise */ 26 | } MATRIX; 27 | 28 | /************************************************ 29 | Initialize a matrix. Unless a matrix in input from matlab, 30 | the declaration should look like this: 31 | MATRIX *x = matrix("x",0,0); //for outputs 32 | MATRIX *x = matrix("x",nr,nc); //for inputs 33 | x->elt[col][row] = 10; 34 | 35 | matrix_free(x); 36 | 37 | An alternate usage is: 38 | MATRIX dd = {1000,1,NULL,NULL,"d",0}; 39 | MATRIX *d = ⅆ 40 | 41 | An exception is when the matrix is an input from Matlab. 42 | The function matlab_to_matrix() invokes the 43 | function matrix(): 44 | 45 | MATRIX *a; 46 | 47 | a = matlab_to_matrix(prhs[0]); 48 | 49 | *************************************************/ 50 | 51 | /************************************************ 52 | *matrix() as a minimum returns a pointer to a that 53 | has MATRIX malloc'd is named. If nc and nc are both 54 | positive, then space for the matrix contents will 55 | be malloc'd and initialized to zero 56 | 57 | matrix_init_ptr() takes a matrix that has already 58 | been MATRIX malloc'd (by *matrix("",0,0)) and will then 59 | malloc the contents and initialize them to zero. 60 | 61 | *matrix() is called when the matrix is first 62 | initialized, and matrix_init_ptr() is called from 63 | within functions that must produce a matrix as 64 | an output. 65 | 66 | *matrix can be invoked to initialize data in the following manner: 67 | MATRIX *data=matrix("*i data",4,1, 1,1,0,1); OR 68 | MATRIX *data=matrix("*m data",4,1, 1.0,1.0,0,1.0); 69 | where the true "name" begins with the third character if 70 | the given name begins with "*i " for integers or "*m " for 71 | MWORDs. 72 | *************************************************/ 73 | 74 | /*MATRIX *matrix(char *name,int nr,int nc);*/ 75 | MATRIX *matrix(char *name,int nr,int nc,...); 76 | void matrix_init_ptr(MATRIX *m, int nr,int nc); 77 | void matrix_free(MATRIX *m); 78 | void matrix_null(MATRIX *m); 79 | 80 | /************************************************ 81 | returns 1 if matrix has been initialized, 82 | 0 otherwise. 83 | *************************************************/ 84 | int matrix_isinit(MATRIX *m); 85 | 86 | /************************************************ 87 | Resize an existing matrix. Assumes that *m points 88 | to a MATRIX, and that MATRIX has a m->name. 89 | 90 | If *m has same size as requested size, then the funciton 91 | does nothing. If not, then memory of the matrix, if 92 | initialized, is freed. And then *m is initialized 93 | to requested size. 94 | *************************************************/ 95 | void matrix_resize(MATRIX *m,int nr,int nc); 96 | 97 | /************************************************ 98 | Map a subset of elements from the input matrix to 99 | the output matrix. Similar to matlab: 100 | out = in(r1:r2,c1:c2); 101 | *************************************************/ 102 | void matrix_reindex(MATRIX *out,MATRIX *in,int c1,int c2,int r1,int r2); 103 | 104 | /************************************************ 105 | Repmat command. Similar to out = repmat(in,m,n) 106 | *************************************************/ 107 | void matrix_repmat(MATRIX *out,MATRIX *in,int m,int n); 108 | 109 | /************************************************ 110 | Length of matrix. Returns an int = max(in->nc,in->nr) 111 | *************************************************/ 112 | int matrix_length(MATRIX *in); 113 | 114 | /************************************************ 115 | Sum of all elements in matrix. 116 | *************************************************/ 117 | MWORD matrix_sumsum(MATRIX *in); 118 | 119 | /************************************************ 120 | Sum,max min of elements in matrix in one dimension 121 | *************************************************/ 122 | void matrix_sum(MATRIX *out,MATRIX *in1,int dim); 123 | void matrix_max(MATRIX *out,MATRIX *in1,int dim); 124 | void matrix_min(MATRIX *out,MATRIX *in1,int dim); 125 | 126 | /************************************************ 127 | returns a one if all elements of two matrices 128 | are equal, zero otherwise 129 | *************************************************/ 130 | int matrix_equal(MATRIX *in1,MATRIX *in2); 131 | 132 | /************************************************ 133 | Copy a matrix from src to dest. 134 | *************************************************/ 135 | void matrix_copy(MATRIX *dest,MATRIX *src); 136 | 137 | /************************************************ 138 | Sort entries of a matrix in ascending order. 139 | Each row is sorted independently. 140 | *************************************************/ 141 | void matrix_sort(MATRIX *m,MATRIX *in); 142 | 143 | /************************************************ 144 | Add two matrices. *in1 and *in2 must be the 145 | same size. 146 | *************************************************/ 147 | void matrix_add(MATRIX *out,MATRIX *in1,MATRIX *in2); 148 | 149 | 150 | /************************************************ 151 | Perform a function like matlab 152 | OUT = (IN < IN2) 153 | 154 | If IN2 is a matrix of the same size as IN, then: 155 | "<" may be any of "<",">","<=",">=","==" 156 | 157 | If IN2 is an MWORD, then prefix the operator with "s": 158 | any of "s<","s>","s<=","s>=","s==" 159 | "s" is for scalar 160 | *************************************************/ 161 | void matrix_op(MATRIX *out,MATRIX *in1,char *cs, ...); 162 | 163 | 164 | /************************************************ 165 | Convert a matrix entires to integer. OP should be: 166 | "fix" 167 | *************************************************/ 168 | void matrix_int(char *op,MATRIX *in,MATRIX *out); 169 | 170 | 171 | /************************************************ 172 | Convert a matrix entires to integer. OP may be one of: 173 | "floor" 174 | *************************************************/ 175 | void matrix_labsort(MATRIX *ilab, MATRIX *lab); 176 | 177 | /*usage: MATRIX m; matrix_name(&m,"mymat");*/ 178 | void matrix_name(MATRIX *m, char *name); 179 | 180 | 181 | /************************************************ 182 | Set all entries of an existing matrix to 183 | a single value f. 184 | *************************************************/ 185 | void matrix_clear(MATRIX *m,MWORD f); 186 | 187 | /************************************************ 188 | Finds the *row and *col of the first value that 189 | tests equal to f in matrix *m. Starts at entry 0,0. 190 | Scans proceeds across increasing columns, 191 | then increasing rows. Returns *row,*col=-1 if no 192 | match is found. 193 | 194 | Skips entires that are NaN. 195 | *************************************************/ 196 | void matrix_find_equal_rc(MATRIX *m, MWORD f, int *row, int *col); 197 | 198 | void matrix_write_quick(FILE *fp,MATRIX *m); 199 | void matrix_disp(MATRIX *m); 200 | void matrix_copy(MATRIX *dest,MATRIX *src); 201 | MWORD matrix_find_min(MATRIX *m,MATRIX *out); 202 | MWORD matrix_minmin(MATRIX *m,MWORD *f); 203 | void matrix_clear_index(MATRIX *m,MWORD f,MATRIX *index); 204 | 205 | 206 | 207 | 208 | #define NTAB 32 209 | typedef struct 210 | { 211 | long idum2; 212 | long iy; 213 | long iv[NTAB]; 214 | long idum; 215 | int iset; /* required for gasdevs */ 216 | float gset; /* required for gasdevs */ 217 | } RANDSTATE; 218 | #undef NTAB 219 | 220 | /************************************************ 221 | Generates a matrix with random numbers between 0 and 1. 222 | Typical use: 223 | MATRIX *x; 224 | RANDSTATE *rs; 225 | x = matrix(1,1000,"x"); 226 | rs = randstate_init(0); 227 | matrix_rand(m,rs); 228 | Or, 229 | matrix_randq(m); 230 | "q" suffix funciton names are "quick" that use an internal 231 | seed of -1. 232 | 233 | randstate_init() performs a malloc for the returned 234 | RANDSTATE, which should ulitmately be free'd. 235 | *************************************************/ 236 | RANDSTATE *randstate_init(long seed); 237 | void matrix_rand(MATRIX *m,RANDSTATE *rs); 238 | void matrix_randn(MATRIX *m,RANDSTATE *rs); 239 | 240 | void matrix_randq(MATRIX *m); 241 | void matrix_randnq(MATRIX *m); 242 | 243 | 244 | /************************************************ 245 | Displays an error message and forces an exit with 246 | return code 1 (if MEX==0) or uses a mex error message 247 | function (if MEX==1). Example: 248 | 249 | error("matrix_add:must have same number of columns"); 250 | *************************************************/ 251 | void error(char *message); 252 | 253 | 254 | /* 255 | MWORD es; 256 | es = findeps(); 257 | fprintf(stdout,"EPS=%E\n",es); 258 | */ 259 | MWORD findeps(); 260 | 261 | /*NaNf makes *x into NaN (floats only)*/ 262 | void NaNf (float *x); 263 | void NaNd (double *x); 264 | 265 | /*returns 1 if x is NaN, 0 otherwise (floats only)*/ 266 | int IsNaNf (float x); 267 | int IsNaNd (double x); 268 | 269 | #if MEX==1 270 | MATRIX *matlab_to_matrix(const mxArray *matlab); 271 | void matrix_to_matlab_old(MATRIX *m,mxArray **matlab); 272 | mxArray *matrix_to_matlab(MATRIX *m); 273 | #endif 274 | 275 | 276 | /* 277 | Philosophy. This is how I decided to initialize matrices: 278 | MATRIX *x; 279 | x = matrix(); 280 | ... 281 | matrix_add(x,a,b); 282 | 283 | If I had done this instead: 284 | 285 | MATRIX *x; 286 | ... 287 | x = matrix_add(a,b); 288 | 289 | Then x=matrix(); isn't necessary. But, it isn't well 290 | suited for repetitive processing, because the output 291 | is returned, it must be malloc'd every time--I cannot 292 | reuse already malloc'd matrices. 293 | 294 | I could also do this: 295 | MATRIX *x; 296 | x = matrix_init(3,1000,"x"); 297 | ... 298 | matrix_add(x,a,b); 299 | which is OK, but that means I have to keep track of the 300 | size of outputs, which is a little bit tedius--why not 301 | have the program do it for me?? 302 | 303 | Some problems might be mitigated by using &x, but I 304 | want to stay away from pointers to pointers. Yuck! 305 | */ 306 | -------------------------------------------------------------------------------- /QuantDmc-4/quantDmc/clib/quantBiDmc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mmatrix.h" 4 | #include "mex.h" 5 | 6 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 7 | { 8 | MATRIX *P; /*input 0*/ 9 | MATRIX *Kin; /*input 1*/ 10 | MATRIX *S = matrix("S",0,0); 11 | MATRIX *h = matrix("h",0,0); 12 | MATRIX *astar = matrix("astar",0,0); 13 | MATRIX *Qstar = matrix("Qstar",0,0); 14 | MATRIX *g = matrix("g",0,0); 15 | MATRIX *mi = matrix("mi",1,1); 16 | int J,I,K; 17 | MWORD log2b = (1.0 / log(2)); 18 | 19 | double P_ij0,P_ij1,t; 20 | int ii,jj,k,ap,a; 21 | 22 | 23 | if (nrhs != 2) 24 | mexErrMsgTxt("Incorrect number of input args."); 25 | 26 | 27 | P = matlab_to_matrix(prhs[0]); 28 | Kin = matlab_to_matrix(prhs[1]); 29 | J = P->nr; 30 | I = P->nc; 31 | K = (int) Kin->elt[0][0]; 32 | 33 | if (K >= I) { 34 | Qstar = matrix("Qstar",I,I); 35 | for (ii=0;iielt[ii][ii] = 1; 37 | } 38 | plhs[0]= matrix_to_matlab(Qstar); 39 | matrix_free(g); 40 | matrix_free(Qstar); 41 | matrix_free(astar); 42 | matrix_free(h); 43 | matrix_free(S); 44 | matrix_free(Kin); 45 | matrix_free(P); 46 | } 47 | 48 | 49 | /* 50 | for loops start at index 1, like Matlab. 51 | but subtract 1 when accessing arrays 52 | */ 53 | g = matrix("g",I,I); 54 | for (ap=1;ap<=I;ap++) { 55 | P_ij0 = 0; 56 | P_ij1 = 0; 57 | for (a=ap;a<=I;a++) { 58 | P_ij0 = P_ij0 + P->elt[a-1][0]; 59 | P_ij1 = P_ij1 + P->elt[a-1][1]; 60 | t = P_ij0 + P_ij1; 61 | g->elt[a-1][ap-1] = 0.5 * (P_ij0 * log2b * log(2.0 * P_ij0 / t) + P_ij1 * log2b * log(2.0 * P_ij1 / t)) + 1E-15; 62 | } 63 | } 64 | 65 | S = matrix("S",I,K); 66 | h = matrix("h",I,K); 67 | 68 | for (a=1;a<=1+I-K;a++) { 69 | S->elt[0][a-1] = g->elt[a-1][0]; 70 | } 71 | 72 | for (k=2;k<=K;k++) { 73 | for (a=k;a<=k+I-K;a++) { 74 | S->elt[k-1][a-1] = -10000.0; 75 | for (ap=k-1;ap<=a-1;ap++) { 76 | t = S->elt[k-2][ap-1] + g->elt[a-1][ap]; 77 | if (t > S->elt[k-1][a-1]) { 78 | S->elt[k-1][a-1] = t; 79 | h->elt[k-1][a-1] = ap; 80 | } 81 | } 82 | } 83 | } 84 | 85 | astar = matrix("astar",1,K+1); 86 | astar->elt[K][0] = I; 87 | for (k = K-1;k>=1;k--) { 88 | astar->elt[k][0] = h->elt[k][(int) astar->elt[k+1][0] - 1 ]; 89 | } 90 | 91 | Qstar = matrix("Qstar",K,I); 92 | for (k=1;k<=K;k++) { 93 | for (a = astar->elt[k-1][0]+1 ; a <= astar->elt[k][0] ; a++ ) { 94 | Qstar->elt[a-1][k-1] = 1; 95 | } 96 | } 97 | 98 | mi->elt[0][0] = S->elt[K-1][I-1]; 99 | plhs[0]= matrix_to_matlab(Qstar); 100 | plhs[1]= matrix_to_matlab(mi); 101 | 102 | matrix_free(mi); 103 | matrix_free(g); 104 | matrix_free(Qstar); 105 | matrix_free(astar); 106 | matrix_free(h); 107 | matrix_free(S); 108 | matrix_free(Kin); 109 | matrix_free(P); 110 | 111 | return; 112 | } 113 | 114 | -------------------------------------------------------------------------------- /QuantDmc-4/quantDmc/contents.m: -------------------------------------------------------------------------------- 1 | %QuantDMC - Matlab library for quantizing discrete memoryless channels. 2 | %Version 4 3 | % 4 | % Quantizing discrete memoryless channels (DMCs) to maximize mutual 5 | % information: 6 | % quantBiDmc - Gives one optimal quantizer of a binary-input DMC. 7 | % MEX implementation. 8 | % quantBiDmcMulti - Gives all optimal quantizers of a binary-input DMC. 9 | % quantDmcKLmeans - KL-means quantization of a DMC. 10 | % quantDmcGreedy - Greedy combining quantization of a DMC. 11 | % 12 | % For binary-input channels QUANTBIDMC should be used, if only one optimal 13 | % quantzer is needed. Otherwise, use QUANTBIDMCMULTI, which is slower. 14 | % For non-binary input channels, QUANTDMCKLMEANS runs faster than 15 | % QUANTDMCGREEDY. When the number of quantizer outputs K is small, 16 | % QUANTKLMEANS also has better peformance. 17 | % 18 | % Additional functions: 19 | % biAwgn2Dmc - create a DMC by quantizing an AWGN channel 20 | % randomDMC - genreates a random DMC 21 | % joint2MI - Compute mutual information 22 | % jointDistribution - compute joint distribution from P(Y|X) and P(X) 23 | % channelSort - Sort the outputs of a binary-input DMC. 24 | % mexify - compile QUANTBIDMC MEX function from C. QuantDMC 25 | % includes MEX files for some platforms, so is 26 | % required only if you are using another platform. 27 | % 28 | % Examples are in the example/ directory. 29 | % 30 | % QuantDMC (c) Brian Kurkoski and contributors 31 | % Distributed under an MIT-like license; see the file LICENSE 32 | 33 | -------------------------------------------------------------------------------- /QuantDmc-4/quantDmc/joint2MI.m: -------------------------------------------------------------------------------- 1 | function [I] = joint2MI(P) 2 | %joint2MI - Compute mutual information 3 | % 4 | % P is a joint distribution between X and Y, then 5 | % JOINT2MI(P) gives the mutual information I(X;Y). 6 | % 7 | % QuantDMC (c) Brian Kurkoski and contributors 8 | % Distributed under an MIT-like license; see the file LICENSE 9 | 10 | P(find(P==0)) = 1000*eps; 11 | 12 | py = sum(P,1); 13 | py = py / sum(py); 14 | pya = repmat(py,size(P,1),1); 15 | 16 | px = sum(P,2); 17 | px = px / sum(px); 18 | pxa = repmat(px,1,size(P,2)); 19 | 20 | pxy = P/sum(sum(P)); 21 | 22 | I = sum(sum( pxy .* log2( pxy ./ (pxa .* pya) ) ) ); 23 | 24 | return 25 | 26 | 27 | %testing 28 | 29 | %p. 189-190 of Cover and Thomas 30 | m = [0.3 0.2 0.5; 0.5 0.3 0.2; 0.2 0.5 0.3]; 31 | %following should be equal to 0: 32 | joint2MI(m) - ( log2(3) - H([0.5 0.3 0.2])) 33 | -------------------------------------------------------------------------------- /QuantDmc-4/quantDmc/jointDistribution.m: -------------------------------------------------------------------------------- 1 | function pxy = jointDistribution(pygx,px) 2 | %jointDistribution - compute joint distribution from P(Y|X) and P(X) 3 | % 4 | % If PYGX is a conditional probability distribution with rows summing to 5 | % 1, and PX is a vector, then JOINTDISTRIBUTION(PYGX,PX) is the joint 6 | % distribution P(X,Y). 7 | % 8 | % QuantDMC (c) Brian Kurkoski and contributors 9 | % Distributed under an MIT-like license; see the file LICENSE 10 | 11 | pxy = repmat(px(:),1,size(pygx,2)) .* pygx; -------------------------------------------------------------------------------- /QuantDmc-4/quantDmc/mexify.m: -------------------------------------------------------------------------------- 1 | %compiles the C functions to MEX 2 | 3 | currentPath = pwd; 4 | 5 | aFile = 'quantBiDmcMulti.m'; 6 | newPath = which(aFile); 7 | if length(newPath) == 0 8 | error(sprintf('Could not find %s in the search path\nAdd QuantDmc to the search path',upper(aFile))); 9 | end 10 | newPath = strrep(newPath,aFile,''); 11 | cd(newPath) 12 | 13 | fprintf('Compiling....') 14 | 15 | try 16 | mex -v clib/quantBiDmc.c clib/mmatrix.c 17 | fprintf('success\n'); 18 | cd(currentPath) 19 | catch 20 | fprintf('Error, failed to compile\n'); 21 | cd(currentPath) 22 | end -------------------------------------------------------------------------------- /QuantDmc-4/quantDmc/quantBiDmc.m: -------------------------------------------------------------------------------- 1 | % [Q,MI] = QuantBiDmc(P,K) 2 | % 3 | % Finds the optimal quantizer of DMC given by P, quantized to K values, 4 | % in the sense of maximizing mutual information. 5 | % P is a 2-by-M matrix, where: 6 | % P(j,m) = Pr( Y=m | X=j ), 7 | % for a DMC with inputs X and outputs Y. K is an integer, generally less 8 | % than M. 9 | % 10 | % Q is one of the optimal quantizers. Q(m,k) is a 1 if DMC output m is quantized 11 | % to k, and otherwise is a 0. 12 | % 13 | % MI is the mutual information between the channel input and the quantizer 14 | % output. 15 | % 16 | % QuantDMC is (c) 2010-2012 Brian Kurkoski 17 | % Distributed under an MIT-like license; see the file LICENSE 18 | % 19 | 20 | error('Run the command MEXIFY to compile QUANTMIDMC before using it'); -------------------------------------------------------------------------------- /QuantDmc-4/quantDmc/quantBiDmc.mexa64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/QuantDmc-4/quantDmc/quantBiDmc.mexa64 -------------------------------------------------------------------------------- /QuantDmc-4/quantDmc/quantBiDmc.mexmaci64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/QuantDmc-4/quantDmc/quantBiDmc.mexmaci64 -------------------------------------------------------------------------------- /QuantDmc-4/quantDmc/quantBiDmc.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/QuantDmc-4/quantDmc/quantBiDmc.mexw64 -------------------------------------------------------------------------------- /QuantDmc-4/quantDmc/quantBiDmcMulti.m: -------------------------------------------------------------------------------- 1 | function [Qout,mi] = quantBiDmcMulti(Pin,K) 2 | % [Q,MI] = quantBiDmcMulti(P,K) 3 | % 4 | % Finds the optimal quantizer of DMC given by P, quantized to K values, 5 | % in the sense of maximizing mutual information. 6 | % P is a 2-by-M matrix, where: 7 | % P(j,m) = Pr( Y=m | X=j ), 8 | % for a DMC with inputs X and outputs Y. K is an integer, generally less 9 | % than M. 10 | % 11 | % Q is a cell array containing M-by-K matrices, each one is an optimal quantizer. 12 | % For each matrix Q{i}, Q{i}(m,k) is a 1 if DMC output m is quantized 13 | % to k, and otherwise is a 0. 14 | % 15 | % MI is the mutual information between the channel input and the quantizer 16 | % output, which is the same for all optimal quantizers. 17 | % 18 | % QuantDMC (c) Brian Kurkoski and contributors 19 | % Distributed under an MIT-like license; see the file LICENSE 20 | % 21 | 22 | J = size(Pin,1); 23 | I = size(Pin,2); 24 | if J ~= 2 25 | error('This only works with binary matrices'); 26 | end 27 | 28 | if K >= I 29 | T = Pin; 30 | mi = NaN; 31 | Qout = {eye(size(Pin,2))}; 32 | return 33 | end 34 | 35 | %Input Pin is conditional, but this function assumes Pin is joint. 36 | Pin = Pin / 2; 37 | 38 | %Pin is joint, construct Pcond to sort. 39 | Pcond = Pin ./ repmat( sum(Pin,2),1,I); 40 | LLR = log( Pcond(1,:) ./ Pcond(2,:) ); 41 | [t,sortorder] = sort(LLR); 42 | 43 | %Sorted P is used from now on 44 | P = Pin(:,sortorder); 45 | 46 | 47 | 48 | %initial distance computation 49 | dist = zeros(I,I); 50 | pj = sum(P,2); 51 | for ii = 1:I 52 | for kk = ii:I 53 | t = sum(P(:,ii:kk),2); 54 | s = sum(t); 55 | %if s > 1; s =1; end 56 | dist(ii,kk) = sum( (t .* log2(t ./ (s * pj) ) ) +eps ); 57 | end 58 | end 59 | 60 | SM = zeros(I,K); 61 | ps = cell(I,K); 62 | SM(:,1) = dist(1,:); 63 | fl = 0; 64 | for kk = 2:K 65 | for ii = kk:I 66 | t = zeros(size([kk-1:ii-1]) ); 67 | for ell = kk-1:ii-1 68 | t(ell - (kk-2) ) = SM(ell,kk-1) + dist(ell+1,ii) ; 69 | end 70 | [SM(ii,kk),ps{ii,kk}] = max(t); 71 | %ps(ii,kk) = ps(ii,kk) + kk - 2; 72 | ps{ii,kk} = find(t == max(t)); 73 | ps{ii,kk} = ps{ii,kk} + kk - 2; 74 | %if length(ps{ii,kk}) > 1 75 | % fl = 1; 76 | %end 77 | end 78 | end 79 | 80 | %build quantizer list 81 | Q = [I]; 82 | for kk = K:-1:1 83 | Qnew = []; 84 | for ii = 1:size(Q,1) 85 | s = Q(ii,K-kk+1); 86 | t = ps{s,kk}; 87 | if length(t) == 0; 88 | t = 0; 89 | end 90 | if length(t) == 1 91 | Q(ii,K-kk+2) = t; 92 | else 93 | Q(ii,K-kk+2) = t(1); 94 | Qt = repmat(Q(ii,1:K-kk+1),length(t)-1,1); 95 | tp = t(:); 96 | Qt = [Qt tp(2:end)]; 97 | Qnew = [Qnew; Qt]; 98 | end 99 | end 100 | Q = [Q; Qnew]; 101 | end 102 | 103 | %build the quantizer from the quantizer list 104 | Qlist = Q; 105 | Q={}; 106 | for ii = 1:size(Qlist,1) 107 | Q{ii} = zeros(K,I); 108 | for kk = 1:K 109 | Q{ii}(K-kk+1, Qlist(ii,kk+1)+1:Qlist(ii,kk)) = 1; 110 | end 111 | end 112 | 113 | %compute mutual information associated with each quantier. 114 | for ii = 1:length(Q) 115 | T = P * Q{ii}' ; 116 | p=sum(T,2); 117 | q=sum(T,1); 118 | mi(ii)=0; 119 | for kk = 1:K 120 | for jj = 1:J 121 | mi(ii) = mi(ii) + T(jj,kk) * log2( T(jj,kk) / (q(kk) * p(jj))) ; 122 | end; 123 | end 124 | end 125 | %disp([ SM(I,K) mi]) 126 | 127 | %reverse the sort order to agree with Pin input 128 | for ii = 1:length(Q); 129 | Q{ii}(:,sortorder) = Q{ii}; 130 | end 131 | 132 | Qout = Q; 133 | 134 | return 135 | -------------------------------------------------------------------------------- /QuantDmc-4/quantDmc/quantDmcGreedy.m: -------------------------------------------------------------------------------- 1 | function [Q,IXZ] = QuantMiDmcGreedy(pygx,K,px) 2 | %greedyCombining Greedy combining quantization of a discrete memoryless channel. 3 | % [Q,IXZ] = GREEDYCOMBINING(PYGX,PX,K) Quantizes a discrete memoryless channel 4 | % (DMC) PYGX with input distribution PX to K levels. PYGX has J rows and M 5 | % columns where the columns sum to one. If K is greater than the number 6 | % of columns M, then no quantization is performed. 7 | % 8 | % Q is an M-by-K quantization matrix such that the conditional distribution 9 | % on the quantizer output Z Pr(Z=z|X=x) = Pr(Y=x|X=x) * Q(y,z) is given by 10 | % PZGX = PYGX * Q 11 | % 12 | % IXZ is the mutual information I(X;Z). 13 | % 14 | % Brian Kurkoski 15 | % Distributed under an MIT-like license; see the file LICENSE 16 | % 17 | 18 | if nargin < 2 19 | error('two input arguments are required'); 20 | end 21 | 22 | [J M] = size(pygx); 23 | 24 | if nargin < 3 25 | px = ones(1,J)/J; 26 | end 27 | 28 | pxy = repmat(px(:),1,M) .* pygx; 29 | 30 | py = sum(pxy,1); 31 | px = sum(pxy,2); 32 | 33 | iself = zeros(1,M); 34 | for yy = 1:M 35 | iself(yy) = sum( pxy(:,yy) .* log2( pxy(:,yy) ./ (px(:)*py(yy)) ) ); 36 | end 37 | 38 | 39 | 40 | %Initial distance computation 41 | dist = ones(M,M)*Inf; 42 | for ii = 1:M-1 43 | for jj = ii+1:M 44 | t = sum((pxy(:,ii) + pxy(:,jj)) .* log2( (pxy(:,ii)+pxy(:,jj)) ./ (px(:)*(py(ii) + py(jj))) ) ); 45 | dist(ii,jj) = iself(ii) + iself(jj) - t; 46 | %dist(ii,jj) = t; 47 | end 48 | end 49 | 50 | Q = eye(M); 51 | 52 | %BEGIN LOOP 53 | while(M > K) 54 | [imin,jmin] = find(dist == min(min(dist)),1); 55 | 56 | %combining (jmin will be deleted) 57 | pxy(:,imin) = pxy(:,imin) + pxy(:,jmin); 58 | 59 | %update distances 60 | py(imin) = sum(pxy(:,imin)); 61 | iself(imin) = sum( pxy(:,imin) .* log2( pxy(:,imin) ./ (px(:)*py(imin)) ) ); 62 | 63 | %update distances in row imin 64 | for j = imin+1:length(dist) 65 | t = sum( (pxy(:,imin) + pxy(:,j)) .* log2( (pxy(:,imin)+pxy(:,j)) ./ (px(:)*(py(imin) + py(j))) ) ); 66 | dist(imin,j) = iself(imin) + iself(j) - t; 67 | end 68 | 69 | %update distance in column imin 70 | for i = 1:imin-1 71 | t = sum( (pxy(:,i) + pxy(:,imin)) .* log2( (pxy(:,i)+pxy(:,imin)) ./ (px(:)*(py(i) + py(imin))) ) ); 72 | dist(i,imin) = iself(i) + iself(imin) - t; 73 | end 74 | 75 | %build the quantizer 76 | Qthis = eye(M-1); 77 | c = Qthis(:,imin); 78 | Qthis = [ Qthis(:,1:jmin-1) , c , Qthis(:,jmin:end) ]; 79 | Q = Qthis * Q; 80 | 81 | %delete the merged term 82 | r = [1:jmin-1 jmin+1:length(dist)]; 83 | pxy = pxy(:,r); 84 | py = py(r); 85 | iself = iself(r); 86 | dist = dist(r,:); 87 | dist = dist(:,r); 88 | 89 | [J,M] = size(pxy); 90 | end 91 | 92 | Q = Q'; 93 | 94 | pzgx = pygx*Q; 95 | pxz = repmat(px(:),1,M) .* pzgx; 96 | pz = sum(pxz,1); 97 | IXZ = sum(sum( pxz .* log2(pxz ./ (px * pz) ))); 98 | 99 | return 100 | -------------------------------------------------------------------------------- /QuantDmc-4/quantDmc/quantDmcKLmeans.m: -------------------------------------------------------------------------------- 1 | function [Q,IXZ,means,clusters,clusterHistory] = QuantMiDmcKLmeans(pygx,K,px) 2 | %klmeans KL means clustering quantization of a discrete memoryless channel. 3 | % 4 | % Q is an M-by-K quantization matrix such that the conditional distribution 5 | % on the quantizer output Z Pr(Z=z|X=x) = Pr(Y=x|X=x) * Q(y,z) is given by 6 | % PZGX = PYGX * Q 7 | % 8 | % IXZ is the mutual information I(X;Z). 9 | % 10 | % If empty clusters are found, then columns are removed from Q, and 11 | % Q may have fewer than K columns. 12 | % 13 | % Alan Zhang and Brian Kurkoski 14 | % Distributed under an MIT-like license; see the file LICENSE 15 | % 16 | 17 | if nargin < 2 18 | error('two input arguments are required'); 19 | end 20 | 21 | maxItr = 100; % maximum number of iteration 22 | 23 | if nargout > 3 24 | trackHistory = true; 25 | else 26 | trackHistory = false; 27 | end 28 | 29 | % Calculate Pr(X|Y) 30 | J = size(pygx,1); % number of inputs 31 | M = size(pygx,2); % number of outputs 32 | if nargin < 3 33 | px = ones(1,J) / J; %default is uniform input distribution 34 | end 35 | pxy = repmat(px(:),1,M) .* pygx; 36 | py = sum(pxy,1); 37 | pxgy = pxy' ./ repmat(py(:)',J,1)'; 38 | 39 | % Random mean initialization 40 | sample = randperm(M); 41 | means = zeros(K,J); 42 | for i = 1:K 43 | means(i,:) = pxgy(sample(i),:); 44 | end 45 | 46 | % Seeding mean initialization 47 | % means = seed(pxgy,K); 48 | 49 | thisMeans = zeros(size(means)); 50 | 51 | if trackHistory 52 | clusterHistory = cell(1,maxItr); 53 | end 54 | 55 | % Assign-update iteration until no change occurs 56 | for i = 1:maxItr 57 | 58 | % assign %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 59 | z = means; 60 | y = pxgy; 61 | 62 | clusters = zeros(1,M); 63 | for m = 1:M 64 | dist = zeros(K,1); % distance between y(i) and the K means 65 | p = y(m,:); 66 | for k = 1:K 67 | q = z(k,:); 68 | dist(k) = sum(p .* log2(p./q) ); 69 | end 70 | [~, cIdx] = min(dist); 71 | clusters(m) = cIdx; 72 | end 73 | 74 | if trackHistory 75 | clusterHistory{i} = clusters; 76 | end 77 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 78 | 79 | % update %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 80 | for jj = 1:K 81 | idx = find(clusters == jj); 82 | thisMeans(jj,:) = mean(pxgy(idx,:)); 83 | end 84 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 85 | 86 | newMeans = thisMeans; 87 | 88 | stop = isequal(newMeans,means); % stop if no change occurs 89 | if stop 90 | fprintf('stable after %d iterations\n',i) 91 | break; 92 | end 93 | means = newMeans; % if means change then repeat 94 | end 95 | 96 | %Output quantizer Pr[Z|Y] 97 | Q = zeros(M,K); 98 | for ii = 1:K 99 | idx = find(clusters == ii); 100 | Q(idx,ii) = 1; 101 | end 102 | 103 | %remove empty columns from Q 104 | emptyClusters = find(sum(Q) == 0); 105 | if ~isempty(emptyClusters) 106 | nonEmpty = setdiff(1:K,emptyClusters); 107 | Q = Q(:,nonEmpty); 108 | fprintf('found %d empty clusters\n',length(emptyClusters)); 109 | K = size(Q,2); 110 | end 111 | 112 | %compute mutual information 113 | pzgx = pygx*Q; 114 | pxz = repmat(px(:),1,K) .* pzgx; 115 | pz = sum(pxz,1); 116 | IXZ = sum(sum( pxz .* log2(pxz ./ (px(:) * pz) ))); 117 | 118 | if trackHistory 119 | clusterHistory = clusterHistory(1:i); 120 | end 121 | -------------------------------------------------------------------------------- /QuantDmc-4/quantDmc/randomDmc.m: -------------------------------------------------------------------------------- 1 | function P = randomDMC(J,M) 2 | % randomDMC - genreates a random DMC 3 | % 4 | % P = RandomDMC(J,M) generates a randomly generated discrete memoryless 5 | % channel (DMC) with J inputs and M outputs. P is a J-by-M matrix, where: 6 | % P(j,m) = Pr(Y=m | X=j ), 7 | % for a DMC with inputs X and outputs Y. 8 | % 9 | % If not specified, J defaults to 2, and M defaults to 3 10 | % 11 | % QuantDMC (c) Brian Kurkoski and contributors 12 | % Distributed under an MIT-like license; see the file LICENSE 13 | 14 | if nargin < 2 15 | M = 3; 16 | end 17 | 18 | if nargin < 1 19 | J = 2; 20 | end 21 | 22 | P = rand(J,M); 23 | for jj = 1:J 24 | P(jj,:) = P(jj,:) ./ sum( P(jj,:) ); 25 | end 26 | 27 | %sort when J=2 28 | if J == 2 29 | [~,t] = sort(P(1,:) ./ P(2,:)); 30 | P=P(:,t); 31 | end 32 | -------------------------------------------------------------------------------- /QuantDmc-4/startup.m: -------------------------------------------------------------------------------- 1 | addpath([pwd '/quantDmc']); 2 | 3 | if exist('quantBiDmc') ~= 3 4 | warning(sprintf('QUANTBIDMC MEX file is not available for this platform\nRun MEXIFY to compile.\n')); 5 | mexify 6 | end -------------------------------------------------------------------------------- /Quantized Density-evolution/Density evolution of LDPC by Andrew Eckford.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/Quantized Density-evolution/Density evolution of LDPC by Andrew Eckford.pdf -------------------------------------------------------------------------------- /Quantized Density-evolution/README.txt: -------------------------------------------------------------------------------- 1 | Density Evolution version 0.1.1 2 | Copyright (C) 2003 by Andrew W. Eckford 3 | 4 | ***Licensing information is contained in the file license.txt 5 | ***You must read and agree to the terms of the license before 6 | ***using this software 7 | 8 | Revision History 9 | 10 | Version 0.1 - January 17, 2003 - First release 11 | Version 0.1.1 - March 14, 2003 - Bug fix in new_chk_overflow.m 12 | 13 | This package contains MATLAB scripts which implement Richardson and Urbanke's 14 | density evolution technique to find the ultimate performance of LDPC codes 15 | in memoryless channels. 16 | 17 | Use: 18 | 19 | result_pe = de_regular(chan,iter,ext,mapping,stop_pe,dv,dc); 20 | 21 | where: 22 | 23 | result_pe : is the result vector of length iter, giving the 24 | probability of error after each iteration. 25 | 26 | chan : is a vector containing the PDF of the channel message, which 27 | corresponds to the requirements of ext (see below). Note that 28 | since chan is a PDF, sum(chan)*increment = 1. 29 | 30 | iter : is the maximum number of iterations 31 | 32 | ext : is a vector of the form [base increment length], describing the 33 | quantization of the channel and extrinsic PDFs, where "base" is the 34 | least quantization step, "increment" is the difference between adjacent 35 | quantization steps, and "length" is the number of quantization steps. 36 | For example, [-30 0.01 6001] represents a quantization of 37 | -30, -29.99, -29.98, ..., 29.99, 30. 38 | 39 | mapping : is a vector of the form [base increment length], used 40 | internally to represent the density of the log-magnitude of the tanh 41 | of a check message. These values are always negative since |tanh(x)|<1. 42 | A value I have often used is [-10 0.0002 50000]. 43 | 44 | stop_pe : is a probability. If the probability of error goes below stop_pe, 45 | the routine exits, rather than performing the remaining operations. Set to 46 | zero to disable. 47 | 48 | dv : is the variable degree. 49 | 50 | dc : is the check degree. 51 | 52 | Example (five iterations for a BSC with inversion probability 0.08394): 53 | 54 | >> chan = zeros(1,6001); 55 | >> chan(3240) = 91.606; 56 | >> chan(2762) = 8.394; 57 | >> ext = [-30 0.01 6001]; 58 | >> mapping = [-10 0.0002 50000]; 59 | >> dv = 3; 60 | >> dc = 6; 61 | >> iter = 5; 62 | >> stop_pe = 1e-5; 63 | >> result_pe = de_regular(chan,iter,ext,mapping,stop_pe,dv,dc) 64 | 65 | result_pe = 66 | 67 | 0.0839 0.0788 0.0756 0.0730 0.0710 68 | 69 | 70 | 71 | For irregular LDPC just use irregular.m 72 | 73 | vard(1,:)=[0 0.2895 0.3158 0 0 0.3947]; 74 | chkd(1,:)=[ 0 0 0 0 0 0.9032 0.0968]; 75 | 76 | -------------------------------------------------------------------------------- /Quantized Density-evolution/chan_mess.m: -------------------------------------------------------------------------------- 1 | %channel output signal 'distribution is N(2/deta^2,4/deta^2) 2 | % apply error function to evalute the value of distribution funtion 3 | % then the probability in a unit area can be found 4 | function chan_ini=chan_mess(ext,deta) 5 | mean=2/deta^2; 6 | var_sqrt=2/deta; 7 | chan_ini=zeros(1,ext(3)); 8 | step=[ext(2) ext(2) (ext(3)-1)/2]; 9 | for i=1:step(3)-1 10 | chan_ini(i+step(3)+1)=(erf(((i+0.5)*step(2)-mean)/(sqrt(2)*var_sqrt))-erf(((i-0.5)*step(2)-mean)/(sqrt(2)*var_sqrt)))/2; 11 | chan_ini(i+1)=(erf(((i-step(3)+0.5)*step(2)-mean)/(sqrt(2)*var_sqrt))-erf(((i-step(3)-0.5)*step(2)-mean)/(sqrt(2)*var_sqrt)))/2; 12 | end 13 | chan_ini(1)=(erf(((-step(3)+0.5)*step(2)-mean)/(sqrt(2)*var_sqrt))+1)/2; 14 | chan_ini(step(3)+1)=(erf(((+0.5)*step(2)-mean)/(sqrt(2)*var_sqrt))-erf(((-0.5)*step(2)-mean)/(sqrt(2)*var_sqrt)))/2; 15 | chan_ini(ext(3))=1-(erf(((step(3)-0.5)*step(2)-mean)/(sqrt(2)*var_sqrt))+1)/2; 16 | chan_ini=chan_ini/ext(2); -------------------------------------------------------------------------------- /Quantized Density-evolution/de_irregular.m: -------------------------------------------------------------------------------- 1 | function result_pe = de_irregular(chan,iter,ext,mapping,stop_pe,vard,chkd,dv,dc) 2 | z = chan; 3 | c = 0; 4 | pe = 0.5; 5 | result_pe = zeros(1,iter); 6 | round(0.3); 7 | while ((c < iter) & (pe > stop_pe)) 8 | c = c + 1; 9 | y_ave=0; 10 | for i=2:dc 11 | if chkd(i)~=0 12 | y = new_xchk(ext, z, i-1, mapping); 13 | y = y / (sum(y)*ext(2)); 14 | y_ave=y_ave+chkd(i)*y; 15 | end 16 | end 17 | xvar_ave=0; 18 | for j=2:dv 19 | if vard(j)~=0 20 | z = new_xvar(chan, y_ave, j-1, ext, ext); 21 | xvar_ave=xvar_ave+vard(j)*z; 22 | end 23 | end 24 | z=xvar_ave; 25 | pe = sum(z(1:round((ext(3)-1)/2 + 1)))*ext(2); 26 | result_pe(c) = pe; 27 | fprintf('%f\n',pe); 28 | end 29 | -------------------------------------------------------------------------------- /Quantized Density-evolution/de_regular.m: -------------------------------------------------------------------------------- 1 | function result_pe = de_regular(chan,iter,ext,mapping,stop_pe,dv,dc) 2 | z = chan; 3 | c = 0; 4 | pe = 0.5; 5 | result_pe = zeros(1,iter); 6 | 7 | while ((c < iter) & (pe > stop_pe)) 8 | c = c + 1; 9 | y = new_xchk(ext, z, dc-1, mapping); 10 | y = y / (sum(y)*ext(2)); 11 | z = new_xvar(chan, y, dv-1, ext, ext); 12 | pe = sum(z(1:round((ext(3)-1)/2 + 1)))*ext(2); 13 | result_pe(c) = pe; 14 | fprintf('%f\n',pe); 15 | end 16 | -------------------------------------------------------------------------------- /Quantized Density-evolution/irregular.m: -------------------------------------------------------------------------------- 1 | function irregular 2 | chan = zeros(1,6001); 3 | ext = [-30 0.01 6001]; 4 | mapping = [-10 0.0002 50000]; 5 | dv = 6; 6 | dc = 6; 7 | iter = 100; 8 | stop_pe = 1e-5; 9 | % vard(1,:)=[0.000000 0.201350 0.102124 0.024210 0.432443 0.139250 0.015776 0.084848]; 10 | % chkd(1,:)=[0.000000 0.000000 0.000000 0.000000 0.000000 0.244334 0.061851 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.693815]; 11 | % vard(1,:)=[0 0.062500 0.495536 0.017857 0.424107 ]; 12 | % chkd(1,:)=[0 0 0 0 0 0 1.000000 0.000000 0.000000 ]; 13 | % vard(1,:)=[0 0.261905 0.000000 0.380952 0.000000 0.357143]; 14 | % chkd(1,:)=[0 0 0 0 0 1.000000]; 15 | vard(1,:)=[0 0.2895 0.3158 0 0 0.3947]; 16 | chkd(1,:)=[ 0 0 0 0 0 0.9032 0.0968]; 17 | % vard=zeros(1,dv); 18 | % chkd=zeros(1,dc); 19 | % vard(2)=0.38354; 20 | % vard(3)=0.04237; 21 | % vard(4)=0.57409; 22 | % chkd(5)=0.24123; 23 | % chkd(6)=0.75877; 24 | % vard(2)=0.2524580000; 25 | % vard(3)=0.0748275000; 26 | % vard(5)=0.6727150000; 27 | % chkd(14)=1; 28 | % squre root of variance for Guass 29 | % vard(3)=1; 30 | % chkd(6)=1; 31 | noise=0.872345;%from GA 32 | ns_str_low=0.9; 33 | ns_str_high=0.94; 34 | ns_stp=0.01; 35 | % chan=chan_mess(ext,noise); 36 | % result_pe = de_irregular(chan,iter,ext,mapping,stop_pe,vard,chkd,dv,dc); 37 | threshold=threshold_tst(vard,chkd,ns_str_low,ns_str_high,ns_stp,ext,mapping,iter,stop_pe); 38 | fprintf('%8f', threshold); 39 | 40 | -------------------------------------------------------------------------------- /Quantized Density-evolution/license.txt: -------------------------------------------------------------------------------- 1 | This software is copyright (C) 2003 by Andrew W. Eckford (hereinafter "the 2 | author"). 3 | 4 | PERMISSION TO USE 5 | 6 | Permission is granted to use this software, in whole or in part, free of 7 | charge, for any non-commercial purpose, including not-for-profit 8 | university research. A commercial purpose is defined as any officially 9 | sanctioned undertaking by any for-profit business. To obtain a license to 10 | use this software for a commercial purpose, please contact the author. 11 | 12 | PERMISSION TO RE-DISTRIBUTE 13 | 14 | Permission is granted to re-distribute this software package, including 15 | all source files, if re-distributed as a whole and unmodified. 16 | Permission is granted to re-distribute modified versions of this software 17 | package if the modifications are restricted to repackaging (e.g., 18 | converting from .tar.gz to .zip), and the repackaged version contains all 19 | the original, unmodified files. In addition to the original source files, 20 | permission is granted to distribute packages with executable versions of 21 | the software for any platform, if the executable version is obtained from 22 | the original source files and only those files, and if the original, 23 | unmodified source files are included in the package. For other permission 24 | to re-distribute, please contact the author. 25 | 26 | COPYRIGHT HORIZON 27 | 28 | This license expires on January 17, 2018. After that date, the author 29 | waives his rights to copyright over this software package, and the package 30 | enters the public domain. 31 | 32 | WARRANTY 33 | 34 | This software is offered "as-is". By using this software, the user agrees 35 | to indemnify the author from any liability that may arise from its use. 36 | -------------------------------------------------------------------------------- /Quantized Density-evolution/new_chk_overflow.m: -------------------------------------------------------------------------------- 1 | function y = new_chk_overflow(f_n_ext,ofl_pos,ofl_neg,ext,mapping) 2 | 3 | m_pos_index = round((2*atanh(exp(-mapping(2)/2)) - ext(1))/ext(2)) + 1; 4 | m_neg_index = round((-2*atanh(exp(-mapping(2)/2)) - ext(1))/ext(2)) + 1; 5 | 6 | if (m_pos_index < ext(3)) 7 | f_n_ext(m_pos_index) = f_n_ext(m_pos_index) + ofl_pos/ext(2); 8 | else 9 | f_n_ext(ext(3)) = f_n_ext(ext(3)) + ofl_pos/ext(2); 10 | end 11 | 12 | if (m_neg_index > 1) 13 | f_n_ext(m_neg_index) = f_n_ext(m_neg_index) + ofl_neg/ext(2); 14 | else 15 | f_n_ext(1) = f_n_ext(1) + ofl_neg/ext(2); 16 | % Thanks to Sang Hyun Lee for spotting this error 17 | end 18 | 19 | % actually, the if-then should be unnecessary, by the nature of overflow ... but 20 | % then we'd have to check whether ofl_pos or ofl_neg was zero 21 | 22 | y = f_n_ext; 23 | -------------------------------------------------------------------------------- /Quantized Density-evolution/new_fft_convolve_chk.m: -------------------------------------------------------------------------------- 1 | function [f_n_log_pos,f_n_log_neg,p_result_zero] = new_fft_convolve_chk(f_log_pos, f_log_neg, num, n_log, excess, p_zero) 2 | 3 | % perform FFTs over R x GF(2) to obtain probabilities with sign information 4 | 5 | % I will *assume* that the range of f_log_pos and f_log_neg are over the range 6 | % min:increment:-increment, with min*increment elements 7 | % 8 | % the input ofl_pos is the probability of the input "flog" message 9 | % being zero ... can directly include this in the sum 10 | % 11 | % furthermore, by the symmetry property, "flog" can only be zero 12 | % if the sign is positive 13 | 14 | % find the probabilities of being positive or negative ... used in calculating the 15 | % conditional probability 16 | 17 | % these form the extended (by 1) messages, which give room for an extra zero message 18 | q_pos = zeros(1,length(f_log_pos)+1); 19 | q_pos(1:length(f_log_pos)) = f_log_pos; 20 | q_neg = zeros(1,length(f_log_neg)+1); 21 | q_neg(1:length(f_log_neg)) = f_log_neg; 22 | 23 | % sf = size of the extended message 24 | sf = length(f_log_pos)+1; 25 | 26 | % find length to nearest higher power of 2 to help with fft 27 | zp2_size = 2^(ceil(log2(sf*num - num + 1))); 28 | zeropad_pos = zeros(1, zp2_size); 29 | zeropad_neg = zeropad_pos; 30 | 31 | % preserve *direct* probabilities under convolution 32 | % also note that overflow is included in zeropad_pos 33 | zeropad_pos(1:sf) = q_pos*n_log(2); 34 | zeropad_neg(1:sf) = q_neg*n_log(2); 35 | zeropad_pos(sf) = excess(1); 36 | zeropad_neg(sf) = excess(3); 37 | 38 | % find the probabilities of being positive or negative and finite ... 39 | % as well as marginal and conditional probabilities 40 | p_pos_fin = sum(zeropad_pos); 41 | p_pos = sum(zeropad_pos) + excess(2); 42 | 43 | % note: excess(1), excess(3) are already contained in zeropad 44 | 45 | p_neg_fin = sum(zeropad_neg); 46 | p_neg = sum(zeropad_neg) + excess(4); 47 | % fprintf('%f \n ',zeropad_pos/p_pos_fin); 48 | % fprintf('%f \n ',zeropad_neg/p_pos_fin); 49 | % here we take the FFT of the *conditional* density 50 | F_pos_fin = fft(zeropad_pos/p_pos_fin); 51 | F_neg_fin = fft(zeropad_neg/p_neg_fin); 52 | 53 | result_pos = zeros(1, zp2_size); 54 | result_neg = zeros(1, zp2_size); 55 | p_result_zero = 0; 56 | 57 | % now combine the magnitude and sign components to get the result 58 | % have to do proper handing for -\infty messages (i.e., wrap=0) 59 | 60 | foo = zeros(num+1,zp2_size); 61 | 62 | % now marginalize with respect to positive or negative events 63 | % (i.e., c even or odd) 64 | % 65 | % note that result_pos and result_neg are joint probabilities 66 | % of the amplitude and being positive or negative 67 | 68 | for c = 0:num 69 | 70 | % no underflow 71 | % any sign = zero -- attached to p_result_zero 72 | v = (1 - (p_pos/(p_pos+p_zero))^(num-c)) * nchoosek(num,c)*p_neg^c * (p_pos+p_zero)^(num-c); 73 | p_result_zero = p_result_zero + v; 74 | temp2=(1-excess(4))^c * (1-excess(2))^(num-c); 75 | temp3=nchoosek(num,c) * p_neg^c * p_pos^(num-c); 76 | v = (F_pos_fin.^(num-c)).*(F_neg_fin.^c); 77 | v = v * temp2; 78 | v = v * temp3; 79 | 80 | if (mod(c,2)==0) 81 | % even negatives -- result is positive 82 | result_pos = result_pos + v; 83 | else 84 | % odd negatives -- result is negative 85 | result_neg = result_neg + v; 86 | end 87 | 88 | % at least one underflow 89 | % regardless of sign, attached to p_result_zero 90 | 91 | % if there are c negative messages, then there are at most num-c positive messages 92 | 93 | for d = 0:(num-c) 94 | 95 | % calculate no underflow first ... then complement 96 | w = (1-excess(2))^c * (1-excess(4))^d; 97 | v = (1-w)*prod(1:num)/(prod(1:c)*prod(1:d)*prod(1:(num-c-d))); 98 | v = v * p_neg^c * p_pos^d * p_zero^(num-c-d); 99 | 100 | p_result_zero = p_result_zero + v; 101 | 102 | end 103 | 104 | end 105 | result_pos=ifft(result_pos); 106 | result_neg=ifft(result_neg); 107 | result_pos = abs(result_pos)/n_log(2); 108 | result_neg = abs(result_neg)/n_log(2); 109 | 110 | f_n_log_pos = result_pos(1:(sf*num - num + 1)); 111 | f_n_log_neg = result_neg(1:(sf*num - num + 1)); 112 | 113 | 114 | -------------------------------------------------------------------------------- /Quantized Density-evolution/new_flog2wrap.m: -------------------------------------------------------------------------------- 1 | function [f_wrap,ofl_pos,ofl_neg] = new_flog2wrap(n_log, f_n_log_pos, f_n_log_neg, ext, p_n_zero) 2 | 3 | % converts a log(tanh(L/2)) form random variable to LLR 4 | % recall that sign information is preserved 5 | 6 | wrap = [ext(2) ext(2) (ext(3)-1)/2]; 7 | t_wrap = wrap(1):wrap(2):(wrap(1) + wrap(2)*(wrap(3)-1)); 8 | 9 | foo = zeros(2,n_log(3)); 10 | foo(1,:) = (n_log(1) - n_log(2)/2):n_log(2):(n_log(1)+n_log(2)*(n_log(3)-1) - n_log(2)/2); 11 | foo(2,:) = (n_log(1) + n_log(2)/2):n_log(2):(n_log(1)+n_log(2)*(n_log(3)-1) + n_log(2)/2); 12 | foo(1,1) = n_log(1); 13 | foo(2,n_log(3)) = n_log(1) + n_log(2)*(n_log(3)-1); 14 | bin_convert = 2*atanh(exp(foo)); 15 | 16 | bar = tanh(t_wrap/2); 17 | coeff = (1./bar).*(1-bar.^2)*0.5; 18 | 19 | [f_wrap_pos,ofl_pos,ufl_pos] = xconvert(n_log, f_n_log_pos, bin_convert, wrap, coeff); 20 | [f_wrap_neg,ofl_neg,ufl_neg] = xconvert(n_log, f_n_log_neg, bin_convert, wrap, coeff); 21 | 22 | result = zeros(1,ext(3)); 23 | 24 | result(1:((ext(3)-1)/2)) = f_wrap_neg(((ext(3)-1)/2):-1:1); 25 | result(((ext(3)-1)/2 + 2):ext(3)) = f_wrap_pos; 26 | result((ext(3)-1)/2 + 1) = (p_n_zero + ufl_pos + ufl_neg)/ext(2); 27 | 28 | f_wrap = result; 29 | 30 | 31 | -------------------------------------------------------------------------------- /Quantized Density-evolution/new_wrap2flog.m: -------------------------------------------------------------------------------- 1 | function [f_log_pos,f_log_neg,excess] = new_wrap2flog(ext, f_ext, mapping) 2 | 3 | % converts a probability from LLR to log(tanh(L/2)) form 4 | % preserving sign information 5 | % 6 | % note, the zero is dropped! ... but not the underflow 7 | 8 | t_mapping = mapping(1):mapping(2):(mapping(1) + mapping(2)*(mapping(3)-1)); 9 | 10 | wrap = [ext(2) ext(2) (ext(3)-1)/2]; 11 | 12 | foo = zeros(2,wrap(3)); 13 | foo(1,:) = (wrap(1) - wrap(2)/2):wrap(2):(wrap(1)+wrap(2)*(wrap(3)-1)- wrap(2)/2); 14 | foo(2,:) = (wrap(1) + wrap(2)/2):wrap(2):(wrap(1)+wrap(2)*(wrap(3)-1) + wrap(2)/2); 15 | foo(1,1) = wrap(1); 16 | foo(2,wrap(3)) = wrap(1)+wrap(2)*(wrap(3)-1); 17 | bin_convert = log(tanh(foo/2)); 18 | 19 | coeff = 2*exp(t_mapping)./(1-exp(2*t_mapping)); 20 | 21 | % excess = [ofl_pos ufl_pos ofl_neg ufl_neg] 22 | excess = zeros(1,4); 23 | bar = f_ext(((ext(3)-1)/2 + 2):ext(3)); 24 | [f_log_pos,ofl,ufl] = xconvert(wrap, bar, bin_convert, mapping, coeff); 25 | excess(1) = ofl; 26 | excess(2) = ufl; 27 | 28 | bar = f_ext(((ext(3)-1)/2):-1:1); 29 | [f_log_neg,ofl,ufl] = xconvert(wrap, bar, bin_convert, mapping, coeff); 30 | excess(3) = ofl; 31 | excess(4) = ufl; 32 | 33 | % note that excess(3) should equal (very close to) zero under the symmetry condition 34 | % ..... NO! It is still nonzero, because of the granularity of the mapping 35 | 36 | -------------------------------------------------------------------------------- /Quantized Density-evolution/new_xchk.m: -------------------------------------------------------------------------------- 1 | function y = new_xchk(ext, f_ext, num, mapping) 2 | 3 | % for some reason, "wrap" = normal log-likelihood ratio 4 | % and "flog" = log(tanh(x/2)), where x is the llr 5 | 6 | % excess = [ofl_pos ufl_pos ofl_neg ufl_neg] 7 | [f_log_pos,f_log_neg,excess] = new_wrap2flog(ext, f_ext, mapping); 8 | 9 | p_zero = f_ext(round((ext(3)-1)/2 + 1))*ext(2); 10 | 11 | % n_log contains the new bins for the convolved function 12 | 13 | n_log = [mapping(1)*num mapping(2) ((mapping(3)+1)*num - num + 1)]; 14 | [f_n_log_pos,f_n_log_neg,p_result_zero] = new_fft_convolve_chk(f_log_pos, f_log_neg, num, n_log, excess, p_zero); 15 | 16 | [f_n_ext,ofl_pos,ofl_neg] = new_flog2wrap(n_log, f_n_log_pos, f_n_log_neg, ext, p_result_zero); 17 | 18 | % note: the overflows should be placed at the value corresponding to 19 | % 2*atanh(exp(-mapping(2)/2)), because this is the uppermost value that 20 | % can be represented using the quantization given by mapping 21 | 22 | f_n_ext = new_chk_overflow(f_n_ext,ofl_pos,ofl_neg,ext,mapping); 23 | 24 | y = f_n_ext; 25 | -------------------------------------------------------------------------------- /Quantized Density-evolution/new_xvar.m: -------------------------------------------------------------------------------- 1 | function y = new_xvar(chan, func, num, state, ext) 2 | 3 | sc = length(chan); 4 | sf = length(func); 5 | 6 | zeropad = zeros(1,sc + sf*num - num); 7 | bar = zeropad; 8 | 9 | % direct probabilities 10 | bar(1:sc) = chan*state(2); 11 | zeropad(1:sf) = func*ext(2); 12 | 13 | F_zeropad = fft(zeropad); 14 | foo = F_zeropad.^num; 15 | foo = foo .* fft(bar); 16 | IF_zeropad = ifft(foo); 17 | 18 | % extract function of the appropriate length from the middle ... 19 | % question: where is the zero? 20 | % clearly, the minimum index is the sum of all input minimum indices 21 | 22 | minx = state(1) + num*ext(1); 23 | 24 | % let's hope that state(2) and ext(2) are the same 25 | 26 | ext_minx_index = round((ext(1) - minx)/ext(2)) + 1; 27 | ext_maxx_index = ext_minx_index + ext(3) - 1; 28 | 29 | %thud = IF_zeropad/sum(IF_zeropad); 30 | ufl = abs(sum(IF_zeropad(1:(ext_minx_index-1)))); 31 | ofl = abs(sum(IF_zeropad((1+ext_maxx_index):length(IF_zeropad)))); 32 | 33 | IF_zeropad(ext_minx_index) = IF_zeropad(ext_minx_index) + ufl; 34 | IF_zeropad(ext_maxx_index) = IF_zeropad(ext_maxx_index) + ofl; 35 | 36 | y = abs(IF_zeropad(ext_minx_index:ext_maxx_index))/ext(2); 37 | 38 | 39 | -------------------------------------------------------------------------------- /Quantized Density-evolution/regular.m: -------------------------------------------------------------------------------- 1 | function regular 2 | chan = zeros(1,6001); 3 | ext = [-30 0.01 6001]; 4 | mapping = [-10 0.0002 50000]; 5 | dv = 3; 6 | dc = 6; 7 | iter = 20; 8 | stop_pe = 1e-5; 9 | % squre root of variance for Guass 10 | noise=1.0; 11 | chan=chan_mess(ext,noise); 12 | result_pe = de_regular(chan,iter,ext,mapping,stop_pe,dv,dc) 13 | 14 | -------------------------------------------------------------------------------- /Quantized Density-evolution/threshold_tst.m: -------------------------------------------------------------------------------- 1 | % given degree distibution find the threshold 2 | function ns_tmp= threshold_tst(vard,chkd,ns_str_low,ns_str_high,ns_stp,ext,mapping,iter,stop_pe) 3 | % vard variable node degree 4 | % chkd check nodedegree 5 | % ns_str start noise 6 | % ns_stp decrease noise step 7 | % chan channle initial message 8 | % ext variable and channel form of the message 9 | % mapping check node messange domain 10 | % iter iterative number 11 | % stop_pe if error probability smaller than, stop without doing anything 12 | flag=1; 13 | % ns_tmp=ns_str; 14 | [row,dv]=size(vard); 15 | [row,dc]=size(chkd); 16 | 17 | while (ns_str_high-ns_str_low>=0.01) 18 | ns_tmp=(ns_str_high+ns_str_low)/2; 19 | chan=chan_mess(ext,ns_tmp); 20 | z = chan; 21 | c = 0; 22 | pe = 0.5; 23 | pe_former=0; 24 | while (c < iter) 25 | c = c + 1; 26 | y_ave=0; 27 | for i=2:dc 28 | if chkd(i)~=0 29 | y = new_xchk(ext, z, i-1, mapping); 30 | y = y / (sum(y)*ext(2)); 31 | y_ave=y_ave+chkd(i)*y; 32 | end 33 | end 34 | xvar_ave=0; 35 | for j=2:dv 36 | if vard(j)~=0 37 | z = new_xvar(chan, y_ave, j-1, ext, ext); 38 | xvar_ave=xvar_ave+vard(j)*z; 39 | end 40 | end 41 | z=xvar_ave; 42 | pe = sum(z(1:round((ext(3)-1)/2 + 1)))*ext(2) 43 | 44 | if(abs(pe_former-pe)<1e-5) 45 | break; 46 | end 47 | 48 | pe_former=pe; 49 | end 50 | if pe>stop_pe 51 | ns_str_high=ns_tmp; 52 | else 53 | ns_str_low=ns_tmp; 54 | end 55 | end 56 | 57 | 58 | -------------------------------------------------------------------------------- /Quantized Density-evolution/xconvert.m: -------------------------------------------------------------------------------- 1 | function [y,ofl,ufl] = xconvert(bins, func, bin_convert, result_bins, coeff) 2 | 3 | % idea: map blockwise from func, defined over bins, into result_bins 4 | % 5 | % bin_convert contains the converted bin boundaries -- 6 | % bin_convert(1,:) contains mapping of lower bin limit, 7 | % bin_convert(2,:) contains mapping of upper bin limit. 8 | 9 | t_result_bins = result_bins(1):result_bins(2):(result_bins(1) + result_bins(2)*(result_bins(3)-1)); 10 | result_func = zeros(1,result_bins(3)); 11 | 12 | % keep track of overflow/underflow 13 | ofl = 0; 14 | ufl = 0; 15 | 16 | for c = 1:bins(3) 17 | 18 | % remember: t_result_bins gives the bin *centers* 19 | 20 | rounds = round((bin_convert(:,c) - result_bins(1))/result_bins(2)) + 1; 21 | 22 | % first: are the indices in range? 23 | 24 | flag = 0; 25 | partflag = 0; 26 | min_result_bin = result_bins(1) - 0.5*result_bins(2); 27 | max_result_bin = result_bins(1) + result_bins(2)*(result_bins(3)-1) + 0.5*result_bins(2); 28 | 29 | % lower range exceeded by both 30 | if ((rounds(1) < 1) & (rounds(2) < 1)) 31 | ufl = ufl + func(c)*bins(2); 32 | flag = 1; 33 | end 34 | 35 | % higher range exceeded by both 36 | if ((rounds(1) > result_bins(3)) & (rounds(2) > result_bins(3))) 37 | ofl = ofl + func(c)*bins(2); 38 | flag = 1; 39 | end 40 | 41 | % lower range exceeded by a single index 42 | if ((flag == 0) & (rounds(1) < 1)) 43 | rounds(1) = 1; 44 | bin_convert(1,c) = min_result_bin; 45 | partflag = 1; 46 | end 47 | 48 | % higher range exceeded by a single index 49 | if ((flag == 0) & (rounds(2) > result_bins(3))) 50 | rounds(2) = result_bins(3); 51 | bin_convert(2,c) = max_result_bin; 52 | partflag = 1; 53 | end 54 | 55 | if (flag == 0) 56 | 57 | % is the conversion restricted to a single bin? 58 | 59 | if (rounds(1) == rounds(2)) 60 | 61 | % map the entire probability of the bin to a single result bin 62 | 63 | bar = func(c)*bins(2)/result_bins(2); 64 | result_func(rounds(1)) = result_func(rounds(1)) + bar; 65 | 66 | % is the conversion over two bins only? 67 | 68 | elseif ((rounds(2)-rounds(1)) == 1) 69 | 70 | % find the fractional probabilities associated with each bin 71 | % the bin boundary is (obviously) halfway between round(2) and round(1) 72 | 73 | bdy = (((rounds(1)-1)+0.5)*result_bins(2) + result_bins(1)); 74 | lowfrac = abs(bin_convert(1,c) - bdy)/result_bins(2); 75 | highfrac = abs(bin_convert(2,c) - bdy)/result_bins(2); 76 | bar = [lowfrac highfrac] * func(c); 77 | bar = bar .* [coeff(rounds(1)) coeff(rounds(2))]; 78 | result_func(rounds(1):rounds(2)) = result_func(rounds(1):rounds(2)) + bar; 79 | 80 | else 81 | 82 | % find the fractional probabilities associated with the end bins 83 | % then the probabilities associated with the intervening bins 84 | 85 | lowbdy = (((rounds(1)-1)+0.5)*result_bins(2) + result_bins(1)); 86 | highbdy = (((rounds(2)-1)-0.5)*result_bins(2) + result_bins(1)); 87 | lowfrac = abs(bin_convert(1,c) - lowbdy)/result_bins(2); 88 | highfrac = abs(bin_convert(2,c) - highbdy)/result_bins(2); 89 | 90 | bar = zeros(1,rounds(2)-rounds(1)+1); 91 | bar(1) = lowfrac*func(c); 92 | bar(rounds(2)-rounds(1)+1) = highfrac*func(c); 93 | bar(2:(rounds(2)-rounds(1))) = func(c); 94 | bar = bar .* coeff(rounds(1):rounds(2)); 95 | result_func(rounds(1):rounds(2)) = result_func(rounds(1):rounds(2)) + bar; 96 | 97 | end % if 98 | 99 | end % if 100 | 101 | if (partflag == 1) 102 | 103 | % part of the probability lies outside of the range 104 | % calculate how much is accounted for; rest is overflow 105 | 106 | pprob = sum(bar)*result_bins(2); 107 | 108 | if (pprob < func(c)*bins(2)) 109 | 110 | if (rounds(1) < 1) % underflow 111 | ufl = ufl + (func(c)*bins(2) - pprob); 112 | else 113 | ofl = ofl + (func(c)*bins(2) - pprob); 114 | end 115 | 116 | end 117 | 118 | end 119 | 120 | end % for 121 | 122 | y = result_func; 123 | 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Density Evolution, Covariance Evolution for AWGN Symmetrical and Assymetrical channels Matlab and Python implementation 2 | 1. The "main.m" file in the subfolder [https://github.com/Lcrypto/Density-Evolution-AWGN/tree/master/](https://github.com/Lcrypto/Density-Evolution-AWGN/tree/master/%20Reciprocal-channel%20approximation%20for%20approximation%20of%20Density%20Evolution%20Iterative%20Decoding%20Threshold) Reciprocal-channel approximation for approximation of Density Evolution Iterative Decoding Threshold contains a protograph reciprocal-channel approximation (RCA) for GA-like approximation of Density Evolution Iterative Decoding Threshold of Multi Edge Type (MET) LDPC Codes. The RCA method constructs codes using the method outlined in S.-Y. Chung, G.D. Forney, T.J. Richardson, R. Urbanke's article titled "On the design of low-density parity-check codes within 0.0045 dB of the Shannon limit," which was published in IEEE Communications Letters in 2001. The RCA method is thoroughly described in S.-Y.Chung's Ph.D. dissertation titled "On the construction of some capacity-approaching coding schemes" from MIT in 2000. 3 | 4 | The code has been tested on both old (2011) and new (2018) versions of Matlab as well as GNU Octave 5.1 (which is several times slower than Matlab). RCA-GA is one of the best methods for fast DE approximation from runtime and accuracy. 5 | 6 | Protograph RCA does not require the generation of protographs; rather, it can be lifted directly using Simulated Annealing with girth/EMD (https://github.com/Lcrypto/Simulated-annealing-lifting-QC-LDPC) or another QC extension method. The "main.m" file provides an example of threshold estimation using the Octopus protograph. 7 | 8 | ![alt text](https://github.com/Lcrypto/Density-Evolution-AWGN/blob/master/Octopus.png) 9 | 10 | 11 | 2. "profgen.m" provides GA-approximation of Density Evolution based optimization of degree distribution for LDPC codes under AWGN-channel. The code was taken from Alexandre de Baynast's website at https://www.ece.rice.edu/~debaynas/codes.html. Due to changes in the lsqlin implementation, the code works only until R2016 (active-set algorithm removed), and the new version of Matlab is currently not supported. We would like to thank Dr. Ovinnikov A. for reporting the bug. 12 | 13 | 14 | 3. The "main.m" file in the GA subfolder contains Gaussian approximation-based Differential Evolution optimization of LDPC degree distribution by Dr. Chén Zǐ Qiáng (陈紫强) from Guilin University of Electronic Technology (桂林电子科技大学,广西桂). 15 | 16 | 17 | The paper titled "A New Density Evolution Approximation for LDPC and Multi-Edge Type LDPC Codes" by Sarah J. Johnson et al., published in IEEE Transactions on Communications in October 2016 (https://arxiv.org/pdf/1605.04665.pdf), provides an excellent comparison of the quality of GA, GA-RCA, and pure DE methods. 18 | 19 | 4. A draft version of Covariance Evolution, which provides a solution to the peeling decoder differential equation with Octopus protograph and is a generalization of Density Evolution on Finite-Length, is now available at https://github.com/Lcrypto/Density-Evolution-AWGN/tree/master/Covariance-Evolution. In Dr. Richardson's file, tabulated values such as a, b, VN, CN, and Circulant are stored. WER(SNR) = Q(a*(10*log10(SNR)-b)) is calculated using these values. Linear interpolation is used to obtain values for circulant between and to calculate WER for them. 20 | 21 | 5. Dr. Fan Zhang's paper titled "Covariance Evolution Estimation of Irregular LDPC List Sum-Product Decoder under Q-ary Symmetric Channel" (https://arxiv.org/abs/0806.3243) provides an estimate of irregular LDPC List Sum-Product decoder under q-ary symmetric channel. The MATLAB source code for this estimation is available at https://github.com/Lcrypto/Density-Evolution-AWGN/tree/master/Covariance_Evolution_of_LIST_BP_under_q-ary_channel. 22 | 23 | 6. Dr. Andrew W. Eckford has developed Quantized Density Evolution, which is available at https://github.com/Lcrypto/Density-Evolution-AWGN/tree/master/Quantized Density-evolution. 24 | 25 | 7. The QuantDMC ver 4 library, developed in 2016, provides Mutual Information optimization for quantized LLRs under Discrete Memoryless Channel. For example, it includes non-uniformly quantized AWGN-channel optimization, which can be found at https://github.com/Lcrypto/Density-Evolution-AWGN/tree/master/QuantDmc-4. Brian Kurkovskiy's website at http://www.jaist.ac.jp/is/labs/bits/source hosts the code. The paper titled "Quantization of binary-input discrete memoryless channels" by B. M. Kurkoski and H. Yagi, published in IEEE Transactions on Information Theory in August 2014, provides an in-depth description of the library. 26 | 27 | An example of how to use the QuantDMC ver 4 library can be found at https://github.com/Very-Fancy/ldpc-quant. An figure from the library application for quantization optimization is shown below: 28 | 29 | 30 | 31 | ![alt text](https://github.com/Lcrypto/Density-Evolution-AWGN/blob/master/QuantDmc-4/075eng.png) 32 | 33 | 34 | 35 | 8. The Density Evolution for Asymmetric Memoryless Channels has been implemented in Python and can be found at https://github.com/Lcrypto/Density-Evolution-AWGN/tree/master/density_evolution_ga_python. Differential evolution is used to find optimal solutions constrained by maximum allowed degree distributions. The Gaussian Approximation implementation is used to construct Multi-edge or Protograph QC-LDPC codes for Richardson-Urbanke Flarion-Qualcomm and Divsalar Jet Propulsion Lab, respectively. It is important to note that the terms "Multi-edge" and "Protograph" refer to the same QC-LDPC codes. 36 | 37 | 9. The "Reported Thresholds and BER Performance for LDPC and LDPC-Like Codes" by Sarah J. Johnson provides valuable information on Density Evolution threshold. The report can be found at https://github.com/Lcrypto/Density-Evolution-AWGN/blob/master/Reported%20Thresholds%20and%20BER%20Performance%20for%20LDPC.pdf. 38 | 39 | 40 | 41 | 42 | To obtain a protograph from a protograph ensemble (weight profile: weight distribution, rho/lambda), you can use various methods. 43 | 44 | "rand_proto.m" generates a protograph according to the weight distribution of the variable and check. The algorithm is probabilistic and may fail. To improve success rate, you can try running the script multiple times (from 10 to 100K) or using different sizes of protographs and degree distributions. 45 | 46 | PEG C++ (https://github.com/Lcrypto/classic-PEG-/tree/master/classic_PEG), PEG+ACE Matlab (https://github.com/Lcrypto/classic-PEG-/blob/master/ProgressiveEdgeGrowthACE.m), and QC PEG with ACE C++ (https://github.com/Lcrypto/classic-PEG-/tree/master/QC-LDPC ACE-PEG) are other options for obtaining protographs. 47 | 48 | To lift a protograph for a certain circulant, you can use: 49 | 50 | Simulated Annealing with girth/EMD - this is the current state-of-the-art lifting method for optimizing graph properties (https://github.com/Lcrypto/Simulated-annealing-lifting-QC-LDPC). 51 | 52 | Quasi-Cyclic PEG with ACE (https://github.com/Lcrypto/classic-PEG-/tree/master/QC-LDPC ACE-PEG) is a previous best solution. 53 | 54 | Fossorier's approach Guess-and-Test can also be used for comparison: 55 | 56 | https://github.com/Lcrypto/Guess-and-Test-For-CPM-weight-more-1 57 | 58 | 59 | and 60 | 61 | 62 | https://github.com/Lcrypto/-Greedy-Guess-and-Test-method-for-construction-QC-LDPC-codes-with-CPM-of-weigth-more-than-1. 63 | 64 | P.S. Note that if you need the degree distribution for relay flat fading, you can use DE for Relay flat-fading which provides the necessary information. [DE for Relay flat-fading](https://github.com/Lcrypto/Density-Evolution-for-relay-flat-fading-channel-) 65 | 66 | 67 | -------------------------------------------------------------------------------- /Reciprocal-channel approximation for approximation of Density Evolution Iterative Decoding Threshold/Octopus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/Reciprocal-channel approximation for approximation of Density Evolution Iterative Decoding Threshold/Octopus.png -------------------------------------------------------------------------------- /Reciprocal-channel approximation for approximation of Density Evolution Iterative Decoding Threshold/README.md: -------------------------------------------------------------------------------- 1 | # Reciproent-channel-approximation-RCA-for-LDPC 2 | Reciproent-channel approximation for approximation of Density Evolution iterative decoding threshold under AWGN channel 3 | 4 | 5 | ![alt text](https://github.com/Lcrypto/Density-Evolution-AWGN/tree/master/%20Reciprocal-channel%20approximation%20for%20approximation%20of%20Density%20Evolution%20Iterative%20Decoding%20Threshold/octopus.png) 6 | 7 | -------------------------------------------------------------------------------- /Reciprocal-channel approximation for approximation of Density Evolution Iterative Decoding Threshold/ReportDETresh.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/Reciprocal-channel approximation for approximation of Density Evolution Iterative Decoding Threshold/ReportDETresh.pdf -------------------------------------------------------------------------------- /Reported Thresholds and BER Performance for LDPC.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/Reported Thresholds and BER Performance for LDPC.pdf -------------------------------------------------------------------------------- /application of proposed methods.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/application of proposed methods.jpg -------------------------------------------------------------------------------- /density_evolution_ga_python/README.md: -------------------------------------------------------------------------------- 1 | # Background 2 | 3 | 4 | An optimal LDPC code is typically defined by a waterfall region close to the Shannon limit of the channel. In principle, when finding an optimal code that performs well in the waterfall region, it would be possible to simulate a large number of codes and pick the code that performs the best. However, due to the large search space and the time it takes to simulate, this would take an immensely long time. Therefore, it is necessary to find a method in which the decoding performance at the waterfall region can be characterized through probabilistic measures of groups of codes. By looking at code ensembles, the search space becomes smaller and simulation times become much faster, which makes the optimization computationally feasible. To further motivate the use of code ensembles, it can be shown that decoding failures that characterize the type of failuresthat occur at the waterfall region are sharply concentrated around the ensemble average. This makes code ensembles representative of the decoding performance at the waterfall region of individual codes within. 5 | 6 | 7 | # Program description 8 | The main script is [density_evolution.py](./density_evolution.py). The parameters that are meant to be adjusted by the user (along with a parameter description) can be found in [config.yml](./config.yml). Furthermore, [de_utils.py](./de_utils.py) contains code that implements density evolution along with some other functions that are used for optimization. 9 | 10 | There are two types of algorithms implemented to optimize degree distributions based on density evolution. The first ([ga_continuous.py](./ga_continuous.py)) uses the concept of differential evolution to find optimal solutions constrained by maximum allowed degree distributions. Furthermore, the degree distributions are considered continuous in this aspect. This algorithm is not error free and could be improved significantly. 11 | 12 | The other algorithm, and the one that has been used most in this project ([ga_discrete.py](ga_discrete.py)), genetically optimizes degree distributions based on the constraints set by the size of the protograph used in [MM_QC_PEGA](https://github.com/Lcrypto/classic-PEG-/tree/master/mm_qc_pega). 13 | 14 | Lastly, since the algorithms are rather complex, the multiprocessing library has been used to run the optimizations in parallel. An illustration of how multiprocessing has been used can be seen in [multiprocessing_illustration.py](multiprocessing_illustration.py). 15 | 16 | ## Dealing with asymmetry of the channel 17 | It is important to mention that the concept used in this project to deal with asymmetry has been the one described on page 312 in [Modern Coding Theory](https://books.google.se/books?hl=en&lr=&id=ZJrZPObOe60C&oi=fnd&pg=PR13&dq=modern+coding+theory+urbanke&ots=WohuOu5lqr&sig=OaewAYIeWVBUZQYBnexWfgaHo3k&redir_esc=y#v=onepage&q&f=false), i.e. the channel has been symmetrized and then evaluated using symmetrical density evolution. This yielded some unexpected results, and it would be interesting to see that the results would be the same for asymmetric density evolution as described in [Wang's article](https://ieeexplore.ieee.org/abstract/document/1542413). 18 | 19 | # Running scripts on a remote server 20 | ## Install Anaconda on remote server 21 | To be able to run the script on a remote server you will need the correct version of python. In our versions, we have used python 3.8.5. Installing directly on the OS is not adviced, so install using some virtual environment, for example Anaconda. Here, we go trhough how to install with Anaconda. 22 | 23 | Install using wget: 24 | - Go to [Anaconda archive](https://repo.anaconda.com/archive/) and pick the latest version of Anaconda compatible with linux (Linux-x86_64.sh) 25 | - Log into your remote server using ssh. 26 | - In your root folder, type: 27 | ``` 28 | $ wget https://repo.anaconda.com/archive/[Anaconda_version.sh] 29 | ``` 30 | 31 | - Replace Anaconda_version.sh with the one you picked from the archive. 32 | - Next install Anaconda (executing in your root folder): 33 | ``` 34 | $ bash [Anaconda_version.sh] 35 | ``` 36 | 37 | - Accept the license and confirm installation location. 38 | - Next, you will need to set you conda environment variable. Do this by typing 39 | ``` 40 | $ echo 'export PATH=~/anaconda3/bin:$PATH' >> ~/.bashrc 41 | $ source ~/.bashrc 42 | ``` 43 | 44 | You should now be all set to start using Anaconda. Check documentation for how to run different commands. 45 | 46 | Essentiallly, you want to create an environment for example 47 | 48 | ``` 49 | $ conda create --name ldpc_master_thesis python=3.8.5 50 | $ source activate ldpc_master_thesis 51 | ``` 52 | 53 | Check that you are in the correct environment and start installing using conda install. You should now have the correct version of python when running scripts. 54 | 55 | 56 | 57 | ## Run jobs using screen 58 | 59 | To run script remotely, use "screen" on linux. 60 | To start a new screen type: 61 | 62 | ``` 63 | $ screen -S [screen_name] 64 | ``` 65 | 66 | You can pick your own "screen_name". 67 | 68 | Then, start your job inside the screen, and if you want to keep it running even after you have logged out from ssh press Ctrl+a+d. 69 | 70 | To go into your screen again, type 71 | 72 | ``` 73 | $ screen -R [screen_name] 74 | ``` 75 | 76 | If you have forgotten your screen name: 77 | 78 | 79 | ``` 80 | $ screen -ls 81 | ``` 82 | 83 | # Sources 84 | 85 | [1] T. J. Richardson, M. A. Shokrollahi and R. L. Urbanke, "Design of capacity-approaching irregular low-density parity-check codes," in IEEE Transactions on Information Theory, vol. 47, no. 2, pp. 619-637, Feb 2001 [https://ieeexplore.ieee.org/document/910578](https://ieeexplore.ieee.org/document/910578) 86 | 87 | 88 | [2] Chih-Chun Wang, S. R. Kulkarni and H. V. Poor, "Density evolution for asymmetric memoryless channels," in IEEE Transactions on Information Theory, vol. 51, no. 12, pp. 4216-4236, Dec. 2005 [https://arxiv.org/pdf/cs/0509014.pdf](https://arxiv.org/pdf/cs/0509014.pdf) 89 | -------------------------------------------------------------------------------- /density_evolution_ga_python/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lcrypto/Density-Evolution-AWGN/b8acdd91dc6e6e352b4abb9ae73eaaa71c62b89e/density_evolution_ga_python/__init__.py -------------------------------------------------------------------------------- /density_evolution_ga_python/config.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | import yaml 3 | 4 | config_file = "config.yml" 5 | with open(config_file, "r") as ymlfile: 6 | cfg = yaml.safe_load(ymlfile) 7 | -------------------------------------------------------------------------------- /density_evolution_ga_python/config.yml: -------------------------------------------------------------------------------- 1 | run_id: "discrete_test2" 2 | n_processes: 4 # number of process to be used for multiprocessing. Only need if running parallel scripts 3 | density_evolution: 4 | Np: 10 # number of individuals in population 5 | generations: 1000 # number of generations. 6 | n_grid: 2048 # number of bins in pdf 7 | min_rber: 0.0001 # lowest rber in search interval (>=0.001) 8 | max_rber: 0.059 # highest rber in search interval (<0.5) 9 | de_iter: 50 # max number of iterations to perform on density evolution 10 | de_tol: 5e-2 # The floor that has to be reached to determine when density evolution has succeeded (rber*de_tol). 11 | is_converged_tol: 1e-15 # Difference between itererations to determine when converged 12 | bs_tol: 1e-4 # the precisision of the bisection search algorithm 13 | algorithm: "ga_discrete_parallel" # choose between "ga_discrete", "ga_continuous", "ga_discrete_parallel" or "ga_continuous_parallel" 14 | load_population: False # if previous training has been done, one can start from that by setting to True 15 | save_interval: 1 # how many generations that should pass before saving population 16 | print_terminal: True # if set to true the log will be outputed in terminal. Otherwise written to log/log.txt 17 | dmc_file: "../compute_dmc/data/2_05_AWGN.csv" # file from compute_dmc calculation 18 | ga_continuous: 19 | R: 0.87671232876 # code rate 20 | F: 0.5 # mutation variable. Usually in interval [0.1,1]. 21 | Cr: 0.7 # recombination probability, [0,1]. 22 | dv: 5 # max variable node edge-perspective degree 23 | dc: 20 # max check node edge-perspective degree 24 | ga_discrete: 25 | n_vn: 73 26 | n_cn: 9 27 | p_vertical: 0.3 28 | p_horizontal: 0.3 29 | p_mutation: 0.1 30 | -------------------------------------------------------------------------------- /density_evolution_ga_python/de_testing.py: -------------------------------------------------------------------------------- 1 | #%% 2 | import de_utils 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | 6 | #%% 7 | 8 | condition1 = False 9 | condition2 = True 10 | n_cn = 9 11 | n_vn = 73 12 | 13 | while not condition1 and condition2: 14 | 15 | proto = np.zeros((n_cn, n_vn), int) 16 | for j in range(n_vn): 17 | k = np.random.choice(n_cn, 2, replace=False) 18 | proto[k, j] = 1 19 | 20 | cn_degrees = np.sum(proto, 0) 21 | vn_degrees = np.sum(proto, 1) 22 | 23 | condition1 = np.all(cn_degrees >= 2) and np.all(vn_degrees >= 2) 24 | condition2 = np.all(cn_degrees <= 25) 25 | 26 | #%% 27 | if condition1 and condition2: 28 | rho_node = np.bincount(vn_degrees)[1:] 29 | rho_edge = np.arange(1, len(rho_node)+1) * rho_node / \ 30 | np.sum(np.arange(1, len(rho_node)+1) * rho_node) 31 | lam_node = np.bincount(cn_degrees)[1:] 32 | lam_edge = np.arange(1, len(lam_node)+1) * lam_node / \ 33 | np.sum(np.arange(1, len(lam_node)+1) * lam_node) 34 | 35 | #%% 36 | def eval(rber, rho_edge, lam_edge): 37 | plot = False 38 | 39 | f_grid, g_grid, pdf = de_utils.init_pdf(rber, 4096, 60) 40 | cdf = de_utils.to_cdf(pdf) 41 | 42 | if plot: 43 | plt.plot(f_grid, cdf) 44 | plt.show() 45 | 46 | result = de_utils.symmetric_density_evolution( 47 | cdf, f_grid, g_grid, rho_edge, lam_edge, tol=rber*0.05, plot=False, prnt=True) 48 | 49 | return result 50 | 51 | 52 | def bisection_search(min, max, rho_edge, lam_edge, tol=0.0001): 53 | while max - min > tol: 54 | x = (min + max)/2 55 | result = eval(x, rho_edge, lam_edge) 56 | 57 | if result == 0: 58 | min = x 59 | elif result > 0: 60 | max = x 61 | else: 62 | raise Exception 63 | 64 | return (min + max)/2 65 | 66 | bisection_search(0.005, 0.05, rho_edge, lam_edge) 67 | 68 | #%% 69 | rber = 0.015 70 | f_grid, g_grid, pdf = de_utils.init_pdf(rber, n_grid=4096, llr_max=30) 71 | cdf = de_utils.to_cdf(pdf) 72 | 73 | de_utils.symmetric_density_evolution(cdf, f_grid, g_grid, rho_edge, lam_edge, n_iter=50, tol=1e-4, plot=True, prnt=True) 74 | # %% 75 | rber = 0.035 76 | f_grid, g_grid, pdf = de_utils.init_pdf(rber, n_grid=1024*4, llr_max=20) 77 | cdf = de_utils.to_cdf(pdf) 78 | 79 | de_utils.symmetric_density_evolution(cdf, f_grid, g_grid, rho_edge, lam_edge, n_iter=50, tol=1e-6, plot=True, prnt=True) 80 | 81 | # %% 82 | -------------------------------------------------------------------------------- /density_evolution_ga_python/de_utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file contains methods for a numeric discretized implementation of density evolution for a general distribution. 3 | 4 | Sources: 5 | https://arxiv.org/pdf/cs/0509014.pdf [1] 6 | https://ieeexplore.ieee.org/abstract/document/910578?casa_token=27RtOEW11OcAAAAA:OX_XwVvok1YSH5PgL930MjWe1a1MySsUdVvu_CCVeIWA3X2m9AwPTN9MR6BS7gDfqQuq_U8o0A [2] 7 | 8 | """ 9 | 10 | from threading import Thread 11 | import matplotlib.pyplot as plt 12 | from scipy.stats import norm 13 | import numpy as np 14 | import scipy.signal as sp 15 | import pandas as pd 16 | import os 17 | import sys 18 | sys.path.insert( 19 | 0, '/home/fredrikblomgren/CAS/MasterThesis/ldpc-investigation-master-thesis/python-files') 20 | 21 | 22 | global data, cfg_de, cfg_cont, cfg_disc, run_id 23 | data = None 24 | 25 | def set_cfg(cfg): 26 | global cfg_de, cfg_cont, cfg_disc, run_id 27 | cfg_de = cfg.get('density_evolution') 28 | cfg_cont = cfg_de.get('ga_continuous') 29 | cfg_disc = cfg_de.get('ga_discrete') 30 | run_id = cfg.get('run_id') 31 | 32 | def to_cdf(pdf): 33 | """Returns the discrete pdf from a given cdf""" 34 | return np.cumsum(pdf) 35 | 36 | 37 | def to_pdf(cdf): 38 | """Returns the discrete pdf from a given cdf""" 39 | cdf = np.hstack((0, cdf, 1)) 40 | pdf = cdf[1:] - cdf[:-1] 41 | return pdf[:-1] 42 | 43 | 44 | def convolution_pad(x, final_size): 45 | """Returns the given array padded to at least double the final_length to avoid circular convolution, rounded to the nearest power of two""" 46 | nearest_power = np.ceil(np.log2(final_size)) 47 | padding = int(2**nearest_power - x.size) 48 | x = np.pad(x, (0, padding)) 49 | 50 | return x 51 | 52 | 53 | def gamma(F, F_grid, G_grid): 54 | """ 55 | Given a discrete stochastic variable f defined by a cdf with probabilities F for each value on F_grid, 56 | calculates the cdf of the transformed variable 57 | g = gamma(f) 58 | with gamma defined as in [1]. 59 | Because G has to be an equidistant grid for numeric purposes, this creates a small quantization error. 60 | """ 61 | zero_index = F.size//2 62 | F_step = abs(F_grid[1] - F_grid[0]) 63 | 64 | G0_indices = np.floor(-np.log(np.tanh(G_grid/2)) / F_step) 65 | G0_indices = np.clip(G0_indices, 0, zero_index - 1).astype(int) 66 | G0 = 1 - F.take(G0_indices + zero_index) 67 | 68 | G1_indices = np.floor(np.log(np.tanh(G_grid/2)) / F_step) 69 | G1_indices = np.clip(G1_indices, -zero_index, -1).astype(int) 70 | G1 = F.take(G1_indices + zero_index) 71 | 72 | return np.stack((G0, G1)) 73 | 74 | 75 | def gamma_inv(G, F_grid, G_grid): 76 | """ 77 | Given a discrete stochastic variable g defined by a 2 dimensional cdf with probabilities G for each value on (GF(2) x G_grid), 78 | calculates the cdf of the transformed variable 79 | f = gamma^-1(g) 80 | with gamma^-1 defined as the inverse of gamma in [2]. 81 | """ 82 | zero_index = F_grid.size//2 83 | G_step = abs(G_grid[1] - G_grid[0]) 84 | 85 | F_neg_indices = np.floor(-np.log(np.tanh(-F_grid[:zero_index]/2)) / G_step) 86 | F_neg_indices = np.clip(F_neg_indices, 0, G[1, :].size-1).astype(int) 87 | F_neg = G[1, :].take(F_neg_indices) 88 | 89 | f_0 = G[1, -1] 90 | 91 | F_pos_indices = np.floor( 92 | -np.log(np.tanh(F_grid[zero_index+1:]/2)) / G_step) 93 | F_pos_indices = np.clip(F_pos_indices, 0, G[0, :].size-1).astype(int) 94 | F_pos = 1 - G[0, :].take(F_pos_indices) 95 | 96 | return np.hstack((F_neg, f_0, F_pos)) 97 | 98 | 99 | # def rho(x, coeffs): 100 | # """ 101 | # """ 102 | # final_size = (x[0, :].size - 1)*len(coeffs) + 1 103 | # dx0, dx1 = to_pdf(x[0, :]), to_pdf(x[1, :]) 104 | # x0, x1 = convolution_pad( 105 | # x[0, :], final_size), convolution_pad(x[1, :], final_size) 106 | # dx0, dx1 = convolution_pad( 107 | # dx0, final_size), convolution_pad(dx1, final_size) 108 | 109 | # x0_ft, x1_ft = np.fft.fft(x0), np.fft.fft(x1) 110 | # dx0_ft, dx1_ft = np.fft.fft(dx0), np.fft.fft(dx1) 111 | # y0_ft, y1_ft = np.zeros(x0.shape, complex), np.zeros(x1.shape, complex) 112 | 113 | # for coeff in coeffs[1:]: 114 | # x0_ft, x1_ft = x0_ft*dx0_ft + x1_ft*dx1_ft, \ 115 | # x0_ft*dx1_ft + x1_ft*dx0_ft 116 | # y0_ft, y1_ft = y0_ft + coeff * x0_ft, y1_ft + coeff * x1_ft 117 | 118 | # y = np.stack((np.abs(np.fft.ifft(y0_ft)[:final_size]), np.abs( 119 | # np.fft.ifft(y1_ft)[:final_size]))) 120 | # y[0, np.argmax(y[0, :]):] = np.max(y[0, :]) 121 | # y[1, np.argmax(y[1, :]):] = np.max(y[1, :]) 122 | 123 | # return y 124 | 125 | 126 | # def lambd(x, coeffs): 127 | # """ 128 | # """ 129 | # final_size = (x.size - 1)*len(coeffs) + 1 130 | # dx = to_pdf(x) 131 | 132 | # x = convolution_pad(x, final_size) 133 | # dx = convolution_pad(dx, final_size) 134 | 135 | # x_ft = np.fft.fft(x) 136 | # dx_ft = np.fft.fft(dx) 137 | # y_ft = np.zeros(x.size, complex) 138 | 139 | # for coeff in coeffs[1:]: 140 | # x_ft = x_ft * dx_ft 141 | # y_ft += coeff*x_ft 142 | 143 | # y = np.abs(np.fft.ifft(y_ft)[:final_size]) 144 | # y[np.argmax(y):] = 1 145 | # return y 146 | 147 | 148 | # def conv(x, x0): 149 | # """ 150 | # """ 151 | # dx = to_pdf(x) 152 | # final_size = x.size + x0.size - 1 153 | 154 | # x0 = convolution_pad(x0, final_size) 155 | # dx = convolution_pad(dx, final_size) 156 | 157 | # y = np.abs(np.fft.ifft(np.fft.fft(dx)*np.fft.fft(x0))[:final_size]) 158 | # y[np.argmax(y):] = 1 159 | # return y 160 | 161 | 162 | def conv(x, x0): 163 | """ 164 | Naive implementation of conv using sp.convolve, kept for reference. 165 | """ 166 | x0 = np.pad(x0, (x0.size, x0.size), constant_values=(0, 1)) 167 | x = np.pad(x, (x.size, x.size), constant_values=(0, 1)) 168 | dx = to_pdf(x) 169 | 170 | y = sp.convolve(x0, dx) 171 | 172 | current_size = y.size 173 | y = y[:np.argmax(y)+1] 174 | y = np.pad(y, (0, current_size-y.size), constant_values=y.max()) 175 | 176 | y = y[y.size//4: -y.size//4] 177 | return y 178 | 179 | 180 | def lambd(x, coeffs): 181 | """ 182 | Naive implementation of lambd using sp.convolve 183 | """ 184 | x = np.pad(x, (x.size//2, x.size//2), constant_values=(0, 1)) 185 | dx = to_pdf(x) 186 | final_size = x.size * len(coeffs) 187 | 188 | y = np.zeros(final_size) 189 | for coeff in coeffs[1:]: 190 | x = sp.convolve(x, dx) 191 | current_size = x.size 192 | 193 | x = x[:np.argmax(x)+1] 194 | padding1 = int(np.ceil((-current_size+final_size)/2)) 195 | padding2 = int(np.floor((-current_size+final_size)/2)) 196 | padding3 = int((current_size-x.size)) 197 | x = np.pad(x, (padding1, padding2 + padding3), constant_values=(0, 1)) 198 | 199 | y += coeff*x 200 | x = x[padding1:-padding2] 201 | 202 | y = y[y.size//4:-y.size//4] 203 | return y 204 | 205 | 206 | def rho(x, coeffs): 207 | """ 208 | 209 | """ 210 | dx = np.stack((to_pdf(x[0, :]), to_pdf(x[1, :]))) 211 | final_size = x.size//2 * len(coeffs) 212 | 213 | x0 = x[0, :] 214 | x1 = x[1, :] 215 | y = np.zeros((2, final_size)) 216 | for coeff in coeffs[1:]: 217 | x0, x1 = sp.convolve(x0, dx[0, :]) + sp.convolve(x1, dx[1, :]),\ 218 | sp.convolve(x1, dx[0, :]) + sp.convolve(x0, dx[1, :]) 219 | current_size = x.size//2 220 | 221 | x0 = x0[:np.argmax(x0)+1] 222 | x1 = x1[:np.argmax(x1)+1] 223 | x0 = np.pad(x0, (0, final_size-x0.size), constant_values=x0.max()) 224 | x1 = np.pad(x1, (0, final_size-x1.size), constant_values=x1.max()) 225 | y[0, :] += coeff * x0 226 | y[1, :] += coeff * x1 227 | 228 | x0 = x0[:current_size] 229 | x1 = x1[:current_size] 230 | 231 | return y 232 | 233 | 234 | def init_pdf(rber, n_grid=512, llr_max=15): 235 | """Returns density values of a DMC pdf and its grid in F and G from a look up table.""" 236 | mu1 = -1 237 | mu2 = 1 238 | 239 | # Load database if not loaded 240 | global data 241 | file_path = cfg_de.get("dmc_file") 242 | if data is None: 243 | data = np.loadtxt(file_path, delimiter=" ", skiprows=1) 244 | 245 | # Interpolate values on rber 246 | rber_step = data[1, 0] - data[0, 0] 247 | rber_index = (rber - data[0, 0])/rber_step 248 | index0 = int(np.floor(rber_index)) 249 | index1 = int(np.ceil(rber_index)) 250 | values = data[index0] + \ 251 | (data[index1] - data[index0]) * (rber_index - index0) 252 | 253 | # Set values 254 | sigma = values[1] 255 | sigma1 = values[2] 256 | sigma2 = values[3] 257 | 258 | if len(values) == 8: 259 | thresholds = np.array([values[5]]) 260 | llrs = values[6:] 261 | elif len(values) == 12: 262 | thresholds = values[5:8] 263 | llrs = values[8:] 264 | else: 265 | raise Exception("Invalid dmc-file") 266 | 267 | # Calculate probabilities 268 | p0 = norm.cdf(np.append(thresholds, np.inf), mu2, sigma2) 269 | p0 = np.ediff1d(p0, to_begin=p0[0]) 270 | #p1 = 1 - norm.cdf(np.array(thresholds), mu1, sigma1) 271 | #p1 = np.ediff1d(p1, to_begin=p1[0]) 272 | p1 = norm.cdf(np.append(thresholds,np.inf),mu1,sigma1) 273 | p1 = np.ediff1d(p1, to_begin=p1[0]) 274 | 275 | # Symmetrize probabilities 276 | # Source: https://books.google.se/books?hl=en&lr=&id=ZJrZPObOe60C&oi=fnd&pg=PR13&dq=modern+coding+theory+urbanke&ots=WogyOo3ipu&sig=qKPObOLJNFbt8_4h9NKPd-bzwo4&redir_esc=y#v=onepage&q=modern%20coding%20theory%20urbanke&f=false 277 | p1 = np.flip(p1) 278 | p_sym = (p0+p1)/2 279 | 280 | step = 2*llr_max / n_grid 281 | bins = np.round(-llrs / step) + n_grid//2 282 | bins = np.clip(bins, 0, n_grid-1) 283 | 284 | x1 = np.linspace(-llr_max, llr_max, n_grid, endpoint=False) 285 | y = np.zeros(x1.shape) 286 | np.put(y, bins.astype(int), p_sym) 287 | 288 | f_step = abs(x1[1] - x1[0]) 289 | max_val = -np.log(np.tanh(f_step)) 290 | x2 = np.linspace(0, max_val, n_grid) 291 | 292 | return x1, x2, y 293 | 294 | 295 | def compute_cbp(pdf, f_grid,is_zero): 296 | y = np.exp(-f_grid/2)*pdf 297 | ber = np.sum(pdf[:int(f_grid.size/2)]) 298 | cbp_avg = np.sum(y) 299 | is_valid = (2*ber <= cbp_avg and cbp_avg <= 2*np.sqrt(ber*(1-ber))) 300 | message = f"CBP should be bounded by 2*ber<= CBP <= 2*sqrt(ber*(1-ber)). CBP = {cbp_avg}. BER = {ber}." 301 | #assert is_valid, message 302 | # if not is_valid: 303 | # message = f"CBP should be bounded by 2*ber<= CBP <= 2*sqrt(ber*(1-ber)). CBP = {cbp_avg}. BER = {ber}." 304 | # print(message) 305 | #plt.plot(f_grid, y) 306 | # plt.show() 307 | return cbp_avg 308 | 309 | 310 | def poly_eval(poly, x): 311 | # sum = 0 312 | # for i, coeff in enumerate(poly): 313 | # sum += coeff*x**i 314 | # 315 | # return sum 316 | return np.sum(poly*x**(np.arange(poly.size))) 317 | 318 | 319 | def compute_eps(lam, rho, r): 320 | lam_2 = lam[1] 321 | rho_prime = rho[1:]*np.arange(1, rho.size) 322 | 323 | rho_prime_1 = poly_eval(rho_prime, 1) 324 | f1 = lam_2*rho_prime_1*r 325 | 326 | if f1 < 1: 327 | if np.abs(lam_2-1) > 1e-1: 328 | f2 = poly_eval(lam, rho_prime_1)*r 329 | eps = (1-f1)/(f2-f1) 330 | if eps > r or eps < 0: 331 | eps = 1 332 | else: 333 | eps = -1 334 | else: 335 | eps = -1 336 | return eps 337 | 338 | 339 | def compute_threshold(pdf, f_grid, lam, rho): 340 | # Based on "C. Stability" section of: 341 | # https://arxiv.org/pdf/cs/0509014.pdf 342 | r = compute_cbp(pdf, f_grid,True) 343 | 344 | eps = compute_eps(lam, rho, r) 345 | 346 | return eps 347 | 348 | 349 | def symmetric_density_evolution(cdf, f_grid, g_grid, rho_coeffs, lambda_coeffs, tol, plot=False, prnt=False): 350 | global cfg_de 351 | n_iter = cfg_de.get("de_iter") 352 | if plot: 353 | fig, axes = plt.subplots(3, 2) 354 | 355 | # assert np.sum(rho_coeffs[1:]) == 1, "Invalid rho polynom" 356 | # assert np.sum(lambda_coeffs[1:]) == 1, "Invalid lambda polynom" 357 | 358 | pl = cdf 359 | p0 = cdf 360 | pl_old = 0 361 | i = 0 362 | diff = np.inf 363 | error = np.inf 364 | while True: 365 | # Compute pdf to determine convergence to zero 366 | pdf_l = to_pdf(pl) 367 | pdf_l = np.where(pdf_l > 1e-10, pdf_l, 0) # Numerical thing 368 | prob_l = np.sum(pdf_l) 369 | 370 | is_valid = (np.abs(1-prob_l)<1e-5) 371 | message = f"Total probability has to sum to one with tolerance 1e-5. Total probability = {prob_l:.6f}." 372 | assert is_valid, message 373 | 374 | # Compute correct f_grid 375 | if i == 0 or i == 1: 376 | coeff = pl.size/f_grid.size 377 | start = coeff*f_grid[0] 378 | step = (f_grid[-1]-f_grid[0])/(f_grid.size-1) 379 | f_grid_l = np.arange(start, -start, step) 380 | 381 | # Check convergence 382 | cbp = compute_cbp(pdf_l, f_grid_l,False) 383 | is_zero = (cbp < tol) 384 | max_iter = (i == n_iter) 385 | is_converged = False 386 | 387 | if is_zero: 388 | error = 0 389 | if prnt: 390 | print("Is zero") 391 | if is_converged and prnt: 392 | print("Converged") 393 | if max_iter and prnt: 394 | print("MAX") 395 | if is_zero or is_converged or max_iter: 396 | if error < 0: 397 | me = "Tjabba" 398 | if plot: 399 | plt.show() 400 | 401 | return error 402 | 403 | is_zero = (cbp < tol) 404 | 405 | # Perform one iteration of density evolution 406 | x1 = gamma(pl, f_grid, g_grid) 407 | x2 = rho(x1, rho_coeffs) 408 | x3 = gamma_inv(x2, f_grid, g_grid) 409 | x4 = lambd(x3, lambda_coeffs) 410 | pl = conv(x4, p0) 411 | pl[np.argwhere(pl<1e-16)] = 0 # Numerical thing 412 | 413 | diff = sum((pl_old - pl)**2) 414 | pl_old = pl 415 | 416 | zero_index = pl.size//2 417 | error = pl[zero_index] 418 | 419 | if plot: 420 | axes[0, 0].plot(x1[0, :]) 421 | axes[0, 0].plot(x1[1, :]) 422 | axes[0, 1].plot(x2[0, :]) 423 | axes[0, 1].plot(x2[1, :]) 424 | axes[1, 0].plot(x3) 425 | axes[1, 1].plot(x4) 426 | axes[2, 0].plot(pl) 427 | axes[2, 1].scatter(i, error) 428 | 429 | is_converged = False #(diff < float(cfg_de.get("is_converged_tol"))) 430 | is_zero = (error < tol) 431 | max_iter = (i == n_iter) 432 | 433 | if is_zero: 434 | error = 0 435 | if prnt: 436 | print("Is zero", error) 437 | if is_converged and prnt: 438 | print("Converged", error) 439 | if max_iter and prnt: 440 | print("MAX", error) 441 | if is_zero or is_converged or max_iter: 442 | if plot: 443 | plt.show() 444 | 445 | return error 446 | 447 | i += 1 448 | 449 | 450 | def eval(rber, rho_edge, lam_edge): 451 | plot = False 452 | n_grid = cfg_de.get("n_grid") 453 | 454 | global X1, X2 455 | f_grid, g_grid, pdf = init_pdf(rber, X1, X2) 456 | cdf = to_cdf(pdf) 457 | if plot: 458 | plt.plot(f_grid, cdf) 459 | plt.show() 460 | 461 | eps = compute_threshold(pdf, f_grid, lam_edge, rho_edge) 462 | if eps == -1: # will not converge to zero 463 | result = 1 464 | elif eps == 1: # will converge to zero 465 | result = 0 466 | else: 467 | result = symmetric_density_evolution( 468 | cdf, f_grid, g_grid, rho_edge, lam_edge, tol=eps, plot=False) 469 | 470 | return result 471 | 472 | 473 | def bisection_search(min, max, rho_edge, lam_edge): 474 | global cfg_de 475 | tol=float(cfg_de.get("bs_tol")) 476 | 477 | while max - min > tol: 478 | x = (min + max)/2 479 | result = eval(x, rho_edge, lam_edge) 480 | 481 | if result == 0: 482 | min = x 483 | elif result > 0: 484 | max = x 485 | else: 486 | error_message = f"The probability from density evolution is negative ({result})." 487 | raise Exception(error_message) 488 | 489 | return (min + max)/2 490 | 491 | 492 | def convert_edge_to_node(p_edge): 493 | p_node = p_edge/(np.arange(1, len(p_edge)+1) * 494 | np.sum(1/np.arange(1, len(p_edge)+1)*p_edge)) 495 | return p_node 496 | 497 | 498 | def set_continuous_params(start_pt, const_mat): 499 | global x_0, C_c 500 | x_0 = start_pt 501 | C_c = const_mat 502 | 503 | 504 | def best_individual_discrete(best_ind): 505 | cn_degrees = np.sum(best_ind, 0) 506 | vn_degrees = np.sum(best_ind, 1) 507 | rho_node = np.bincount(vn_degrees)[1:] 508 | lam_node = np.bincount(cn_degrees)[1:] 509 | rho_node = rho_node/np.sum(rho_node) 510 | lam_node = lam_node/np.sum(lam_node) 511 | return lam_node, rho_node 512 | 513 | 514 | def best_individual_continous(best_ind): 515 | global x_0, C_c 516 | x = x_0 + np.matmul(C_c, best_ind) 517 | dc = cfg_cont.get("dc") 518 | dv = cfg_cont.get("dv") 519 | rho_edge = x[:dc] 520 | lam_edge = x[dc:] 521 | lam_node = convert_edge_to_node(lam_edge) 522 | rho_node = convert_edge_to_node(rho_edge) 523 | return lam_node, rho_node 524 | 525 | 526 | def save_params(): 527 | algorithm = cfg_de.get("algorithm") 528 | data = { 529 | 530 | "Np": [cfg_de.get("Np")], 531 | "generations": [cfg_de.get("generations")], 532 | "n_grid": [cfg_de.get("n_grid")], 533 | "algorithm": [algorithm] 534 | } 535 | 536 | if algorithm == "ga_continuous" or algorithm == "ga_continuous_parallel": 537 | data_c = { 538 | "R": [cfg_cont.get("R")], 539 | "F": [cfg_cont.get("F")], 540 | "Cr": [cfg_cont.get("Cr")], 541 | "dv": [cfg_cont.get("dv")], 542 | "dc": [cfg_cont.get("dc")] 543 | } 544 | data.update(data_c) 545 | 546 | if algorithm == "ga_discrete" or algorithm == "ga_discrete_parallel": 547 | data_d = { 548 | "n_vn": [cfg_disc.get("n_vn")], 549 | "n_cn": [cfg_disc.get("n_cn")], 550 | "p_vertical": [cfg_disc.get("p_vertical")], 551 | "p_horizontal": [cfg_disc.get("p_horizontal")], 552 | "p_mutation": [cfg_disc.get("p_mutation")] 553 | } 554 | data.update(data_d) 555 | 556 | df = pd.DataFrame.from_dict(data) 557 | 558 | os.makedirs('data/', exist_ok=True) 559 | fname = "data/" + run_id + "_de_params.csv" 560 | df.to_csv(fname) 561 | 562 | 563 | def save_population(population, fitness, generation, best_idx, best_rber, algorithm): 564 | if algorithm == "discrete": 565 | lam_node, rho_node = best_individual_discrete( 566 | population[best_idx, :, :]) 567 | elif algorithm == "continuous": 568 | lam_node, rho_node = best_individual_continous(population[:, best_idx]) 569 | 570 | fname = "data/" + run_id + ".npz" 571 | with open(fname, 'wb') as f: 572 | np.savez(f, population=population, fitness=fitness, generation=np.array([generation]), best_idx=np.array( 573 | [best_idx]), best_rber=np.array([best_rber]), lam_node=lam_node, rho_node=rho_node) 574 | 575 | 576 | def log(txt, options): 577 | fname = "data/log_" + run_id + ".txt" 578 | with open(fname, options) as f: 579 | f.write(txt+"\n") 580 | 581 | # %% 582 | -------------------------------------------------------------------------------- /density_evolution_ga_python/density_evolution.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file implements the full asymmetric density evolution algorithm for optimisng on the discritized A-BIAWGN channel. 3 | 4 | Sources: 5 | https://arxiv.org/pdf/cs/0509014.pdf 6 | https://arxiv.org/pdf/2001.01249.pdf 7 | 8 | """ 9 | import ga_discrete as ga_d 10 | import ga_continuous as ga_c 11 | #import ga_discrete_parallel as ga_d_p 12 | #import ga_continuous_parallel as ga_c_p 13 | import matplotlib.pyplot as plt 14 | import numpy as np 15 | import time 16 | from config import cfg 17 | 18 | 19 | np.seterr(divide='ignore') 20 | cfg_de = cfg.get('density_evolution') 21 | 22 | 23 | def main(): 24 | algorithm = cfg_de.get("algorithm") 25 | if algorithm == "ga_continuous": 26 | ga_c.ga_continous() 27 | elif algorithm == "ga_discrete": 28 | ga_d.ga_discrete() 29 | elif algorithm == "ga_continuous_parallel": 30 | ga_c_p.ga_continous_parallel() 31 | elif algorithm == "ga_discrete_parallel": 32 | ga_d_p.ga_discrete_parallel() 33 | else: 34 | raise Exception("No valid algorithm chosen.") 35 | 36 | 37 | if __name__ == "__main__": 38 | main() 39 | -------------------------------------------------------------------------------- /density_evolution_ga_python/ga_continuous.py: -------------------------------------------------------------------------------- 1 | # %% Imports and variables 2 | from time import process_time 3 | import numpy as np 4 | from scipy.optimize import linprog 5 | from scipy.linalg import null_space 6 | import de_utils as de_u 7 | import random 8 | 9 | 10 | 11 | from config import cfg 12 | cfg_de = cfg.get('density_evolution') 13 | cfg_cont = cfg_de.get('ga_continuous') 14 | run_id = cfg.get("run_id") 15 | 16 | def start_point(R, dv, dc): 17 | # lam and rho are assumed to begin at degree 2 18 | k = 1/np.arange(2, dc+1) 19 | i = 1/np.arange(2, dv+1) 20 | 21 | # C is the constraint matrix. 22 | # 1st row: code rate constraint 23 | # 2nd row: coefficients of rho should sum to 1 24 | # 3rd row: coefficients of lam should sum to 1 25 | # lb: coefficients of rho and lam should be positive (>0) 26 | c1 = np.concatenate((k, -(1-R)*i)) 27 | c2 = np.concatenate((np.ones(dc-1), np.zeros(dv-1))) 28 | c3 = np.concatenate((np.zeros(dc-1), np.ones(dv-1))) 29 | C = np.stack((c1, c2, c3)) 30 | 31 | d = np.array([[0], [1], [1]]) 32 | lb = np.zeros((dv+dc-2, 1)) 33 | f = np.ones((dv+dc-2, 1)) 34 | 35 | sol = linprog(f, A_ub=None, b_ub=None, A_eq=C, 36 | b_eq=d, method='interior-point') 37 | x_0 = sol.x 38 | 39 | return C, x_0 40 | 41 | 42 | def add_one_degree(C_c, x_0, dc): 43 | 44 | # %% Add degree 1 45 | x_0 = np.concatenate(([0], x_0[:dc-1], [0], x_0[dc-1:])) 46 | D = np.size(C_c, 1) 47 | z_vec = np.zeros((1, D)) 48 | C_c = np.vstack((z_vec, C_c[:dc-1, :], z_vec, C_c[dc-1:, :])) 49 | 50 | return C_c, x_0 51 | 52 | # Differential evolution help functions 53 | 54 | 55 | def compute_x(x_0, C_c, eta): 56 | return x_0 + np.matmul(C_c, eta) 57 | 58 | 59 | def poly_eval(p, x): 60 | exp = np.arange(0, p.size) 61 | return p*x**exp 62 | 63 | 64 | def compute_fitness(x, dc): 65 | fitness = 0 66 | in_domain = True 67 | for xi in x: 68 | if xi < 0: 69 | fitness += -100 + 10*xi 70 | in_domain = False 71 | 72 | if fitness == 0: 73 | rho = x[:dc] 74 | lam = x[dc:] 75 | min = cfg_de.get("min_rber") 76 | max = cfg_de.get("max_rber") 77 | result = de_u.bisection_search( 78 | min, max, rho, lam) 79 | fitness = 100*result 80 | 81 | return fitness, in_domain 82 | 83 | 84 | def differential_evolution(C_c, x_0, dc): 85 | # Np: number of individuals in population 86 | # gens: Number of generations. Around 5000 87 | # F: mutation variable. Usually in interval [0.1,1]. 88 | # Cr: recombination probability, [0,1]. 89 | 90 | Np = cfg_de.get('Np') 91 | gens = cfg_de.get('generations') 92 | F = cfg_cont.get('F') 93 | Cr = cfg_cont.get('Cr') 94 | D = np.size(C_c, 1) 95 | load_population = cfg_de.get("load_population") 96 | de_u.save_params() 97 | 98 | code_rate = cfg_cont.get("R") 99 | dv = cfg_cont.get("dv") 100 | dc = cfg_cont.get("dc") 101 | 102 | print_terminal = cfg_de.get("print_terminal") 103 | header = f""" 104 | Running ga_continuous.py 105 | =================================================================== 106 | Optimizing code ensamble through differential evolution algorithm. 107 | Code rate: {code_rate:.2f}. 108 | Number of individuals: {Np}. 109 | Number of generations: {gens}. 110 | Max variable node degree: {dv}. 111 | Max check node degree: {dc}. 112 | Parameter settings: F = {F}, Cr = {Cr} 113 | ------------------------------------------------------------------- 114 | """ 115 | if print_terminal: 116 | print(header) 117 | else: 118 | de_u.log(header,'w') 119 | 120 | # x = x_0 + C_c*eta 121 | # Initialize population 122 | if load_population: 123 | fname = "data/" + run_id + ".npz" 124 | data = np.load(fname) 125 | eta_Np = data["population"] 126 | fitness_Np = data["fitness"] 127 | g_start = int(data["generation"][0])+1 128 | dim_0 = np.size(fitness_Np, axis=0) 129 | if gens != np.size(fitness_Np, axis=0): 130 | fitness_Np_new = np.zeros((gens, Np)) 131 | fitness_Np_new[:dim_0] = fitness_Np 132 | fitness_Np = fitness_Np_new 133 | else: 134 | eta_Np = np.random.rand(D, Np) 135 | fitness_Np = np.zeros((gens,Np)) 136 | g_start = 0 137 | 138 | domain_Np = np.full(Np, False) 139 | 140 | try: 141 | # Optimize population over generations 142 | t1_start = process_time() 143 | for g in range(g_start,gens): 144 | 145 | u_Np = np.copy(eta_Np) 146 | for i in range(Np): 147 | # Generate selection parameters according to algorithm 148 | r0 = random.randint(0, Np-1) 149 | r1 = random.randint(0, Np-1) 150 | r2 = random.randint(0, Np-1) 151 | jrand = random.randint(0, D-1) 152 | while (r0 == i): 153 | r0 = random.randint(0, Np-1) 154 | while (r1 == i or r1 == r0): 155 | r1 = random.randint(0, Np-1) 156 | while (r2 == i or r2 == r0 or r2 == r1): 157 | r2 = random.randint(0, Np-1) 158 | 159 | # Mutation and cross over 160 | cr_arr = np.random.rand(D) 161 | for j in range(D): 162 | if (cr_arr[j] < Cr or j == jrand): 163 | u_Np[j, i] = eta_Np[j, r0] + F * \ 164 | (eta_Np[j, r1]-eta_Np[j, r2]) 165 | 166 | # Selection 167 | if g == 0: 168 | x = compute_x(x_0, C_c, eta_Np[:, i]) 169 | fitness, in_domain = compute_fitness(x, dc) 170 | fitness_Np[g, i] = fitness 171 | domain_Np[i] = in_domain 172 | else: 173 | x = compute_x(x_0, C_c, u_Np[:, i]) 174 | fitness, in_domain = compute_fitness(x, dc) 175 | 176 | if fitness > fitness_Np[g-1, i]: 177 | eta_Np[:, i] = u_Np[:, i] 178 | fitness_Np[g, i] = fitness 179 | domain_Np[i] = in_domain 180 | else: 181 | fitness_Np[g, i] = fitness_Np[g-1, i] 182 | 183 | ave_fitness = np.sum(fitness_Np[g,:])/Np 184 | best_idx = np.argmax(fitness_Np[g,:]) 185 | 186 | # Write current status 187 | 188 | n_domain = domain_Np.sum() 189 | if n_domain != 0: 190 | rber_max = np.max(fitness_Np[g,domain_Np]) 191 | rber_min = np.min(fitness_Np[g,domain_Np]) 192 | else: 193 | rber_max = 0 194 | rber_min = 0 195 | t1_stop = process_time() 196 | status = f"{g} generations completed. Average fitness:{ave_fitness:.2f}. In domain: {n_domain}. RBER: max {rber_max:.2f}, min: {rber_min:.2f}. " 197 | if print_terminal: 198 | print(status) 199 | else: 200 | de_u.log(status,'a') 201 | 202 | if g % int(cfg_de.get("save_interval")) == 0: 203 | de_u.save_population(eta_Np, fitness_Np, g,best_idx,"continuous") 204 | 205 | status = f""" 206 | ------------------------------------------------------------------- 207 | Finished! 208 | =================================================================== 209 | """ 210 | if print_terminal: 211 | print(status) 212 | else: 213 | de_u.log(status,'a') 214 | finally: 215 | de_u.save_population(eta_Np, fitness_Np, g, best_idx, "continuous") 216 | if g < gens-1: 217 | status = f""" 218 | ------------------------------------------------------------------- 219 | Optimization interrupted. 220 | =================================================================== 221 | """ 222 | if print_terminal: 223 | print(status) 224 | else: 225 | de_u.log(status, 'a') 226 | 227 | 228 | def ga_continous(): 229 | de_u.set_cfg(cfg) 230 | 231 | R = cfg_cont.get('R') 232 | dv = cfg_cont.get('dv') 233 | dc = cfg_cont.get('dc') 234 | 235 | # x = [rho;lam] 236 | # 1. Compute an initial start point 237 | C, x_0 = start_point(R, dv, dc) 238 | 239 | # 2. Find the complement of constraint matrix. 240 | # This gives us the allowed directions to step around in 241 | C_c = null_space(C) 242 | 243 | 244 | # 3. Add degree 1 to x_0 and C_c matrix 245 | C_c, x_0 = add_one_degree(C_c, x_0, dc) 246 | de_u.set_continuous_params(x_0, C_c) 247 | 248 | # 4. Perform optimization through differential evolution 249 | differential_evolution(C_c, x_0, dc) 250 | -------------------------------------------------------------------------------- /density_evolution_ga_python/ga_continuous_parallel.py: -------------------------------------------------------------------------------- 1 | # %% Imports and variables 2 | from time import process_time 3 | import numpy as np 4 | from scipy.optimize import linprog 5 | from scipy.linalg import null_space 6 | import de_utils as de_u 7 | import random 8 | import ga_continuous as ga_c 9 | from multiprocessing import Pool, shared_memory 10 | from multiprocessing.sharedctypes import Value 11 | 12 | 13 | from config import cfg 14 | cfg_de = cfg.get('density_evolution') 15 | cfg_cont = cfg_de.get('ga_continuous') 16 | run_id = cfg.get("run_id") 17 | n_processes = cfg.get("n_processes") 18 | 19 | # Function that is parallelized through Pool in multiprocessing 20 | def de_individual(i): 21 | global eta_name, u_name, fit_name, dom_name, eta_shape, u_shape, fit_shape, dom_shape, Np, Cr, F, C_c, x_0, g_idx, dc 22 | D = np.size(C_c,1) 23 | shm_eta = shared_memory.SharedMemory(name = eta_name) 24 | shm_u = shared_memory.SharedMemory(name=u_name) 25 | shm_fit = shared_memory.SharedMemory(name=fit_name) 26 | shm_dom = shared_memory.SharedMemory(name=dom_name) 27 | 28 | eta = np.ndarray(eta_shape, dtype=np.float64, buffer=shm_eta.buf) 29 | u = np.ndarray(u_shape, dtype=np.float64, buffer=shm_u.buf) 30 | fitness = np.ndarray(fit_shape, dtype=np.float64, buffer=shm_fit.buf) 31 | domain = np.ndarray(dom_shape, dtype=bool, buffer=shm_dom.buf) 32 | 33 | g = g_idx.value 34 | 35 | # Generate selection parameters according to algorithm 36 | r0 = random.randint(0, Np-1) 37 | r1 = random.randint(0, Np-1) 38 | r2 = random.randint(0, Np-1) 39 | jrand = random.randint(0, D-1) 40 | while (r0 == i): 41 | r0 = random.randint(0, Np-1) 42 | while (r1 == i or r1 == r0): 43 | r1 = random.randint(0, Np-1) 44 | while (r2 == i or r2 == r0 or r2 == r1): 45 | r2 = random.randint(0, Np-1) 46 | 47 | # Mutation and cross over 48 | cr_arr = np.random.rand(D) 49 | for j in range(D): 50 | if (cr_arr[j] < Cr or j == jrand): 51 | u[j, i] = eta[j, r0] + F * \ 52 | (eta[j, r1]-eta[j, r2]) 53 | 54 | # Selection 55 | if g_idx.value == 0: 56 | x = ga_c.compute_x(x_0, C_c, eta[:, i]) 57 | fit, in_domain = ga_c.compute_fitness(x, dc) 58 | fitness[g, i] = fit 59 | domain[i] = in_domain 60 | else: 61 | x = ga_c.compute_x(x_0, C_c, u[:, i]) 62 | fit, in_domain = ga_c.compute_fitness(x, dc) 63 | 64 | if fit > fitness[g-1, i]: 65 | eta[:, i] = u[:, i] 66 | fitness[g, i] = fit 67 | domain[i] = in_domain 68 | else: 69 | fitness[g, i] = fitness[g-1, i] 70 | 71 | shm_eta.close() 72 | shm_u.close() 73 | shm_fit.close() 74 | shm_dom.close() 75 | 76 | 77 | # Used for initializeing multiprocessing 78 | def pool_initializer(): 79 | global eta_name, u_name, fit_name, dom_name, eta_shape, u_shape, fit_shape, dom_shape, Np, Cr, F, C_c, x_0, g_idx, dc 80 | 81 | 82 | 83 | def differential_evolution(C_c, x_0, dc): 84 | global eta_name, u_name, fit_name, dom_name, eta_shape, u_shape, fit_shape, dom_shape, Np, Cr, F, g_idx 85 | # Np: number of individuals in population 86 | # gens: Number of generations. Around 5000 87 | # F: mutation variable. Usually in interval [0.1,1]. 88 | # Cr: recombination probability, [0,1]. 89 | 90 | Np = cfg_de.get('Np') 91 | gens = cfg_de.get('generations') 92 | F = cfg_cont.get('F') 93 | Cr = cfg_cont.get('Cr') 94 | D = np.size(C_c, 1) 95 | load_population = cfg_de.get("load_population") 96 | de_u.save_params() 97 | 98 | code_rate = cfg_cont.get("R") 99 | dv = cfg_cont.get("dv") 100 | dc = cfg_cont.get("dc") 101 | 102 | print_terminal = cfg_de.get("print_terminal") 103 | header = f""" 104 | Running ga_continuous.py 105 | =================================================================== 106 | Optimizing code ensamble through differential evolution algorithm. 107 | Code rate: {code_rate:.2f}. 108 | Number of individuals: {Np}. 109 | Number of generations: {gens}. 110 | Max variable node degree: {dv}. 111 | Max check node degree: {dc}. 112 | Parameter settings: F = {F}, Cr = {Cr} 113 | ------------------------------------------------------------------- 114 | """ 115 | if print_terminal: 116 | print(header) 117 | else: 118 | de_u.log(header,'w') 119 | 120 | # x = x_0 + C_c*eta 121 | # Initialize population 122 | if load_population: 123 | fname = "data/" + run_id + ".npz" 124 | data = np.load(fname) 125 | eta_Np = data["population"] 126 | fitness_Np = data["fitness"] 127 | g_start = int(data["generation"][0])+1 128 | dim_0 = np.size(fitness_Np, axis=0) 129 | if gens != np.size(fitness_Np, axis=0): 130 | fitness_Np_new = np.zeros((gens, Np)) 131 | fitness_Np_new[:dim_0] = fitness_Np 132 | fitness_Np = fitness_Np_new 133 | else: 134 | eta_Np = np.random.rand(D, Np) 135 | fitness_Np = np.zeros((gens,Np)) 136 | g_start = 0 137 | 138 | domain_Np = np.full(Np, False) 139 | 140 | # Initialize shared_memory in multiprocessing 141 | shm_eta = shared_memory.SharedMemory(create=True, size=eta_Np.nbytes) 142 | shm_u = shared_memory.SharedMemory(create=True, size=eta_Np.nbytes) 143 | shm_fit = shared_memory.SharedMemory(create=True, size=fitness_Np.nbytes) 144 | shm_dom = shared_memory.SharedMemory(create=True, size=domain_Np.nbytes) 145 | 146 | eta = np.ndarray(eta_Np.shape, dtype=np.float64, buffer=shm_eta.buf) 147 | u = np.ndarray(eta_Np.shape, dtype=np.float64, buffer=shm_u.buf) 148 | fitness = np.ndarray(fitness_Np.shape, dtype=np.float64, buffer=shm_fit.buf) 149 | domain = np.ndarray(domain_Np.shape, dtype=bool, buffer=shm_dom.buf) 150 | 151 | eta[:] = eta_Np[:] 152 | u[:] = eta_Np[:] 153 | fitness[:] = fitness_Np[:] 154 | domain[:] = domain_Np[:] 155 | 156 | eta_name = shm_eta.name 157 | u_name = shm_u.name 158 | fit_name = shm_fit.name 159 | dom_name = shm_dom.name 160 | 161 | eta_shape = eta.shape 162 | u_shape = u.shape 163 | fit_shape = fitness.shape 164 | dom_shape = domain.shape 165 | 166 | g_idx = Value('i', g_start) 167 | 168 | # Use Pool for parallel computing 169 | pool = Pool(processes=n_processes, initializer=pool_initializer) 170 | pop_idx = range(Np) 171 | 172 | try: 173 | # Optimize population over generations 174 | t1_start = process_time() 175 | for g in range(g_start,gens): 176 | 177 | u[:] = np.copy(eta) 178 | pool.map(de_individual, pop_idx) 179 | # Equivalent to: 180 | #for i in range(Np): 181 | # de_individual(i) 182 | g_idx.value += 1 183 | 184 | ave_fitness = np.sum(fitness[g,:])/Np 185 | best_idx = np.argmax(fitness[g,:]) 186 | best_rber = np.max(fitness[g,:]) 187 | # Write current status 188 | 189 | n_domain = domain.sum() 190 | if n_domain != 0: 191 | rber_max = np.max(fitness[g,domain]) 192 | rber_min = np.min(fitness[g,domain]) 193 | else: 194 | rber_max = 0 195 | rber_min = 0 196 | t1_stop = process_time() 197 | status = f"{g} generations completed. Average fitness:{ave_fitness:.2f}. In domain: {n_domain}. RBER: max {rber_max:.2f}, min: {rber_min:.2f}." 198 | if print_terminal: 199 | print(status) 200 | else: 201 | de_u.log(status,'a') 202 | 203 | if g % int(cfg_de.get("save_interval")) == 0: 204 | de_u.save_population(eta, fitness, g, best_idx, best_rber,"continuous") 205 | 206 | status = f""" 207 | ------------------------------------------------------------------- 208 | Finished! 209 | =================================================================== 210 | """ 211 | if print_terminal: 212 | print(status) 213 | else: 214 | de_u.log(status,'a') 215 | finally: 216 | de_u.save_population(eta, fitness, g, best_idx, 217 | best_rber, "continuous") 218 | if g < gens-1: 219 | status = f""" 220 | ------------------------------------------------------------------- 221 | Optimization interrupted. 222 | =================================================================== 223 | """ 224 | if print_terminal: 225 | print(status) 226 | else: 227 | de_u.log(status, 'a') 228 | 229 | shm_eta.close() 230 | shm_u.close() 231 | shm_fit.close() 232 | shm_dom.close() 233 | shm_eta.unlink() 234 | shm_u.unlink() 235 | shm_fit.unlink() 236 | shm_dom.unlink() 237 | 238 | 239 | def ga_continous_parallel(): 240 | global C_c, x_0, dc 241 | de_u.set_cfg(cfg) 242 | 243 | R = cfg_cont.get('R') 244 | dv = cfg_cont.get('dv') 245 | dc = cfg_cont.get('dc') 246 | 247 | # x = [rho;lam] 248 | # 1. Compute an initial start point 249 | C, x_0 = ga_c.start_point(R, dv, dc) 250 | 251 | # 2. Find the complement of constraint matrix. 252 | # This gives us the allowed directions to step around in 253 | C_c = null_space(C) 254 | 255 | # 3. Add degree 1 to x_0 and C_c matrix 256 | C_c, x_0 = ga_c.add_one_degree(C_c, x_0, dc) 257 | de_u.set_continuous_params(x_0,C_c) 258 | 259 | # 4. Perform optimization through differential evolution 260 | differential_evolution(C_c, x_0, dc) 261 | 262 | # %% 263 | 264 | -------------------------------------------------------------------------------- /density_evolution_ga_python/ga_discrete.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import de_utils as de_u 3 | import matplotlib.pyplot as plt 4 | 5 | from config import cfg 6 | cfg_de = cfg.get('density_evolution') 7 | cfg_disc = cfg_de.get('ga_discrete') 8 | run_id = cfg.get("run_id") 9 | 10 | 11 | def init_population(n_pop, n_cn, n_vn): 12 | population = np.zeros((n_pop, n_cn, n_vn), int) 13 | for i in range(n_pop): 14 | for j in range(n_vn): 15 | k = np.random.choice(n_cn, 2, replace=False) 16 | population[i, k, j] = 1 17 | 18 | return population 19 | 20 | 21 | def vertical_crossover(i1, i2): 22 | crossover_point = np.random.randint(i1[0, :].size) 23 | i1_new = np.hstack((i1[:, :crossover_point], i2[:, crossover_point:])) 24 | i2_new = np.hstack((i1[:, crossover_point:], i2[:, :crossover_point])) 25 | return i1_new, i2_new 26 | 27 | 28 | def horizontal_crossover(i1, i2): 29 | crossover_point = np.random.randint(i1[:, 0].size) 30 | i1_new = np.vstack((i1[:crossover_point, :], i2[crossover_point:, :])) 31 | i2_new = np.vstack((i1[crossover_point:, :], i2[:crossover_point, :])) 32 | return i1_new, i2_new 33 | 34 | 35 | def mutation(i): 36 | mutation_i = np.random.randint(0, i[:, 0].size) 37 | mutation_j = np.random.randint(0, i[0, :].size) 38 | i[mutation_i, mutation_j] = not i[mutation_i, mutation_j] 39 | return i 40 | 41 | 42 | def tournament(population, fitness, n_competitiors=3): 43 | n_pop = cfg_de.get("Np") 44 | competitors_index = np.random.choice(n_pop, n_competitiors, replace=False) 45 | competitors_fitness = fitness[competitors_index] 46 | winner_index = competitors_index[np.argmax(competitors_fitness)] 47 | i_new = population[winner_index, :, :] 48 | fitness_new = fitness[winner_index] 49 | return i_new, fitness_new 50 | 51 | 52 | def evaluate(i): 53 | cn_degrees = np.sum(i, 0) 54 | vn_degrees = np.sum(i, 1) 55 | 56 | condition1 = np.all(cn_degrees >= 2) and np.all(vn_degrees >= 2) 57 | condition2 = np.all(cn_degrees <= 25) 58 | 59 | if condition1 and condition2: 60 | rho_node = np.bincount(vn_degrees)[1:] 61 | rho_edge = np.arange(1, len(rho_node)+1) * rho_node / \ 62 | np.sum(np.arange(1, len(rho_node)+1) * rho_node) 63 | lam_node = np.bincount(cn_degrees)[1:] 64 | lam_edge = np.arange(1, len(lam_node)+1) * lam_node / \ 65 | np.sum(np.arange(1, len(lam_node)+1) * lam_node) 66 | 67 | min = cfg_de.get("min_rber") 68 | max = cfg_de.get("max_rber") 69 | fitness = de_u.bisection_search(min, max, rho_edge, lam_edge) 70 | return fitness*100 71 | 72 | else: 73 | return -100 74 | 75 | 76 | def ga_discrete(): 77 | load_population = cfg_de.get("load_population") 78 | de_u.set_cfg(cfg) 79 | 80 | n_pop = cfg_de.get("Np") 81 | n_generations = cfg_de.get("generations") 82 | n_vn = cfg_disc.get("n_vn") 83 | n_cn = cfg_disc.get("n_cn") 84 | p_vertical = cfg_disc.get("p_vertical") 85 | p_horizontal = cfg_disc.get("p_horizontal") 86 | p_mutation = cfg_disc.get("p_mutation") 87 | print_terminal = cfg_de.get("print_terminal") 88 | 89 | de_u.save_params() 90 | 91 | if load_population: 92 | fname = "data/" + run_id + ".npz" 93 | data = np.load(fname) 94 | population = data["population"] 95 | fitness = data["fitness"] 96 | i_start = int(data["generation"][0]) + 1 97 | dim_0 = np.size(fitness, axis=0) 98 | best_rber = data["best_rber"] 99 | best_idx = data["best_idx"] 100 | if n_generations != np.size(fitness, axis=0): 101 | fitness_new = np.zeros((n_generations, n_pop)) 102 | fitness_new[:dim_0] = fitness 103 | fitness = fitness_new 104 | else: 105 | population = init_population(n_pop, n_cn, n_vn) 106 | fitness = np.full((n_generations, n_pop), -np.inf) 107 | i_start = 0 108 | best_idx = 0 109 | best_rber = 0 110 | 111 | code_rate = (n_vn-n_cn)/n_vn 112 | i = i_start 113 | 114 | header = f""" 115 | Running ga_disrete.py 116 | =================================================================== 117 | Optimizing {n_cn}x{n_vn} protograph. 118 | Code rate: {code_rate:.2f}. 119 | Number of individuals: {n_pop}. 120 | Number of generations: {n_generations}. 121 | Mutation probability: {p_mutation:.2f}. 122 | Vertical probability: {p_vertical:.2f}. 123 | Horizontal probability: {p_horizontal:.2f}. 124 | ------------------------------------------------------------------- 125 | """ 126 | if print_terminal: 127 | print(header) 128 | else: 129 | de_u.log(header, 'w') 130 | 131 | try: 132 | # Initial evaluation 133 | if i_start == 0: 134 | for j in range(n_pop): 135 | if fitness[i_start,j] == -np.inf: 136 | fitness[i_start,j] = evaluate(population[j, :, :]) 137 | i_start += 1 138 | 139 | for i in range(i_start,n_generations): 140 | 141 | # Select with elitism 142 | population_new = np.zeros(population.shape, int) 143 | #fitness_new = np.full(fitness.shape, -np.inf) 144 | population_new[0] = population[np.argmax(fitness[i-1,:])] 145 | fitness[i,0] = fitness[i-1,np.argmax(fitness[i-1,:])] 146 | for j in range(1, n_pop): 147 | population_new[j], fitness[i,j] = tournament( 148 | population, fitness[i-1,:]) 149 | population = population_new 150 | #fitness = fitness_new 151 | 152 | # Crossover 153 | for j in range(1, n_pop-1, 2): 154 | if np.random.rand() < p_vertical: 155 | population[j], population[j + 156 | 1] = vertical_crossover(population[j], population[j+1]) 157 | fitness[i-1,j], fitness[i-1,j+1] = -np.inf, -np.inf 158 | if np.random.rand() < p_horizontal: 159 | population[j], population[j + 160 | 1] = horizontal_crossover(population[j], population[j+1]) 161 | fitness[i,j], fitness[i,j+1] = -np.inf, -np.inf 162 | 163 | # Mutation 164 | for j in range(1, n_pop): 165 | if np.random.rand(): 166 | population[j] = mutation(population[j]) 167 | fitness[i,j] = -np.inf 168 | 169 | # Evaluate new individuals 170 | for j in range(n_pop): 171 | if fitness[i,j] == -np.inf: 172 | fitness[i,j] = evaluate(population[j, :, :]) 173 | 174 | best_idx = np.argmax(fitness[i, :]) 175 | best_rber = np.max(fitness[i, :]) 176 | 177 | status = f"{i} generations completed. RBER: best: {np.max(fitness[i,:]):.2f}, min: {np.min(fitness[i,:]):.2f}, mean: {np.mean(fitness[i,:]):.2f}, variance: {np.var(fitness[i,:]):.2f}. " 178 | if print_terminal: 179 | print(status) 180 | else: 181 | de_u.log(status, 'a') 182 | 183 | if i % int(cfg_de.get("save_interval")) == 0: 184 | de_u.save_population(population,fitness,i,best_idx, best_rber,"discrete") 185 | 186 | 187 | status = f""" 188 | ------------------------------------------------------------------- 189 | Finished! 190 | =================================================================== 191 | """ 192 | if print_terminal: 193 | print(status) 194 | else: 195 | de_u.log(status,'a') 196 | 197 | finally: 198 | de_u.save_population(population, fitness, i, best_idx, best_rber, "discrete") 199 | if i < n_generations-1: 200 | status = f""" 201 | ------------------------------------------------------------------- 202 | Optimization interrupted. 203 | =================================================================== 204 | """ 205 | if print_terminal: 206 | print(status) 207 | else: 208 | de_u.log(status, 'a') 209 | -------------------------------------------------------------------------------- /density_evolution_ga_python/ga_discrete_parallel.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import de_utils as de_u 3 | import matplotlib.pyplot as plt 4 | import ga_discrete as ga_d 5 | from multiprocessing import Pool, shared_memory 6 | from multiprocessing.sharedctypes import Value 7 | 8 | from config import cfg 9 | cfg_de = cfg.get('density_evolution') 10 | cfg_disc = cfg_de.get('ga_discrete') 11 | run_id = cfg.get("run_id") 12 | n_processes = cfg.get("n_processes") 13 | 14 | 15 | def evaluate(j): 16 | global pop_name, fit_name, pop_shape, fit_shape, i_idx 17 | 18 | shm_pop = shared_memory.SharedMemory(name=pop_name) 19 | shm_fit = shared_memory.SharedMemory(name=fit_name) 20 | pop = np.ndarray(pop_shape, dtype=np.int64, buffer=shm_pop.buf) 21 | fit = np.ndarray(fit_shape, dtype=np.float64, buffer=shm_fit.buf) 22 | i = i_idx.value 23 | 24 | if fit[i, j] == -np.inf: 25 | cn_degrees = np.sum(pop[j, :, :], 0) 26 | vn_degrees = np.sum(pop[j, :, :], 1) 27 | 28 | condition1 = np.all(cn_degrees >= 2) and np.all(vn_degrees >= 2) 29 | condition2 = np.all(cn_degrees <= 25) 30 | 31 | if condition1 and condition2: 32 | rho_node = np.bincount(vn_degrees)[1:] 33 | rho_edge = np.arange(1, len(rho_node)+1) * rho_node / \ 34 | np.sum(np.arange(1, len(rho_node)+1) * rho_node) 35 | lam_node = np.bincount(cn_degrees)[1:] 36 | lam_edge = np.arange(1, len(lam_node)+1) * lam_node / \ 37 | np.sum(np.arange(1, len(lam_node)+1) * lam_node) 38 | 39 | min = cfg_de.get("min_rber") 40 | max = cfg_de.get("max_rber") 41 | fitness = de_u.bisection_search(min, max, rho_edge, lam_edge) 42 | fit[i, j] = fitness*100 43 | 44 | else: 45 | fit[i, j] = -100 46 | shm_pop.close() 47 | shm_fit.close() 48 | 49 | 50 | def pool_initializer(): 51 | global pop_name, fit_name, pop_shape, i_idx 52 | 53 | 54 | def ga_discrete_parallel(): 55 | global pop_name, fit_name, pop_shape, fit_shape, i_idx 56 | load_population = cfg_de.get("load_population") 57 | de_u.set_cfg(cfg) 58 | 59 | n_pop = cfg_de.get("Np") 60 | n_generations = cfg_de.get("generations") 61 | n_vn = cfg_disc.get("n_vn") 62 | n_cn = cfg_disc.get("n_cn") 63 | p_vertical = cfg_disc.get("p_vertical") 64 | p_horizontal = cfg_disc.get("p_horizontal") 65 | p_mutation = cfg_disc.get("p_mutation") 66 | print_terminal = cfg_de.get("print_terminal") 67 | 68 | de_u.save_params() 69 | 70 | if load_population: 71 | fname = "data/" + run_id + ".npz" 72 | data = np.load(fname) 73 | population = data["population"] 74 | fitness = data["fitness"] 75 | i_start = int(data["generation"][0]) + 1 76 | dim_0 = np.size(fitness, axis=0) 77 | if n_generations != np.size(fitness, axis=0): 78 | fitness_new = np.zeros((n_generations, n_pop)) 79 | fitness_new[:dim_0] = fitness 80 | fitness = fitness_new 81 | else: 82 | population = ga_d.init_population(n_pop, n_cn, n_vn) 83 | fitness = np.full((n_generations, n_pop), -np.inf) 84 | i_start = 0 85 | 86 | best_idx = 0 87 | best_rber = 0 88 | code_rate = (n_vn-n_cn)/n_vn 89 | 90 | header = f""" 91 | Running ga_disrete.py 92 | =================================================================== 93 | Optimizing {n_cn}x{n_vn} protograph. 94 | Code rate: {code_rate:.2f}. 95 | Number of individuals: {n_pop}. 96 | Number of generations: {n_generations}. 97 | Mutation probability: {p_mutation:.2f}. 98 | Vertical probability: {p_vertical:.2f}. 99 | Horizontal probability: {p_horizontal:.2f}. 100 | ------------------------------------------------------------------- 101 | """ 102 | if print_terminal: 103 | print(header) 104 | else: 105 | de_u.log(header, 'w') 106 | 107 | # Initialize shared_memory in multiprocessing 108 | shm_pop = shared_memory.SharedMemory(create=True, size=population.nbytes) 109 | shm_fit = shared_memory.SharedMemory(create=True, size=fitness.nbytes) 110 | 111 | pop = np.ndarray(population.shape, dtype=np.int64, buffer=shm_pop.buf) 112 | fit = np.ndarray(fitness.shape, dtype=np.float64, buffer=shm_fit.buf) 113 | 114 | pop[:] = population[:] 115 | fit[:] = fitness[:] 116 | 117 | pop_name = shm_pop.name 118 | fit_name = shm_fit.name 119 | 120 | pop_shape = pop.shape 121 | fit_shape = fit.shape 122 | 123 | i_idx = Value('i', i_start) 124 | i = i_start 125 | # Use Pool for parallel computing 126 | pool = Pool(processes=n_processes, initializer=pool_initializer) 127 | pop_idx = range(n_pop) 128 | 129 | try: 130 | # Initial evaluation 131 | if i_start == 0: 132 | pool.map(evaluate, pop_idx) 133 | best_idx = np.argmax(fit[i_start, :]) 134 | best_rber = np.max(fit[i_start, :]) 135 | 136 | status = f"{i} generations completed. RBER: best: {np.max(fit[i_start,:]):.2f}, min: {np.min(fit[i_start,:]):.2f}, mean: {np.mean(fit[i_start,:]):.2f}, variance: {np.var(fit[i_start,:]):.2f}. " 137 | if print_terminal: 138 | print(status) 139 | else: 140 | de_u.log(status, 'a') 141 | 142 | i_start += 1 143 | i_idx.value += 1 144 | 145 | for i in range(i_start, n_generations): 146 | 147 | # Select with elitism 148 | pop_new = np.zeros(pop.shape, int) 149 | pop_new[0] = pop[np.argmax(fit[i-1, :])] 150 | fit[i, 0] = fit[i-1, np.argmax(fit[i-1, :])] 151 | for j in range(1, n_pop): 152 | pop_new[j], fit[i, j] = ga_d.tournament( 153 | pop, fit[i-1, :]) 154 | pop[:] = pop_new[:] 155 | #fit = fit_new 156 | 157 | # Crossover 158 | for j in range(1, n_pop-1, 2): 159 | if np.random.rand() < p_vertical: 160 | pop[j], pop[j + 161 | 1] = ga_d.vertical_crossover(pop[j], pop[j+1]) 162 | fit[i-1, j], fit[i-1, j+1] = -np.inf, -np.inf 163 | if np.random.rand() < p_horizontal: 164 | pop[j], pop[j + 165 | 1] = ga_d.horizontal_crossover(pop[j], pop[j+1]) 166 | fit[i, j], fit[i, j+1] = -np.inf, -np.inf 167 | 168 | # Mutation 169 | for j in range(1, n_pop): 170 | if np.random.rand(): 171 | pop[j] = ga_d.mutation(pop[j]) 172 | fit[i, j] = -np.inf 173 | 174 | # Evaluate new individuals 175 | pool.map(evaluate, pop_idx) 176 | 177 | i_idx.value += 1 178 | 179 | # Keep track of best individual 180 | best_idx = np.argmax(fit[i, :]) 181 | best_rber = np.max(fit[i, :]) 182 | 183 | status = f"{i} generations completed. RBER: best: {np.max(fit[i,:]):.2f}, min: {np.min(fit[i,:]):.2f}, mean: {np.mean(fit[i,:]):.2f}, variance: {np.var(fit[i,:]):.2f}. " 184 | if print_terminal: 185 | print(status) 186 | else: 187 | de_u.log(status, 'a') 188 | 189 | if i % int(cfg_de.get("save_interval")) == 0: 190 | de_u.save_population(pop, fit, i, best_idx, 191 | best_rber, "discrete") 192 | 193 | status = f""" 194 | ------------------------------------------------------------------- 195 | Finished! 196 | =================================================================== 197 | """ 198 | if print_terminal: 199 | print(status) 200 | else: 201 | de_u.log(status, 'a') 202 | 203 | finally: 204 | de_u.save_population(pop, fit, i, best_idx, best_rber, "discrete") 205 | if i < n_generations-1: 206 | status = f""" 207 | ------------------------------------------------------------------- 208 | Optimization interrupted. 209 | =================================================================== 210 | """ 211 | if print_terminal: 212 | print(status) 213 | else: 214 | de_u.log(status, 'a') 215 | 216 | shm_pop.close() 217 | shm_fit.close() 218 | shm_pop.unlink() 219 | shm_fit.unlink() 220 | -------------------------------------------------------------------------------- /density_evolution_ga_python/multiprocessing_illustration.py: -------------------------------------------------------------------------------- 1 | # Illustration of how multiprocessing will be used in algorithms 2 | import time 3 | from multiprocessing import shared_memory, Pool 4 | import numpy as np 5 | from random import random 6 | 7 | 8 | def random_num(i): 9 | global shr_name, dim 10 | existing_shm = shared_memory.SharedMemory(name=shr_name) 11 | np_array = np.ndarray(dim, dtype=np.float64, buffer=existing_shm.buf) 12 | 13 | np_array[i] = random() 14 | 15 | existing_shm.close() 16 | 17 | def increment(i): 18 | global shr_name, dim 19 | existing_shm = shared_memory.SharedMemory(name=shr_name) 20 | np_arr = np.ndarray(dim, dtype=np.float64, buffer=existing_shm.buf) 21 | 22 | np_arr[i] += 1 23 | 24 | existing_shm.close() 25 | 26 | 27 | # Use initializer to share data that is fixed throughout computations 28 | def initializer(): 29 | global dim, shr_name 30 | 31 | 32 | if __name__ == '__main__': 33 | global dim, shr_name 34 | dim = 10 35 | n_processes = 4 36 | 37 | # Use shared_memory to share data between processes that operate on the same array 38 | # but never on the same part of the array. In this case we are interested in sharing 39 | # numpy arrays 40 | a = np.ones(dim, dtype=np.float64) 41 | shm = shared_memory.SharedMemory(create=True, size=a.nbytes) 42 | # # Now create a NumPy array backed by shared memory 43 | np_array = np.ndarray(a.shape, dtype=np.float64, buffer=shm.buf) 44 | np_array[:] = a[:] # Copy the original data into shared memory 45 | shr_name = shm.name 46 | print(np_array) 47 | 48 | # Use pool to split up processes 49 | pool = Pool(processes=n_processes, initializer=initializer) 50 | idx = range(dim) 51 | pool.map(random_num, idx) 52 | pool.map(increment, idx) 53 | 54 | print(np_array) 55 | shm.close() 56 | shm.unlink() 57 | -------------------------------------------------------------------------------- /hgen.m: -------------------------------------------------------------------------------- 1 | function [H,exactRate,nk,ERROR_FLAG] = hgen(R,N,Lambda,Deg_Lambda,Rho,Deg_Rho,seed,DEBUG_FLAG,FileName_sparse); 2 | % [H_SPARSE,EXACT_RATE,NK,ERROR_FLAG] = HGEN(R,N,LAMBDA,DEG_LAMBDA,RHO,DEG_RHO,SEED,DEBUG_FLAG, FILENAME_SPARSE) 3 | % generates a random Parity-Check Matrix of rate R and length N for a given 4 | % profile 5 | % LAMBDA = [LAMBDA(1),...,LAMBDA(.)] is the polynomial representing the proportion of edges LAMBDA(i) connected to 6 | % variables nodes of degree DEG_LAMBDA(i) 7 | % DEG_LAMBDA = [2,3,...] is the vector representing all degrees of the variables-nodes in the code 8 | % RHO = [RHO(1),...,RHO(.)] is the polynomial representing the proportion of edges RHO(i) connected to 9 | % check nodes of degree DEG_RHO(i) 10 | % DEG_RHO = [2,3,...] is the vector representing all degrees of the check-nodes in the code 11 | % SEED seed number to initialize the random generator 12 | % DEBUG_FLAG 0 to desactive it, 1 to print some crucial variables 13 | % FILENAME to use the default name (gallager.n.nk.rate.dat), use [] 14 | % EXACT_RATE the exact rate given by the parity-check matrix (as close as 15 | % possible of R) 16 | % NK dimension of the parity-check equation H (nk x n) 17 | % EXAMPLE: 18 | %R = .6;N = 6500;Lambda = [0.2096540000 0.4024980000 0.3878480000];Deg_Lambda = [2 3 10];Rho = [1];Deg_Rho = [9];seed = 0;DEBUG_FLAG = 1;FileName = []; 19 | 20 | ERROR_FLAG = 0; 21 | FALSE_ = 0; 22 | TRUE_ = 1; 23 | rand('state',seed); 24 | 25 | if (R-floor(100*R)/100<2e-2); 26 | R = floor(100*R)/100; 27 | end; 28 | CodeNumber = 0; 29 | Int_0_1_Lambda = sum(Lambda./Deg_Lambda); 30 | Int_0_1_Rho = sum(Rho./Deg_Rho); 31 | M = round(N*(1-round(1e16*(1-Int_0_1_Rho/Int_0_1_Lambda))/1e16)); 32 | Proportion_Lambda = (Int_0_1_Lambda)*Lambda./Deg_Lambda/sum((Int_0_1_Lambda)*Lambda./Deg_Lambda); 33 | Proportion_Rho = (Int_0_1_Rho)*Rho./Deg_Rho/sum((Int_0_1_Rho)*Rho./Deg_Rho); 34 | Nb_Variable_Nodes = round((N/Int_0_1_Lambda)*Lambda./Deg_Lambda); 35 | Nb_Check_Nodes = round((M/Int_0_1_Rho)*Rho./Deg_Rho); 36 | 37 | % First step: add nb_row_toaddtoright rows of the lowest connection degree; 38 | nb_row_toaddtoright = M-sum(Nb_Check_Nodes); 39 | Nb_Check_Nodes(1) = Nb_Check_Nodes(1)+nb_row_toaddtoright; 40 | % Update the total number of ones on the right side 41 | nb1_right = sum(Nb_Check_Nodes.*Deg_Rho); 42 | nb1_left = sum(Nb_Variable_Nodes.*Deg_Lambda); 43 | nb_col_toaddtoleft = N-sum(Nb_Variable_Nodes); 44 | if length(Lambda)==1 & nb_col_toaddtoleft~=0; 45 | disp('Cannot generate this matrix'); 46 | return; 47 | else; 48 | if (nb1_right ~= nb1_left | nb_col_toaddtoleft ~= 0); 49 | x = [Deg_Lambda(1),Deg_Lambda(2);1,1]\[nb1_right-nb1_left;nb_col_toaddtoleft]; 50 | Nb_Variable_Nodes(1) = Nb_Variable_Nodes(1)+x(1); 51 | Nb_Variable_Nodes(2) = Nb_Variable_Nodes(2)+x(2); 52 | end; 53 | end; 54 | 55 | exactRate = (sum(Nb_Variable_Nodes)-sum(Nb_Check_Nodes))/sum(Nb_Variable_Nodes) 56 | KK = sum(Nb_Variable_Nodes)-sum(Nb_Check_Nodes); 57 | nk = M; 58 | 59 | if sum(Nb_Variable_Nodes.*Deg_Lambda) ~= sum(Nb_Check_Nodes.*Deg_Rho); 60 | disp('Cannot generate this matrix'); 61 | return; 62 | end; 63 | 64 | 65 | 66 | if DEBUG_FLAG; 67 | String = []; 68 | for l = 1:length(Deg_Lambda); 69 | String = [String,'+',num2str(Deg_Lambda(l)),'*',num2str(Nb_Variable_Nodes(l))]; 70 | end; 71 | String = [String,' (',num2str(sum(Nb_Variable_Nodes.*Deg_Lambda)),')','~=']; 72 | for l = 1:length(Deg_Rho); 73 | String = [String,'+',num2str(Deg_Rho(l)),'*',num2str(Nb_Check_Nodes(l))]; 74 | end; 75 | String = [String,' (',num2str(sum(Nb_Check_Nodes.*Deg_Rho)),')']; 76 | disp(String); 77 | disp(['Add ',num2str(N-sum(Nb_Variable_Nodes)),' columns and ',num2str(M-sum(Nb_Check_Nodes)),' rows']); 78 | 79 | disp('Press any key to continue and adjust the weights by hands if necessary');pause; 80 | %end; 81 | end; 82 | 83 | CumSum_Nb_Variable_Nodes = cumsum(Nb_Variable_Nodes); 84 | Nb_Elements_Per_Column = zeros(1,N); 85 | Nb_Elements_Per_Column(1:CumSum_Nb_Variable_Nodes(1)) = Deg_Lambda(1); 86 | for l = 1:length(Deg_Lambda)-1; 87 | Nb_Elements_Per_Column(CumSum_Nb_Variable_Nodes(l)+1:CumSum_Nb_Variable_Nodes(l+1)) = Deg_Lambda(l+1); 88 | end; 89 | 90 | CumSum_Nb_Check_Nodes = cumsum(Nb_Check_Nodes); 91 | Nb_Elements_Per_Row = zeros(1,M); 92 | Nb_Elements_Per_Row(1:CumSum_Nb_Check_Nodes(1)) = Deg_Rho(1); 93 | for l = 1:length(Deg_Rho)-1; 94 | Nb_Elements_Per_Row(CumSum_Nb_Check_Nodes(l)+1:CumSum_Nb_Check_Nodes(l+1)) = Deg_Rho(l+1); 95 | end; 96 | Random_Nb_Elements_Per_Row = Nb_Elements_Per_Row(randperm(length(Nb_Elements_Per_Row))); 97 | 98 | 99 | % disp('---------------------- Parity-check matrix (Hr) generation... ------------------'); 100 | 101 | CYCLESREMOVAL_ = FALSE_; 102 | 103 | while ~CYCLESREMOVAL_; 104 | 105 | Max_Deg_Rho = max(Deg_Rho); 106 | Index_Temp = 0; 107 | Vec_Temp = zeros(sum(Nb_Check_Nodes.*Deg_Rho),1); 108 | Vec_Temp(Index_Temp+1:Index_Temp+Deg_Lambda(1)*Nb_Variable_Nodes(1)) = repmat([1:CumSum_Nb_Variable_Nodes(1)],1,Deg_Lambda(1)); 109 | Index_Temp = Index_Temp+Deg_Lambda(1)*Nb_Variable_Nodes(1); 110 | for l=2:length(Deg_Lambda); 111 | Vec_Temp(Index_Temp+1:Index_Temp+Deg_Lambda(l)*Nb_Variable_Nodes(l)) = repmat([CumSum_Nb_Variable_Nodes(l-1)+1:CumSum_Nb_Variable_Nodes(l)],1,Deg_Lambda(l)); 112 | Index_Temp = Index_Temp+Deg_Lambda(l)*Nb_Variable_Nodes(l); 113 | end; 114 | Random_Columns_Index = Vec_Temp(randperm(length(Vec_Temp))); 115 | 116 | Hr = zeros(M,max(Deg_Rho)); 117 | Index = 1; 118 | for n = 1:M; 119 | Hr(n,1:Random_Nb_Elements_Per_Row(n)) = Random_Columns_Index(Index:Index+Random_Nb_Elements_Per_Row(n)-1).'; 120 | Index = Index+Random_Nb_Elements_Per_Row(n); 121 | end; 122 | %Hr = reshape(Vec_Temp(randperm(length(Vec_Temp))),M,Deg_Rho); 123 | 124 | % disp('---------- Parity-check matrix (Hr) generation done ------------'); 125 | 126 | % ---------- Removal of cycles of length 2... -------------------- 127 | 128 | % Validation 129 | for n = 1:M; 130 | if DEBUG_FLAG; 131 | if mod(n,floor(M/100))==0;disp([num2str(round(n/M*100)),'%']);end; 132 | end; 133 | Hrn = Hr(n,1:Random_Nb_Elements_Per_Row(n)); 134 | [B,In,Jn] = unique(Hrn); 135 | IndicesToSwitch = setdiff([1:Random_Nb_Elements_Per_Row(n)],In); 136 | NbIndicesToSwitch = length(IndicesToSwitch); 137 | if n+NbIndicesToSwitch<=M; 138 | for d = 1:NbIndicesToSwitch; 139 | IndexToSwitch = IndicesToSwitch(d); 140 | IndexToSwitch2 = floor(Random_Nb_Elements_Per_Row(n+d)*rand)+1; 141 | tmp = Hr(n,IndexToSwitch); 142 | Hr(n,IndexToSwitch) = Hr(n+d,IndexToSwitch2); 143 | Hr(n+d,IndexToSwitch2) = tmp; 144 | end; 145 | else; 146 | for d = 1:NbIndicesToSwitch; 147 | IndexToSwitch = IndicesToSwitch(d); 148 | IndexToSwitch2 = floor(Random_Nb_Elements_Per_Row(n-d)*rand)+1; 149 | tmp = Hr(n,IndexToSwitch); 150 | Hr(n,IndexToSwitch) = Hr(n-d,IndexToSwitch2); 151 | Hr(n-d,IndexToSwitch2) = tmp; 152 | end; 153 | end; 154 | 155 | % if Diff ~= 0; 156 | % switch Diff; 157 | % case 1; 158 | % %disp('Attempt to remove cycle(s) of length 2'); 159 | % [B,In,Jn] = unique(Hr(n,1:Random_Nb_Elements_Per_Row(n))); 160 | % 161 | % for l = 1:Random_Nb_Elements_Per_Row(n); 162 | % if length(find(In==l))==0; 163 | % l_eliminate = l; 164 | % end; 165 | % end; 166 | % if ~l_eliminate; 167 | % disp('FAILURE --- Matrix is too full -- Please restart the program'); 168 | % CYCLESREMOVAL_ = FALSE_ 169 | % end; 170 | % temp = Hr(n,l_eliminate); 171 | % if n1-eps; 3 | x = 1e-99; 4 | elseif y.0393; 8 | x = ((.0218-log(y))/.4527)^(1/.86); 9 | else; 10 | x0 = 2*lambertw(.5*pi/y^2); 11 | if ~isfinite(x0);x0=50;end; 12 | x1 = fzero(f1,x0,[],y); 13 | x2 = fzero(f2,x0,[],y); 14 | x = (x1+x2)/2; 15 | end; 16 | end; 17 | -------------------------------------------------------------------------------- /profgen.m: -------------------------------------------------------------------------------- 1 | function [dc,rho,dv,lambda,newRate,thres,lambda2star,EbN0mindB] = profgen(targetRate,max_deg_dv,dc_init); 2 | % PROFGEN Generates optimal LDPC code profile 3 | % PROFGEN(RATE,MAX_DEG_DV,DC_INIT) generates an optimal block code profile (dv,dc) of rate defined by RATE. 4 | % DV, LAMBDA and RHO are optimized for given DC_INIT (concentration theorem). 5 | % A constraint on the maximal degree for the variable nodes can be added 6 | % which guarantees that MAX_DEG_DV = max(dv). The default value is 20. 7 | % Optimal THRESHOLD, LAMBDA_STAR(2) and EBN0_MIN (dB) are given as well. 8 | % MATLAB COMMAND EXAMPLE 9 | % >> targetRate = 1/2;max_deg_dv = 10;dc_init = [7];[dc,rho,dv,lambda,newRate,thres,lambda2star,EbN0mindB] = profgen(targetRate,max_deg_dv,dc_init); 10 | 11 | % ---------- Initialization ----------------------- 12 | 13 | warning off MATLAB:fzero:UndeterminedSyntax; %to suppress this warning 14 | TRUE = 1; 15 | FALSE = 0; 16 | f1 = inline('Phi-(1-3/x)*sqrt(pi/x)*exp(-x/4)','x','Phi'); 17 | f2 = inline('(1+1/(7*x))*sqrt(pi/x)*exp(-x/4)-Phi','x','Phi'); 18 | end_while = FALSE; 19 | if isempty(dc_init); 20 | dc_init = floor(3/(1-targetRate)); 21 | else; 22 | dc_init = dc_init(1); 23 | end; 24 | dc = [dc_init,dc_init+1]; % Concentration theorem 25 | step = 1e-1; 26 | dv = [2:max_deg_dv].'; 27 | lambda = zeros(size(dv)); 28 | C = (1./dv).'; 29 | d = .5; 30 | sigma_opt_dc = [0,Inf]; 31 | step = 0.1; 32 | rho1_min = 0; 33 | rho1_max = 1; 34 | 35 | % ---------- Optimization--------------------- 36 | 37 | while (abs(sigma_opt_dc(1)-sigma_opt_dc(2)) > 1e-5); 38 | rho1 = [(rho1_min+rho1_max)/2,(rho1_min+rho1_max)/2+step]; 39 | for lrho1 = 1:length(rho1); 40 | rho(1) = rho1(lrho1);rho(2) = 1-rho(1); 41 | sigma_min = .5; 42 | sigma_max = 1.17/targetRate; 43 | sigma = sigma_min; 44 | newRate = Inf; 45 | while ( abs(targetRate-newRate) > 1e-5 ); 46 | s = 2/sigma^2; 47 | %lambda2max = max([0,(sum(rho./dc)/(1-targetRate)-1/3)/(1/2-1/3),min([(sum(rho./dc)/(1-targetRate)-1/dv(end))/(1/2-1/dv(end)),exp(1/2/sigma^2)/sum(rho.*(dc-1)),1])]); 48 | lambda2max = max([0,min([exp(1/2/sigma^2)/sum(rho.*(dc-1)),1])]) 49 | r = linspace(eps,phi(s),100);r = reshape(r,length(r),1);fr_tmp = zeros(size(r)); 50 | for n = 1:length(r);rn = r(n);tmp = 0;for jc = 1:length(dc);tmp = tmp+rho(jc)*phi_1(1-(1-rn)^(dc(jc)-1),f1,f2);end;fr_tmp(n) = tmp;end; 51 | A = zeros(length(r),length(dv));for lr = 1:length(r);for iv = 1:length(dv);A(lr,iv) = phi(s+(dv(iv)-1)*fr_tmp(lr));end;end; 52 | A = [A;-1./(dv.')]; 53 | b = [r;-sum(rho./dc)]; 54 | Aeq = ones(1,length(dv)); 55 | beq = 1; 56 | LB = zeros(length(dv),1); 57 | UB = [lambda2max;ones(length(dv)-1,1)-eps]; 58 | lambda=lsqlin(C,d,A,b,Aeq,beq,LB,UB); 59 | newRate = 1-sum(rho./dc)/sum(lambda./dv); 60 | if newRate < targetRate; 61 | sigma_max = sigma; 62 | sigma = (sigma_min+sigma)/2; 63 | else; 64 | sigma_min = sigma; 65 | sigma_opt_dc(lrho1) = sigma; 66 | sigma = (sigma_max+sigma)/2; 67 | end; 68 | end 69 | end; 70 | if sigma_opt_dc(1)>sigma_opt_dc(2); 71 | rho1_max = rho1(2); 72 | else; 73 | rho1_min = rho1(1); 74 | end; 75 | step = step/2; 76 | end; 77 | thres = mean(sigma_opt_dc); 78 | EbN0mindB = 10*log10(1/(2*newRate*thres^2)); 79 | lambda2star = exp(1/2/sigma^2)/sum(rho.*(dc-1)); 80 | 81 | -------------------------------------------------------------------------------- /rand_proto.m: -------------------------------------------------------------------------------- 1 | function [H,final_column_weights,final_row_weights]=rand_proto(n,m,lambda,rho) 2 | %Function construct protograph or subgraph(subpart) of protograph with degree 3 | %distribution defined by column (lambda, closes as it posible) and row 4 | %(rho) distributions 5 | %without eliminating balance cycles(TS) and grown of code distance pattern 6 | %base on Implementing the Belief Propagation Algorithm in MATLAB 7 | %R?ffer, B. S. and Kellett, C. M. 8 | %Technical report. Department of Electrical Engineering and Computer Science, University of Newcastle, Australia, November 2008. 9 | 10 | %Example of parameters 11 | % n=32;%columns in protograph 12 | % m=22;%row in protograph 13 | % lambda=[0,0.1,0.2,0,0,0.7]; %Column distributions polynomial 14 | % rho=[[0,0,0,0.1,0.05,0.15,0.2,0.1,0.1,0.2,0.1];%Row distribution polynomial 15 | v=lambda ; 16 | h=rho; 17 | %Initialisation 18 | %m=floor(n*(1-r)); 19 | H=zeros([m,n]); 20 | alpha=[];%alphawillcontainthecolumnweightfor 21 | %eachcolumn 22 | for i=1:length(v) 23 | for j=1:(floor(v(i)*n))%alwaysunderfillandthenaddextras 24 | %later 25 | alpha=[alpha i]; 26 | end 27 | end 28 | while(length(alpha)~=n) 29 | alpha=[alpha i]; 30 | end 31 | 32 | beta=[];%betawillcontaintherowweightforeachrow 33 | for i=1:length(h) 34 | for j=1:(floor(h(i)*m))%alwaysunderfillandthenaddextras 35 | beta=[beta,i]; 36 | end 37 | end 38 | while(length(beta)~=m) 39 | beta=[beta i]; 40 | end 41 | %Construction 42 | for i=1:n 43 | %construct column i 44 | c=[]; 45 | beta_temp=beta; 46 | for j=1:alpha(i) 47 | %temp_row=randint(1,1,[1,m]); 48 | % 49 | % X=randint(1,Nused*Nframe,M) 50 | % X = randi(M, 1, Nused*Nframe) - 1; 51 | tic; 52 | temp_row=randi(m,1); 53 | while(((beta_temp(temp_row)==0)&&... 54 | (max(beta_temp)>0))||... 55 | ((beta_temp(temp_row)<=-10))) 56 | rng('shuffle'); 57 | time=toc; 58 | if time>2 59 | error('start again several time or use different size of protograph and degree distibution'); 60 | 61 | end 62 | 63 | 64 | temp_row=mod(temp_row+1,m)+1 65 | end 66 | c=[c temp_row]; 67 | beta_temp(temp_row)=-10; 68 | end 69 | %decremententriesinbeta 70 | for k=1:length(c) 71 | beta(c(k))=beta(c(k))-1; 72 | end 73 | %populate H 74 | for j=1:alpha(i) 75 | H(c(j),i)=1; 76 | end 77 | 78 | end 79 | 80 | %Calculateactualcolumndistribution 81 | column_weights=H'*ones(m,1); 82 | for i=1:max(column_weights) 83 | count=0; 84 | for j=1:length(column_weights) 85 | if(column_weights(j)==i) 86 | count=count+1; 87 | end 88 | end 89 | final_column_weights(i)=count/length(column_weights); 90 | end 91 | %Calculateactual rowweights 92 | row_weights=H*ones(n,1); 93 | for i=1:max(row_weights') 94 | count=0; 95 | for j=1:length(row_weights) 96 | if(row_weights(j)==i) 97 | count=count+1; 98 | end 99 | end 100 | final_row_weights(i)=count/length(row_weights); 101 | %spy(H) 102 | end 103 | --------------------------------------------------------------------------------