sz_float.c 13.6 KB
Newer Older
T
tickduan 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/**
 *  @file sz_float.c
 *  @author Sheng Di, Dingwen Tao, Xin Liang, Xiangyu Zou, Tao Lu, Wen Xia, Xuan Wang, Weizhe Zhang
 *  @date Aug, 2016
 *  @brief SZ_Init, Compression and Decompression functions
 *  (C) 2016 by Mathematics and Computer Science (MCS), Argonne National Laboratory.
 *      See COPYRIGHT in top-level directory.
 */


#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "sz.h"
#include "CompressElement.h"
#include "DynamicByteArray.h"
#include "TightDataPointStorageF.h"
#include "sz_float.h"
#include "szd_float.h"
#include "zlib.h"
#include "utility.h"

T
tickduan 已提交
25 26 27
# define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b))


T
tickduan 已提交
28

T
tickduan 已提交
29
void computeReqLength_float(double realPrecision, short rangeExpo, int* reqLength, float* medianValue)
T
tickduan 已提交
30
{
T
tickduan 已提交
31 32
	short realPrecExpo = getPrecisionReqLength_double(realPrecision);
	*reqLength = 9 + rangeExpo - realPrecExpo + 1; //radExpo-reqExpo == reqMantiLength
T
tickduan 已提交
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
	if(*reqLength<9)
		*reqLength = 9;
	if(*reqLength>32)
	{	
		*reqLength = 32;
		*medianValue = 0;
	}			
}


unsigned int optimize_intervals_float_1D(float *oriData, size_t dataLength, double realPrecision)
{	
	size_t i = 0, radiusIndex;
	float pred_value = 0, pred_err;
	size_t *intervals = (size_t*)malloc(confparams_cpr->maxRangeRadius*sizeof(size_t));
	memset(intervals, 0, confparams_cpr->maxRangeRadius*sizeof(size_t));
	size_t totalSampleSize = dataLength/confparams_cpr->sampleDistance;
	for(i=2;i<dataLength;i++)
	{
		if(i%confparams_cpr->sampleDistance==0)
		{
			//pred_value = 2*oriData[i-1] - oriData[i-2];
			pred_value = oriData[i-1];
			pred_err = fabs(pred_value - oriData[i]);
			radiusIndex = (unsigned long)((pred_err/realPrecision+1)/2);
			if(radiusIndex>=confparams_cpr->maxRangeRadius)
				radiusIndex = confparams_cpr->maxRangeRadius - 1;			
			intervals[radiusIndex]++;
		}
	}
	//compute the appropriate number
	size_t targetCount = totalSampleSize*confparams_cpr->predThreshold;
	size_t sum = 0;
	for(i=0;i<confparams_cpr->maxRangeRadius;i++)
	{
		sum += intervals[i];
		if(sum>targetCount)
			break;
	}
	if(i>=confparams_cpr->maxRangeRadius)
		i = confparams_cpr->maxRangeRadius-1;
		
	unsigned int accIntervals = 2*(i+1);
	unsigned int powerOf2 = roundUpToPowerOf2(accIntervals);
	
	if(powerOf2<32)
		powerOf2 = 32;
	
	free(intervals);
	//printf("accIntervals=%d, powerOf2=%d\n", accIntervals, powerOf2);
	return powerOf2;
}

TightDataPointStorageF* SZ_compress_float_1D_MDQ(float *oriData, 
T
tickduan 已提交
87
				size_t dataLength, float realPrecision, float valueRangeSize, float medianValue_f)
