/*
Regression Test for the Low-density parity-check Encoder and Decoder

Table entries below copied from:
https://www.etsi.org/deliver/etsi_en/302700_302799/302755/01.04.01_60/en_302755v010401p.pdf

Copyright 2018 <NAME> <<EMAIL>>
*/

#include <iostream>
#include <random>
#include <cmath>
#include <cassert>
#include <chrono>
#include <algorithm>
#include <functional>
#include "ldpc_encoder.hh"
#include "ldpc_decoder.hh"

struct DVB_T2_TABLE_A1
{
	static const int M = 360;
	static const int N = 64800;
	static const int K = 32400;
	static const int LINKS_MIN_CN = 6;
	static const int LINKS_MAX_CN = 7;
	static const int LINKS_TOTAL = 226799;
	static const int DEG_MAX = 8;
	static constexpr int DEG[] = {
		8, 3, 0
	};
	static constexpr int LEN[] = {
		36, 54, 0
	};
	static constexpr int POS[] = {
		54,	9318,	14392,	27561,	26909,	10219,	2534,	8597,
		55,	7263,	4635,	2530,	28130,	3033,	23830,	3651,
		56,	24731,	23583,	26036,	17299,	5750,	792,	9169,
		57,	5811,	26154,	18653,	11551,	15447,	13685,	16264,
		58,	12610,	11347,	28768,	2792,	3174,	29371,	12997,
		59,	16789,	16018,	21449,	6165,	21202,	15850,	3186,
		60,	31016,	21449,	17618,	6213,	12166,	8334,	18212,
		61,	22836,	14213,	11327,	5896,	718,	11727,	9308,
		62,	2091,	24941,	29966,	23634,	9013,	15587,	5444,
		63,	22207,	3983,	16904,	28534,	21415,	27524,	25912,
		64,	25687,	4501,	22193,	14665,	14798,	16158,	5491,
		65,	4520,	17094,	23397,	4264,	22370,	16941,	21526,
		66,	10490,	6182,	32370,	9597,	30841,	25954,	2762,
		67,	22120,	22865,	29870,	15147,	13668,	14955,	19235,
		68,	6689,	18408,	18346,	9918,	25746,	5443,	20645,
		69,	29982,	12529,	13858,	4746,	30370,	10023,	24828,
		70,	1262,	28032,	29888,	13063,	24033,	21951,	7863,
		71,	6594,	29642,	31451,	14831,	9509,	9335,	31552,
		72,	1358,	6454,	16633,	20354,	24598,	624,	5265,
		73,	19529,	295,	18011,	3080,	13364,	8032,	15323,
		74,	11981,	1510,	7960,	21462,	9129,	11370,	25741,
		75,	9276,	29656,	4543,	30699,	20646,	21921,	28050,
		76,	15975,	25634,	5520,	31119,	13715,	21949,	19605,
		77,	18688,	4608,	31755,	30165,	13103,	10706,	29224,
		78,	21514,	23117,	12245,	26035,	31656,	25631,	30699,
		79,	9674,	24966,	31285,	29908,	17042,	24588,	31857,
		80,	21856,	27777,	29919,	27000,	14897,	11409,	7122,
		81,	29773,	23310,	263,	4877,	28622,	20545,	22092,
		82,	15605,	5651,	21864,	3967,	14419,	22757,	15896,
		83,	30145,	1759,	10139,	29223,	26086,	10556,	5098,
		84,	18815,	16575,	2936,	24457,	26738,	6030,	505,
		85,	30326,	22298,	27562,	20131,	26390,	6247,	24791,
		86,	928,	29246,	21246,	12400,	15311,	32309,	18608,
		87,	20314,	6025,	26689,	16302,	2296,	3244,	19613,
		88,	6237,	11943,	22851,	15642,	23857,	15112,	20947,
		89,	26403,	25168,	19038,	18384,	8882,	12719,	7093,
		0,	14567,	24965,
		1,	3908,	100,
		2,	10279,	240,
		3,	24102,	764,
		4,	12383,	4173,
		5,	13861,	15918,
		6,	21327,	1046,
		7,	5288,	14579,
		8,	28158,	8069,
		9,	16583,	11098,
		10,	16681,	28363,
		11,	13980,	24725,
		12,	32169,	17989,
		13,	10907,	2767,
		14,	21557,	3818,
		15,	26676,	12422,
		16,	7676,	8754,
		17,	14905,	20232,
		18,	15719,	24646,
		19,	31942,	8589,
		20,	19978,	27197,
		21,	27060,	15071,
		22,	6071,	26649,
		23,	10393,	11176,
		24,	9597,	13370,
		25,	7081,	17677,
		26,	1433,	19513,
		27,	26925,	9014,
		28,	19202,	8900,
		29,	18152,	30647,
		30,	20803,	1737,
		31,	11804,	25221,
		32,	31683,	17783,
		33,	29694,	9345,
		34,	12280,	26611,
		35,	6526,	26122,
		36,	26165,	11241,
		37,	7666,	26962,
		38,	16290,	8480,
		39,	11774,	10120,
		40,	30051,	30426,
		41,	1335,	15424,
		42,	6865,	17742,
		43,	31779,	12489,
		44,	32120,	21001,
		45,	14508,	6996,
		46,	979,	25024,
		47,	4554,	21896,
		48,	7989,	21777,
		49,	4972,	20661,
		50,	6612,	2730,
		51,	12742,	4418,
		52,	29194,	595,
		53,	19267,	20113,
	};
};

