File Coverage

lib/PDL/Compression.pd
Criterion Covered Total %
statement 6 6 100.0
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 8 8 100.0


line stmt bran cond sub pod time code
1             use strict;
2             use warnings;
3              
4             { no warnings 'once'; # pass info back to Makefile.PL
5             $PDL::Core::Dev::EXTRAS{$::PDLMOD}{OBJECT} .= join '', map " $::PDLBASE/$_\$(OBJ_EXT)", qw(ricecomp);
6             $PDL::Core::Dev::EXTRAS{$::PDLMOD}{INC} .= qq{ "-I$::PDLBASE"};
7             }
8              
9             pp_addpm({At=>'Top'},<<'EOD');
10              
11             =head1 NAME
12              
13             PDL::Compression - compression utilities
14              
15             =head1 DESCRIPTION
16              
17             These routines generally accept some data as a PDL and compress it
18             into a smaller PDL. Algorithms typically work on a single dimension
19             and broadcast over other dimensions, producing a broadcasted table of
20             compressed values if more than one dimension is fed in.
21              
22             The Rice algorithm, in particular, is designed to be identical to the
23             RICE_1 algorithm used in internal FITS-file compression (see PDL::IO::FITS).
24              
25             =head1 SYNOPSIS
26              
27             use PDL::Compression
28              
29             ($y,$xsize) = $x->rice_compress();
30             $c = $y->rice_expand($xsize);
31              
32             =cut
33 3     3   21  
  3         4  
  3         98  
34 3     3   43 use strict;
  3         5  
  3         967  
35             use warnings;
36              
37             EOD
38              
39             pp_addpm({At=>'Bot'},<<'EOD');
40              
41             =head1 AUTHORS
42              
43             Copyright (C) 2010 Craig DeForest.
44             All rights reserved. There is no warranty. You are allowed
45             to redistribute this software / documentation under certain
46             conditions. For details, see the file COPYING in the PDL
47             distribution. If this file is separated from the PDL distribution,
48             the copyright notice should be included in the file.
49              
50             The Rice compression library is derived from the similar library in
51             the CFITSIO 3.24 release, and is licensed under yet more more lenient
52             terms than PDL itself; that notice is present in the file "ricecomp.c".
53              
54             =head1 BUGS
55              
56             =over 3
57              
58             =item * Currently headers are ignored.
59              
60             =item * Currently there is only one compression algorithm.
61              
62             =back
63              
64             =head1 TODO
65              
66             =over 3
67              
68             =item * Add object encapsulation
69              
70             =item * Add test suite
71              
72             =back
73              
74             =cut
75              
76             EOD
77              
78             pp_addpm(<<'EOD');
79              
80             =head1 METHODS
81              
82             =cut
83              
84             EOD
85              
86             pp_def(
87             "rice_compress",
88             HandleBad => 0,
89             Pars => 'in(n); [o]out(m=CALC(ceil($SIZE(n) * 1.01))); indx[o]len()',
90             OtherPars => "int blocksize", # in OtherPars to avoid autopromotion
91             GenericTypes =>['B','S','US','L'],
92             Doc => <<'EOD',
93             =for ref
94              
95             Squishes an input PDL along the 0 dimension by Rice compression. In
96             scalar context, you get back only the compressed PDL; in list context,
97             you also get back ancillary information that is required to uncompress
98             the data with rice_uncompress.
99              
100             Multidimensional data are broadcasted over - each row is compressed
101             separately, and the returned PDL is squished to the maximum compressed
102             size of any row. If any of the streams could not be compressed (the
103             algorithm produced longer output), the corresponding length is set to -1
104             and the row is treated as if it had length 0.
105              
106             Rice compression only works on integer data types -- if you have
107             floating point data you must first quantize them.
108              
109             The underlying algorithm is identical to the Rice compressor used in
110             CFITSIO (and is used by PDL::IO::FITS to load and save compressed FITS
111             images).
112              
113             The optional blocksize indicates how many samples are to be compressed
114             as a unit; it defaults to 32.
115              
116             How it works:
117              
118             Rice compression is a subset of Golomb compression, and works on data sets
119             where variation between adjacent samples is typically small compared to the
120             dynamic range of each sample. In this implementation (originally written
121             by Richard White and contributed to CFITSIO in 1999), the data are divided
122             into blocks of samples (by default 32 samples per block). Each block
123             has a running difference applied, and the difference is bit-folded to make
124             it positive definite. High order bits of the difference stream are discarded,
125             and replaced with a unary representation; low order bits are preserved. Unary
126             representation is very efficient for small numbers, but large jumps could
127             give rise to ludicrously large bins in a plain Golomb code; such large jumps
128             ("high entropy" samples) are simply recorded directly in the output stream.
129              
130             Working on astronomical or solar image data, typical compression ratios of
131             2-3 are achieved.
132             EOD
133             PMCode => <<'EOD',
134             sub PDL::rice_compress {
135             my $in = shift;
136             my $blocksize = shift || 32;
137             ## Reject floating-point inputs
138             if( $in->type != byte &&
139             $in->type != short &&
140             $in->type != ushort &&
141             $in->type != long
142             ) {
143             die("rice_compress: input needs to have type byte, short, ushort, or long, not ".($in->type)."\n");
144             }
145             PDL::_rice_compress_int( $in, my $out=PDL->null, my $len=PDL->null, $blocksize );
146             my $l = $len->max->sclr;
147             $out = $out->slice("0:".($l-1))->sever;
148             return wantarray ? ($out, $in->dim(0), $blocksize, $len) : $out;
149             }
150             EOD
151             CHeader => qq{#include "ricecomp.h"\n},
152             Code => <<'EOD',
153             char *err = "error message not updated";
154             $len() = fits_rcomp$TBSUL(_byte,_short,_short,)(&err, (void *)$P(in),
155             $SIZE(n),
156             (void *)$P(out),
157             $SIZE(m) * sizeof($GENERIC(out)),
158             $COMP(blocksize)
159             );
160             if (err) $CROAK("%s", err);
161             EOD
162             );
163              
164             pp_def(
165             "rice_expand",
166             HandleBad=>0,
167             Pars=>'in(n); indx len(); [o]out(m);',
168             OtherPars=>'IV dim0 => m; int blocksize',
169             OtherParsDefaults=>{ blocksize=>32 },
170             GenericTypes=>['B','S','US','L'],
171             Doc=><<'EOD',
172             =for ref
173              
174             Unsquishes a PDL that has been squished by rice_compress.
175             EOD
176             CHeader => qq{#include "ricecomp.h"\n},
177             Code=><<'EOD',
178             char *err = fits_rdecomp$TBSUL(_byte,_short,_short,)( (void *)$P(in),
179             $len(),
180             (void *)$P(out),
181             $SIZE(m),
182             $COMP(blocksize)
183             );
184             if (err) $CROAK("%s", err);
185             EOD
186             );
187              
188             pp_done();