T
tickduan 已提交
88 89 90 91 92 93 94
{
	unsigned int quantization_intervals;
	if(exe_params->optQuantMode==1)
		quantization_intervals = optimize_intervals_float_1D_opt(oriData, dataLength, realPrecision);
	else
		quantization_intervals = exe_params->intvCapacity;
	//updateQuantizationInfo(quantization_intervals);	
T
tickduan 已提交
95
	int half_interval = quantization_intervals/2;
T
tickduan 已提交
96

T
tickduan 已提交
97 98 99
    //
	// calc reqlength and need set medianValue to zero. 
	// 
T
tickduan 已提交
100
	size_t i;
T
tickduan 已提交
101
	int reqLength; // need save bits length for one float .  value ragne 9~32 
T
tickduan 已提交
102
	float medianValue = medianValue_f;
T
tickduan 已提交
103
	short rangeExpo = getExponent_float(valueRangeSize/2);
T
tickduan 已提交
104
	
T
tickduan 已提交
105
	computeReqLength_float(realPrecision, rangeExpo, &reqLength, &medianValue);	
T
tickduan 已提交
106

T
tickduan 已提交
107 108 109
	//
	//  malloc all 
	//
T
tickduan 已提交
110
	
T
tickduan 已提交
111 112 113 114
	// 1 type 
	int* type = (int*) malloc(dataLength*sizeof(int));	
	float* spaceFillingValue = oriData; //
	// 2 lead
T
tickduan 已提交
115 116
	DynamicIntArray *exactLeadNumArray;
	new_DIA(&exactLeadNumArray, DynArrayInitLen);
T
tickduan 已提交
117
	// 3 mid
T
tickduan 已提交
118 119
	DynamicByteArray *exactMidByteArray;
	new_DBA(&exactMidByteArray, DynArrayInitLen);
T
tickduan 已提交
120
	// 4 residual bit
T
tickduan 已提交
121 122 123
	DynamicIntArray *resiBitArray;
	new_DIA(&resiBitArray, DynArrayInitLen);
	
T
tickduan 已提交
124 125
	unsigned char preDiffBytes[4];
	intToBytes_bigEndian(preDiffBytes, 0);
T
tickduan 已提交
126
	
T
tickduan 已提交
127
	// calc save byte length and bit lengths with reqLength
T
tickduan 已提交
128 129
	int reqBytesLength = reqLength/8;
	int resiBitsLength = reqLength%8;
T
tickduan 已提交
130
	//float last3CmprsData[3] = {0};
T
tickduan 已提交
131 132 133 134 135 136 137

	FloatValueCompressElement *vce = (FloatValueCompressElement*)malloc(sizeof(FloatValueCompressElement));
	LossyCompressionElement *lce = (LossyCompressionElement*)malloc(sizeof(LossyCompressionElement));
				
	//add the first data	
	type[0] = 0;
	compressSingleFloatValue(vce, spaceFillingValue[0], realPrecision, medianValue, reqLength, reqBytesLength, resiBitsLength);
T
tickduan 已提交
138 139 140 141
	// set lce
	updateLossyCompElement_Float(vce->curBytes, preDiffBytes, reqBytesLength, resiBitsLength, lce);
	memcpy(preDiffBytes, vce->curBytes, 4);
	// lce to arrays
T
tickduan 已提交
142
	addExactData(exactMidByteArray, exactLeadNumArray, resiBitArray, lce);
T
tickduan 已提交
143
	//listAdd_float(last3CmprsData, vce->data);
T
tickduan 已提交
144 145 146 147
		
	//add the second data
	type[1] = 0;
	compressSingleFloatValue(vce, spaceFillingValue[1], realPrecision, medianValue, reqLength, reqBytesLength, resiBitsLength);
T
tickduan 已提交
148 149
	updateLossyCompElement_Float(vce->curBytes, preDiffBytes, reqBytesLength, resiBitsLength, lce);
	memcpy(preDiffBytes, vce->curBytes, 4);
T
tickduan 已提交
150
	addExactData(exactMidByteArray, exactLeadNumArray, resiBitArray, lce);
T
tickduan 已提交
151
	//listAdd_float(last3CmprsData, vce->data);
T
tickduan 已提交
152

T
tickduan 已提交
153 154
	int state;
	float checkRadius;
T
tickduan 已提交
155
	float oriFloat;
T
tickduan 已提交
156
	float pred = vce->data;
T
tickduan 已提交
157
	float diff;
T
tickduan 已提交
158
	checkRadius = (quantization_intervals-1)*realPrecision;
T
tickduan 已提交
159
	float double_realpreci = 2*realPrecision;
T
tickduan 已提交
160 161
	float recip_precision = 1/realPrecision;
	
T
tickduan 已提交
162
	for(i=2; i < dataLength; i++)
T
tickduan 已提交
163
	{	
T
tickduan 已提交
164
		oriFloat = spaceFillingValue[i];
T
tickduan 已提交
165 166
		//pred = 2*last3CmprsData[0] - last3CmprsData[1];
		//pred = last3CmprsData[0];
T
tickduan 已提交
167 168
		diff = fabsf(oriFloat - pred);	
		if(diff < checkRadius)
T
tickduan 已提交
169
		{
T
tickduan 已提交
170 171
			state = ((int)( diff * recip_precision + 1))>>1;
			if(oriFloat >= pred)
T
tickduan 已提交
172
			{
T
tickduan 已提交
173 174
				type[i] = half_interval + state;
				pred = pred + state * double_realpreci;
T
tickduan 已提交
175 176 177
			}
			else //curData<pred
			{
T
tickduan 已提交
178 179
				type[i] = half_interval - state;
				pred = pred - state * double_realpreci;
T
tickduan 已提交
180 181 182
			}
				
			//double-check the prediction error in case of machine-epsilon impact	
T
tickduan 已提交
183
			if(fabs(oriFloat - pred) > realPrecision)
T
tickduan 已提交
184 185
			{	
				type[i] = 0;				
T
tickduan 已提交
186 187 188
				compressSingleFloatValue(vce, oriFloat, realPrecision, medianValue, reqLength, reqBytesLength, resiBitsLength);
				updateLossyCompElement_Float(vce->curBytes, preDiffBytes, reqBytesLength, resiBitsLength, lce);
				memcpy(preDiffBytes, vce->curBytes, 4);
T
tickduan 已提交
189 190 191
				addExactData(exactMidByteArray, exactLeadNumArray, resiBitArray, lce);		
				
				//listAdd_float(last3CmprsData, vce->data);	
T
tickduan 已提交
192
				pred = vce->data;				
T
tickduan 已提交
193 194 195
			}
			else
			{
T
tickduan 已提交
196
				//listAdd_float(last3CmprsData, pred);	
T
tickduan 已提交
197
			}	
T
tickduan 已提交
198
			// go next
T
tickduan 已提交
199 200 201 202 203
			continue;
		}
		
		//unpredictable data processing		
		type[i] = 0;		
T
tickduan 已提交
204 205 206
		compressSingleFloatValue(vce, oriFloat, realPrecision, medianValue, reqLength, reqBytesLength, resiBitsLength);
		updateLossyCompElement_Float(vce->curBytes, preDiffBytes, reqBytesLength, resiBitsLength, lce);
		memcpy(preDiffBytes, vce->curBytes, 4);
T
tickduan 已提交
207 208 209
		addExactData(exactMidByteArray, exactLeadNumArray, resiBitArray, lce);

		//listAdd_float(last3CmprsData, vce->data);
T
tickduan 已提交
210
		pred = vce->data;	
T
tickduan 已提交
211 212 213 214 215 216 217
		
	}//end of for
		
//	char* expSegmentsInBytes;
//	int expSegmentsInBytes_size = convertESCToBytes(esc, &expSegmentsInBytes);
	size_t exactDataNum = exactLeadNumArray->size;
	
T
tickduan 已提交
218
	TightDataPointStorageF* tdps = NULL;			
T
tickduan 已提交
219 220 221 222 223
	new_TightDataPointStorageF(&tdps, dataLength, exactDataNum, 
			type, exactMidByteArray->array, exactMidByteArray->size,  
			exactLeadNumArray->array,  
			resiBitArray->array, resiBitArray->size, 
			resiBitsLength,
T
tickduan 已提交
224
			realPrecision, medianValue, (char)reqLength, quantization_intervals, 0);
T
tickduan 已提交
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

//sdi:Debug
/*	int sum =0;
	for(i=0;i<dataLength;i++)
		if(type[i]==0) sum++;
	printf("opt_quantizations=%d, exactDataNum=%zu, sum=%d\n",quantization_intervals, exactDataNum, sum);
*/	
	//free memory
	free_DIA(exactLeadNumArray);
	free_DIA(resiBitArray);
	free(type);	
	free(vce);
	free(lce);	
	free(exactMidByteArray); //exactMidByteArray->array has been released in free_TightDataPointStorageF(tdps);
	
	return tdps;
}