struct DVB_T2_TABLE_A3
{
	static const int M = 360;
	static const int N = 64800;
	static const int K = 43200;
	static const int LINKS_MIN_CN = 9;
	static const int LINKS_MAX_CN = 10;
	static const int LINKS_TOTAL = 215999;
	static const int DEG_MAX = 13;
	static constexpr int DEG[] = {
		13, 3, 0
	};
	static constexpr int LEN[] = {
		12, 108, 0
	};
	static constexpr int POS[] = {
		317,	2255,	2324,	2723,	3538,	3576,	6194,	6700,	9101,	10057,	12739,	17407,	21039,
		1958,	2007,	3294,	4394,	12762,	14505,	14593,	14692,	16522,	17737,	19245,	21272,	21379,
		127,	860,	5001,	5633,	8644,	9282,	12690,	14644,	17553,	19511,	19681,	20954,	21002,
		2514,	2822,	5781,	6297,	8063,	9469,	9551,	11407,	11837,	12985,	15710,	20236,	20393,
		1565,	3106,	4659,	4926,	6495,	6872,	7343,	8720,	15785,	16434,	16727,	19884,	21325,
		706,	3220,	8568,	10896,	12486,	13663,	16398,	16599,	19475,	19781,	20625,	20961,	21335,
		4257,	10449,	12406,	14561,	16049,	16522,	17214,	18029,	18033,	18802,	19062,	19526,	20748,
		412,	433,	558,	2614,	2978,	4157,	6584,	9320,	11683,	11819,	13024,	14486,	16860,
		777,	5906,	7403,	8550,	8717,	8770,	11436,	12846,	13629,	14755,	15688,	16392,	16419,
		4093,	5045,	6037,	7248,	8633,	9771,	10260,	10809,	11326,	12072,	17516,	19344,	19938,
		2120,	2648,	3155,	3852,	6888,	12258,	14821,	15359,	16378,	16437,	17791,	20614,	21025,
		1085,	2434,	5816,	7151,	8050,	9422,	10884,	12728,	15353,	17733,	18140,	18729,	20920,
		856,	1690,	12787,
		6532,	7357,	9151,
		4210,	16615,	18152,
		11494,	14036,	17470,
		2474,	10291,	10323,
		1778,	6973,	10739,
		4347,	9570,	18748,
		2189,	11942,	20666,
		3868,	7526,	17706,
		8780,	14796,	18268,
		160,	16232,	17399,
		1285,	2003,	18922,
		4658,	17331,	20361,
		2765,	4862,	5875,
		4565,	5521,	8759,
		3484,	7305,	15829,
		5024,	17730,	17879,
		7031,	12346,	15024,
		179,	6365,	11352,
		2490,	3143,	5098,
		2643,	3101,	21259,
		4315,	4724,	13130,
		594,	17365,	18322,
		5983,	8597,	9627,
		10837,	15102,	20876,
		10448,	20418,	21478,
		3848,	12029,	15228,
		708,	5652,	13146,
		5998,	7534,	16117,
		2098,	13201,	18317,
		9186,	14548,	17776,
		5246,	10398,	18597,
		3083,	4944,	21021,
		13726,	18495,	19921,
		6736,	10811,	17545,
		10084,	12411,	14432,
		1064,	13555,	17033,
		679,	9878,	13547,
		3422,	9910,	20194,
		3640,	3701,	10046,
		5862,	10134,	11498,
		5923,	9580,	15060,
		1073,	3012,	16427,
		5527,	20113,	20883,
		7058,	12924,	15151,
		9764,	12230,	17375,
		772,	7711,	12723,
		555,	13816,	15376,
		10574,	11268,	17932,
		15442,	17266,	20482,
		390,	3371,	8781,
		10512,	12216,	17180,
		4309,	14068,	15783,
		3971,	11673,	20009,
		9259,	14270,	17199,
		2947,	5852,	20101,
		3965,	9722,	15363,
		1429,	5689,	16771,
		6101,	6849,	12781,
		3676,	9347,	18761,
		350,	11659,	18342,
		5961,	14803,	16123,
		2113,	9163,	13443,
		2155,	9808,	12885,
		2861,	7988,	11031,
		7309,	9220,	20745,
		6834,	8742,	11977,
		2133,	12908,	14704,
		10170,	13809,	18153,
		13464,	14787,	14975,
		799,	1107,	3789,
		3571,	8176,	10165,
		5433,	13446,	15481,
		3351,	6767,	12840,
		8950,	8974,	11650,
		1430,	4250,	21332,
		6283,	10628,	15050,
		8632,	14404,	16916,
		6509,	10702,	16278,
		15900,	16395,	17995,
		8031,	18420,	19733,
		3747,	4634,	17087,
		4453,	6297,	16262,
		2792,	3513,	17031,
		14846,	20893,	21563,
		17220,	20436,	21337,
		275,	4107,	10497,
		3536,	7520,	10027,
		14089,	14943,	19455,
		1965,	3931,	21104,
		2439,	11565,	17932,
		154,	15279,	21414,
		10017,	11269,	16546,
		7169,	10161,	16928,
		10284,	16791,	20655,
		36,	3175,	8475,
		2605,	16269,	19290,
		8947,	9178,	15420,
		5687,	9156,	12408,
		8096,	9738,	14711,
		4935,	8093,	19266,
		2667,	10062,	15972,
		6389,	11318,	14417,
		8800,	18137,	18434,
		5824,	5927,	15314,
		6056,	13168,	15179,
		3284,	13138,	18919,
		13115,	17259,	17332,
	};
};