T
tickduan 已提交
243 244 245
// compress core algorithm  if success return true else return false
bool SZ_compress_args_float_NoCkRngeNoGzip_1D( unsigned char* newByteData, float *oriData, 
                   size_t dataLength, double realPrecision, size_t *outSize, float valueRangeSize, float medianValue_f)
T
tickduan 已提交
246
{		
T
tickduan 已提交
247
	// get tdps
T
tickduan 已提交
248
	TightDataPointStorageF* tdps = NULL;	
T
tickduan 已提交
249
	tdps = SZ_compress_float_1D_MDQ(oriData, dataLength, realPrecision, valueRangeSize, medianValue_f);	
T
tickduan 已提交
250 251 252 253 254 255 256 257 258 259 260
	if(tdps == NULL)
	  return false;

    // serialize 
	if(!convertTDPStoFlatBytes_float(tdps, newByteData, outSize))
	{
		free_TightDataPointStorageF(tdps);
		return false;
	}
	  
	// check compressed size large than original
T
tickduan 已提交
261
	if(*outSize > 1 + MetaDataByteLength + exe_params->SZ_SIZE_TYPE + 1 + sizeof(float)*dataLength)
T
tickduan 已提交
262 263 264
	{
		return false;
	}	
T
tickduan 已提交
265 266
	
	free_TightDataPointStorageF(tdps);
T
tickduan 已提交
267
	return true;
T
tickduan 已提交
268 269 270
}


T
tickduan 已提交
271
void SZ_compress_args_float_withinRange(unsigned char* newByteData, float *oriData, size_t dataLength, size_t *outSize)
T
tickduan 已提交
272 273 274 275
{
	TightDataPointStorageF* tdps = (TightDataPointStorageF*) malloc(sizeof(TightDataPointStorageF));
	tdps->leadNumArray = NULL;
	tdps->residualMidBits = NULL;
T
tickduan 已提交
276
	
T
tickduan 已提交
277 278 279 280 281 282 283
	tdps->allSameData = 1;
	tdps->dataSeriesLength = dataLength;
	tdps->exactMidBytes = (unsigned char*)malloc(sizeof(unsigned char)*4);
	tdps->isLossless = 0;
	float value = oriData[0];
	floatToBytes(tdps->exactMidBytes, value);
	tdps->exactMidBytes_size = 4;
T
tickduan 已提交
284
	
T
tickduan 已提交
285 286 287 288 289 290 291 292
	size_t tmpOutSize;
	//unsigned char *tmpByteData;
	convertTDPStoFlatBytes_float(tdps, newByteData, &tmpOutSize);

	//*newByteData = (unsigned char*)malloc(sizeof(unsigned char)*12); //for floating-point data (1+3+4+4)
	//memcpy(*newByteData, tmpByteData, 12);
	*outSize = tmpOutSize; //8+SZ_SIZE_TYPE; //8==3+1+4(float_size)
	free_TightDataPointStorageF(tdps);	
T
tickduan 已提交
293 294
}

T
tickduan 已提交
295 296 297 298
void cost_start();
double cost_end(const char* tag);
void show_rate( int in_len, int out_len);

T
tickduan 已提交
299
int SZ_compress_args_float(float *oriData, size_t r1, unsigned char* newByteData, size_t *outSize, sz_params* params)
T
tickduan 已提交
300
{
T
tickduan 已提交
301 302
	int status = SZ_SUCCESS;
	size_t dataLength = r1;
T
tickduan 已提交
303
	
T
tickduan 已提交
304
	//cost_start();
T
tickduan 已提交
305
	// check at least elements count  
T
tickduan 已提交
306 307
	if(dataLength <= MIN_NUM_OF_ELEMENTS)
	{
T
tickduan 已提交
308
		printf("error, input elements count=%d less than %d, so need not do compress.\n", (int)dataLength, MIN_NUM_OF_ELEMENTS);
T
tickduan 已提交
309
		return SZ_LITTER_ELEMENT;
T
tickduan 已提交
310 311 312 313
	}
	
	float valueRangeSize = 0, medianValue = 0;
	float min = 0;
T
tickduan 已提交
314

T
tickduan 已提交
315
	min = computeRangeSize_float(oriData, dataLength, &valueRangeSize, &medianValue);	
T
tickduan 已提交
316 317

	// calc max
T
tickduan 已提交
318
	float max = min+valueRangeSize;
T
tickduan 已提交
319 320
	params->fmin = min;
	params->fmax = max;
T
tickduan 已提交
321
	
T
tickduan 已提交
322
	// calc precision
T
tickduan 已提交
323
	double realPrecision = 0; 
T
tickduan 已提交
324
	if(params->errorBoundMode==PSNR)
T
tickduan 已提交
325
	{
T
tickduan 已提交
326 327
		params->errorBoundMode = SZ_ABS;
		realPrecision = params->absErrBound = computeABSErrBoundFromPSNR(params->psnr, (double)params->predThreshold, (double)valueRangeSize);
T
tickduan 已提交
328 329
		//printf("realPrecision=%lf\n", realPrecision);
	}
T
tickduan 已提交
330
	else if(params->errorBoundMode==NORM) //norm error = sqrt(sum((xi-xi_)^2))
T
tickduan 已提交
331
	{
T
tickduan 已提交
332 333
		params->errorBoundMode = SZ_ABS;
		realPrecision = params->absErrBound = computeABSErrBoundFromNORM_ERR(params->normErr, dataLength);
T
tickduan 已提交
334
		//printf("realPrecision=%lf\n", realPrecision);				
T
tickduan 已提交
335 336 337
	}
	else
	{
T
tickduan 已提交
338 339
		realPrecision = getRealPrecision_float(valueRangeSize, params->errorBoundMode, params->absErrBound, params->relBoundRatio, &status);
		params->absErrBound = realPrecision;
T
tickduan 已提交
340
	}	
T
tickduan 已提交
341

T
tickduan 已提交
342 343 344 345 346
	//cost_end(" sz_pre_calc");

    //
	// do compress 
	//
T
tickduan 已提交
347
	if(valueRangeSize <= realPrecision)
T
tickduan 已提交
348
	{		
T
tickduan 已提交
349
		// special deal with same data
T
tickduan 已提交
350
		SZ_compress_args_float_withinRange(newByteData, oriData, dataLength, outSize);
T
tickduan 已提交
351
		return SZ_SUCCESS;
T
tickduan 已提交
352
	}
T
tickduan 已提交
353

T
tickduan 已提交
354 355 356 357 358 359 360 361 362 363
	//
	// first compress with sz
	//		
	size_t tmpOutSize = 0;
	unsigned char* tmpByteData  =  newByteData;
	bool twoStage =  params->szMode != SZ_BEST_SPEED;
	if(twoStage)
	{
		tmpByteData = (unsigned char*)malloc(r1*sizeof(float) + 1024);
	}
T
tickduan 已提交
364

T
tickduan 已提交
365 366
	// compress core algorithm
	if(!SZ_compress_args_float_NoCkRngeNoGzip_1D(tmpByteData, oriData, r1, realPrecision, &tmpOutSize, valueRangeSize, medianValue))
T
tickduan 已提交
367
	{
T
tickduan 已提交
368 369 370 371
		*outSize = 0;
		if(twoStage)
			free(tmpByteData);
		return SZ_ALGORITHM_ERR;
T
tickduan 已提交
372
	}
T
tickduan 已提交
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392

    //cost_end(" sz_first_compress");
	//show_rate(r1*sizeof(float), *outSize);
	//
	//  second compress with Call Zstd or Gzip 
	//
	//cost_start();
	if(!twoStage)
	{
		*outSize = tmpOutSize;
	}
	else
	{
		*outSize = sz_lossless_compress(params->losslessCompressor, params->gzipMode, tmpByteData, tmpOutSize, newByteData);
		free(tmpByteData);	
	}

	//cost_end(" sz_second_compress");
	//show_rate(r1*sizeof(float), *outSize);
	return SZ_SUCCESS;
T
tickduan 已提交
393
}
T
tickduan 已提交
394