struct DVB_T2_TABLE_A6
{
	static const int M = 360;
	static const int N = 64800;
	static const int K = 54000;
	static const int LINKS_MIN_CN = 21;
	static const int LINKS_MAX_CN = 22;
	static const int LINKS_TOTAL = 237599;
	static const int DEG_MAX = 13;
	static constexpr int DEG[] = {
		13, 3, 0
	};
	static constexpr int LEN[] = {
		15, 135, 0
	};
	static constexpr int POS[] = {
		0,	4362,	416,	8909,	4156,	3216,	3112,	2560,	2912,	6405,	8593,	4969,	6723,
		1,	2479,	1786,	8978,	3011,	4339,	9313,	6397,	2957,	7288,	5484,	6031,	10217,
		2,	10175,	9009,	9889,	3091,	4985,	7267,	4092,	8874,	5671,	2777,	2189,	8716,
		3,	9052,	4795,	3924,	3370,	10058,	1128,	9996,	10165,	9360,	4297,	434,	5138,
		4,	2379,	7834,	4835,	2327,	9843,	804,	329,	8353,	7167,	3070,	1528,	7311,
		5,	3435,	7871,	348,	3693,	1876,	6585,	10340,	7144,	5870,	2084,	4052,	2780,
		6,	3917,	3111,	3476,	1304,	10331,	5939,	5199,	1611,	1991,	699,	8316,	9960,
		7,	6883,	3237,	1717,	10752,	7891,	9764,	4745,	3888,	10009,	4176,	4614,	1567,
		8,	10587,	2195,	1689,	2968,	5420,	2580,	2883,	6496,	111,	6023,	1024,	4449,
		9,	3786,	8593,	2074,	3321,	5057,	1450,	3840,	5444,	6572,	3094,	9892,	1512,
		10,	8548,	1848,	10372,	4585,	7313,	6536,	6379,	1766,	9462,	2456,	5606,	9975,
		11,	8204,	10593,	7935,	3636,	3882,	394,	5968,	8561,	2395,	7289,	9267,	9978,
		12,	7795,	74,	1633,	9542,	6867,	7352,	6417,	7568,	10623,	725,	2531,	9115,
		13,	7151,	2482,	4260,	5003,	10105,	7419,	9203,	6691,	8798,	2092,	8263,	3755,
		14,	3600,	570,	4527,	200,	9718,	6771,	1995,	8902,	5446,	768,	1103,	6520,
		15,	6304,	7621,
		16,	6498,	9209,
		17,	7293,	6786,
		18,	5950,	1708,
		19,	8521,	1793,
		20,	6174,	7854,
		21,	9773,	1190,
		22,	9517,	10268,
		23,	2181,	9349,
		24,	1949,	5560,
		25,	1556,	555,
		26,	8600,	3827,
		27,	5072,	1057,
		28,	7928,	3542,
		29,	3226,	3762,
		0,	7045,	2420,
		1,	9645,	2641,
		2,	2774,	2452,
		3,	5331,	2031,
		4,	9400,	7503,
		5,	1850,	2338,
		6,	10456,	9774,
		7,	1692,	9276,
		8,	10037,	4038,
		9,	3964,	338,
		10,	2640,	5087,
		11,	858,	3473,
		12,	5582,	5683,
		13,	9523,	916,
		14,	4107,	1559,
		15,	4506,	3491,
		16,	8191,	4182,
		17,	10192,	6157,
		18,	5668,	3305,
		19,	3449,	1540,
		20,	4766,	2697,
		21,	4069,	6675,
		22,	1117,	1016,
		23,	5619,	3085,
		24,	8483,	8400,
		25,	8255,	394,
		26,	6338,	5042,
		27,	6174,	5119,
		28,	7203,	1989,
		29,	1781,	5174,
		0,	1464,	3559,
		1,	3376,	4214,
		2,	7238,	67,
		3,	10595,	8831,
		4,	1221,	6513,
		5,	5300,	4652,
		6,	1429,	9749,
		7,	7878,	5131,
		8,	4435,	10284,
		9,	6331,	5507,
		10,	6662,	4941,
		11,	9614,	10238,
		12,	8400,	8025,
		13,	9156,	5630,
		14,	7067,	8878,
		15,	9027,	3415,
		16,	1690,	3866,
		17,	2854,	8469,
		18,	6206,	630,
		19,	363,	5453,
		20,	4125,	7008,
		21,	1612,	6702,
		22,	9069,	9226,
		23,	5767,	4060,
		24,	3743,	9237,
		25,	7018,	5572,
		26,	8892,	4536,
		27,	853,	6064,
		28,	8069,	5893,
		29,	2051,	2885,
		0,	10691,	3153,
		1,	3602,	4055,
		2,	328,	1717,
		3,	2219,	9299,
		4,	1939,	7898,
		5,	617,	206,
		6,	8544,	1374,
		7,	10676,	3240,
		8,	6672,	9489,
		9,	3170,	7457,
		10,	7868,	5731,
		11,	6121,	10732,
		12,	4843,	9132,
		13,	580,	9591,
		14,	6267,	9290,
		15,	3009,	2268,
		16,	195,	2419,
		17,	8016,	1557,
		18,	1516,	9195,
		19,	8062,	9064,
		20,	2095,	8968,
		21,	753,	7326,
		22,	6291,	3833,
		23,	2614,	7844,
		24,	2303,	646,
		25,	2075,	611,
		26,	4687,	362,
		27,	8684,	9940,
		28,	4830,	2065,
		29,	7038,	1363,
		0,	1769,	7837,
		1,	3801,	1689,
		2,	10070,	2359,
		3,	3667,	9918,
		4,	1914,	6920,
		5,	4244,	5669,
		6,	10245,	7821,
		7,	7648,	3944,
		8,	3310,	5488,
		9,	6346,	9666,
		10,	7088,	6122,
		11,	1291,	7827,
		12,	10592,	8945,
		13,	3609,	7120,
		14,	9168,	9112,
		15,	6203,	8052,
		16,	3330,	2895,
		17,	4264,	10563,
		18,	10556,	6496,
		19,	8807,	7645,
		20,	1999,	4530,
		21,	9202,	6818,
		22,	3403,	1734,
		23,	2106,	9023,
		24,	6881,	3883,
		25,	3895,	2171,
		26,	4062,	6424,
		27,	3755,	9536,
		28,	4683,	2131,
		29,	7347,	8027,
	};
};

struct DVB_T2_TABLE_B7
{
	static const int M = 360;
	static const int N = 16200;
	static const int K = 13320;
	static const int LINKS_MIN_CN = 15;
	static const int LINKS_MAX_CN = 19;
	static const int LINKS_TOTAL = 49319;
	static const int DEG_MAX = 13;
	static constexpr int DEG[] = {
		13, 3, 0
	};
	static constexpr int LEN[] = {
		1, 36, 0
	};
	static constexpr int POS[] = {
		3,	2409,	499,	1481,	908,	559,	716,	1270,	333,	2508,	2264,	1702,	2805,
		4,	2447,	1926,
		5,	414,	1224,
		6,	2114,	842,
		7,	212,	573,
		0,	2383,	2112,
		1,	2286,	2348,
		2,	545,	819,
		3,	1264,	143,
		4,	1701,	2258,
		5,	964,	166,
		6,	114,	2413,
		7,	2243,	81,
		0,	1245,	1581,
		1,	775,	169,
		2,	1696,	1104,
		3,	1914,	2831,
		4,	532,	1450,
		5,	91,	974,
		6,	497,	2228,
		7,	2326,	1579,
		0,	2482,	256,
		1,	1117,	1261,
		2,	1257,	1658,
		3,	1478,	1225,
		4,	2511,	980,
		5,	2320,	2675,
		6,	435,	1278,
		7,	228,	503,
		0,	1885,	2369,
		1,	57,	483,
		2,	838,	1050,
		3,	1231,	1990,
		4,	1738,	68,
		5,	2392,	951,
		6,	163,	645,
		7,	2644,	1704,
	};
};