T
tickduan 已提交
395 396 397 398 399 400 401
unsigned int optimize_intervals_float_1D_opt(float *oriData, size_t dataLength, double realPrecision)
{	
	size_t i = 0, radiusIndex;
	float pred_value = 0, pred_err;
	size_t *intervals = (size_t*)malloc(confparams_cpr->maxRangeRadius*sizeof(size_t));
	memset(intervals, 0, confparams_cpr->maxRangeRadius*sizeof(size_t));
	size_t totalSampleSize = 0;//dataLength/confparams_cpr->sampleDistance;
T
tickduan 已提交
402

T
tickduan 已提交
403 404 405 406 407 408 409 410 411
	float * data_pos = oriData + 2;
	while(data_pos - oriData < dataLength){
		totalSampleSize++;
		pred_value = data_pos[-1];
		pred_err = fabs(pred_value - *data_pos);
		radiusIndex = (unsigned long)((pred_err/realPrecision+1)/2);
		if(radiusIndex>=confparams_cpr->maxRangeRadius)
			radiusIndex = confparams_cpr->maxRangeRadius - 1;			
		intervals[radiusIndex]++;
T
tickduan 已提交
412

T
tickduan 已提交
413 414 415 416 417 418 419 420 421 422 423 424 425
		data_pos += confparams_cpr->sampleDistance;
	}
	//compute the appropriate number
	size_t targetCount = totalSampleSize*confparams_cpr->predThreshold;
	size_t sum = 0;
	for(i=0;i<confparams_cpr->maxRangeRadius;i++)
	{
		sum += intervals[i];
		if(sum>targetCount)
			break;
	}
	if(i>=confparams_cpr->maxRangeRadius)
		i = confparams_cpr->maxRangeRadius-1;
T
tickduan 已提交
426
		
T
tickduan 已提交
427 428
	unsigned int accIntervals = 2*(i+1);
	unsigned int powerOf2 = roundUpToPowerOf2(accIntervals);
T
tickduan 已提交
429
	
T
tickduan 已提交
430 431
	if(powerOf2<32)
		powerOf2 = 32;
T
tickduan 已提交
432
	
T
tickduan 已提交
433 434 435
	free(intervals);
	return powerOf2;
}