constexpr int DVB_T2_TABLE_A1::DEG[];
constexpr int DVB_T2_TABLE_A1::LEN[];
constexpr int DVB_T2_TABLE_A1::POS[];

constexpr int DVB_T2_TABLE_A3::DEG[];
constexpr int DVB_T2_TABLE_A3::LEN[];
constexpr int DVB_T2_TABLE_A3::POS[];

constexpr int DVB_T2_TABLE_A6::DEG[];
constexpr int DVB_T2_TABLE_A6::LEN[];
constexpr int DVB_T2_TABLE_A6::POS[];

constexpr int DVB_T2_TABLE_B7::DEG[];
constexpr int DVB_T2_TABLE_B7::LEN[];
constexpr int DVB_T2_TABLE_B7::POS[];

#if 0
typedef DVB_T2_TABLE_A1 TABLE;
static const float QEF_SNR = -1.8;
static const int BCH_T = 12;
#endif
#if 1
typedef DVB_T2_TABLE_A3 TABLE;
static const float QEF_SNR = 0.3;
static const int BCH_T = 10;
#endif
#if 0
typedef DVB_T2_TABLE_A6 TABLE;
static const float QEF_SNR = 2.2;
static const int BCH_T = 10;
#endif
#if 0
typedef DVB_T2_TABLE_B7 TABLE;
static const float QEF_SNR = 2.5;
static const int BCH_T = 12;
#endif

int main()
{
	const int TRIALS = 25;
	const int FACTOR = 2;
	const int BETA = 1;

	const int CODE_LEN = TABLE::N;
	const int DATA_LEN = TABLE::K;

	CODE::LDPCEncoder<TABLE> encode;
	CODE::LDPCDecoder<TABLE, BETA> decode;

	std::random_device rd;
	std::default_random_engine generator(rd());
	typedef std::uniform_int_distribution<int> uniform;
	typedef std::normal_distribution<float> normal;

	int8_t *code = new int8_t[CODE_LEN];
	int8_t *orig = new int8_t[CODE_LEN];
	int8_t *noisy = new int8_t[CODE_LEN];
	float *symb = new float[CODE_LEN];

	float min_SNR = 20, min_mbs = 1000, max_mbs = 0;

	for (float SNR = -5; SNR <= 15; SNR += 0.1) {
		//float mean_signal = 0;
		float sigma_signal = 1;
		float mean_noise = 0;
		float sigma_noise = std::sqrt(sigma_signal * sigma_signal / (2 * std::pow(10, SNR / 10)));

		auto data = std::bind(uniform(0, 1), generator);
		auto awgn = std::bind(normal(mean_noise, sigma_noise), generator);

		for (int i = 0; i < DATA_LEN; ++i)
			code[i] = 1 - 2 * data();

		encode(code, code + DATA_LEN);

		for (int i = 0; i < CODE_LEN; ++i)
			orig[i] = code[i];

		for (int i = 0; i < CODE_LEN; ++i)
			symb[i] = code[i];

		for (int i = 0; i < CODE_LEN; ++i)
			symb[i] += awgn();

		// $LLR=log(\frac{p(x=+1|y)}{p(x=-1|y)})$
		// $p(x|\mu,\sigma)=\frac{1}{\sqrt{2\pi}\sigma}}e^{-\frac{(x-\mu)^2}{2\sigma^2}}$
		float DIST = 2; // BPSK
		float fact = DIST * FACTOR / (sigma_noise * sigma_noise);
		for (int i = 0; i < CODE_LEN; ++i)
			code[i] = std::min<float>(std::max<float>(std::nearbyint(fact * symb[i]), -128), 127);

		for (int i = 0; i < CODE_LEN; ++i)
			noisy[i] = code[i];

		auto start = std::chrono::system_clock::now();
		int count = decode(code, code + DATA_LEN, TRIALS);
		auto end = std::chrono::system_clock::now();
		auto usec = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
		float mbs = (float)DATA_LEN / usec.count();
		int iters = count < 0 ? TRIALS : TRIALS - count;

		int awgn_errors = 0;
		for (int i = 0; i < CODE_LEN; ++i)
			awgn_errors += noisy[i] * orig[i] < 0;
		int quantization_erasures = 0;
		for (int i = 0; i < CODE_LEN; ++i)
			quantization_erasures += !noisy[i];
		int uncorrected_errors = 0;
		for (int i = 0; i < CODE_LEN; ++i)
			uncorrected_errors += code[i] * orig[i] <= 0;
		int decoder_errors = 0;
		for (int i = 0; i < CODE_LEN; ++i)
			decoder_errors += code[i] * orig[i] <= 0 && orig[i] * noisy[i] > 0;
		float bit_error_rate = (float)uncorrected_errors / (float)(CODE_LEN);

		if (uncorrected_errors <= BCH_T)
			min_SNR = std::min(min_SNR, SNR);
		min_mbs = std::min(min_mbs, mbs);
		max_mbs = std::max(max_mbs, mbs);

		if (0) {
			std::cerr << SNR << " Es/N0 => AWGN with standard deviation of " << sigma_noise << " and mean " << mean_noise << std::endl;
			std::cerr << awgn_errors << " errors caused by AWGN." << std::endl;
			std::cerr << quantization_erasures << " erasures caused by quantization." << std::endl;
			std::cerr << decoder_errors << " errors caused by decoder." << std::endl;
			std::cerr << uncorrected_errors << " errors uncorrected." << std::endl;
			std::cerr << bit_error_rate << " bit error rate." << std::endl;
			if (count < 0) {
				std::cerr << "decoder failed at converging to a code word!" << std::endl;
			} else {
				std::cerr << iters << " iterations were needed." << std::endl;
			}
			std::cerr << usec.count() << " microseconds to decode." << std::endl;
			std::cerr << mbs << " megabit per second." << std::endl;
		} else {
			std::cout << SNR << " " << bit_error_rate << " " << iters << " " << mbs << std::endl;
		}
	}

	delete[] code;
	delete[] orig;
	delete[] noisy;
	delete[] symb;

	std::cerr << "QEF at: " << min_SNR << " SNR, speed min: " << min_mbs << " Mb/s and speed max: " << max_mbs << " Mb/s." << std::endl;
	assert(min_SNR < QEF_SNR);
	std::cerr << "Low-density parity-check code regression test passed!" << std::endl;
	return 0;
}

