Math-WalshTransform

 view release on metacpan or  search on metacpan

lua/WalshTransform.lua  view on Meta::CPAN

-- ----------------------------------------------------------------- --
--      This Lua5 module is Copyright (c) 2010, Peter J Billam       --
--                        www.pjb.com.au                             --
--                                                                   --
--   This module is free software; you can redistribute it and/or    --
--          modify it under the same terms as Lua5 itself.           --
-- ----------------------------------------------------------------- --
local M = {} -- public interface
M.Version = '1.17'
M.VersionDate = '12aug2010'

-- Example usage:
-- local WT = require 'WalshTransform'
-- H = WT.fht(a)

--------------------- infrastructure ----------------------
local function warn(str)
    io.stderr:write(str,'\n')
end
local function die(str)
    io.stderr:write(str,'\n')
    os.exit(1)
end
local function jw2jh(n)
	if (n < 16) then
		if n == 8 then return {0,4,6,2,3,7,5,1}; end
		if n == 4 then return {0,2,3,1}; end
		if n == 2 then return {0,1}; end
		if n == 1 then return {0}; end
		warn "jw2jh: n=$n must be power of 2\n"; return false;
	end
	local half_n = n / 2;
	local half = jw2jh(half_n)
	local whole = {}
	local i = 1; while i <= half_n do
		whole[i] = 2 * half[i]
		i = i + 1
	end
	i = half_n; local j = half_n + 1
	while i >= 1 do
		whole[j] = 1 + whole[i]
		i = i - 1
		j = j + 1
	end
	return whole
end
-------------------------------------------------------

function M.fht(a)
	local i; local mr = {}; for i=1,#a do mr[i] = a[i] end
	local k = 1
	local n = #mr
	local l = n
	local nl; local nk; local j;
	while true do
		i = 0; l = l/2;
		for nl=1,l do
			for nk=1,k do
				i = i + 1; j = i + k;
				mr[i] = (mr[i] + mr[j])/2;
				mr[j] =  mr[i] - mr[j];
			end
			i = j;
		end
		k = 2*k;
		if k >= n then break end
	end
	if k == n then
		return mr
	else
		warn("WalshTransform::fht \$n = $n but must be power of 2\n")
		return false
	end

lua/WalshTransform.lua  view on Meta::CPAN


function M.size(a)
	local sum=0.0; local i; for i=1,#a do sum = sum + a[i]*a[i] end
	return math.sqrt(sum)
end

function M.product(a,b)
	if type(a) ~= 'table' then
		warn("WalshTransform.product 1st arg must be a table\n")
		return nil
	end
	if type(b) ~= 'table' then
		warn("WalshTransform.product 2nd arg must be a table\n")
		return nil
	end
	if #a ~= #b then
		warn("WalshTransform.product the 2 args must be the same size\n")
		return nil
	end
	local c = {}; local i;
	for i=1,#a do c[i] = a[i]*b[i] end
	return c
end

function M.normalise(a)
	if type(a) ~= 'table' then
		warn("WalshTransform.product 1st arg must be a table\n")
		return nil
	end
	local s = M.size(a);  local normalised = {};  local i
	for i = 1, #a do normalised[i] = a[i]/s end
	return normalised
end

function M.average (...)
	local i = 1; local j; local sum = {}; local n = 0
	for i,a in ipairs({...}) do
		if type(a) ~= 'table' then
			warn("WalshTransform.average arg must be a table\n")
			return nil
		end
		for j=1, #a do sum[j] = (sum[j] or 0) + a[j] end
		n = n + 1
	end
	for j=1,#sum do sum[j] = sum[j] / n end
	return sum
end

return M

--[[

=pod

=head1 NAME

WalshTransform.lua - Fast Hadamard and Walsh Transforms

=head1 SYNOPSIS

 local WT = require 'WalshTransform' -- name doesn't matter of course
 local f = {1.618, 2.718, 3.142, 4.669}  -- must be power-of-two long
 local FH1 = WT.fht(f)   -- Hadamard transform
 local fh1 = WT.fhtinv(FH1)
 -- or
 local FW2 = WT.fwt(f)   -- Walsh transform
 local fw2 = WT.fwtinv(FW2)
 local FH2 = WT.walsh2hadamard(FW2)

 local PS  = WT.power_spectrum(f)

 local whats_going_on = WT.biggest(9,WT.fwt(WT.sublist(time_series,-16)))
 local EVENT1 = WT.fwt(WT.sublist(time_series,478,16))
 local EVENT2 = WT.fwt(WT.sublist(time_series,2316,16))
 local EVENT3 = WT.fwt(WT.sublist(time_series,3261,16))
 EVENT1[1]=0.0; EVENT2[1]=0.0; EVENT3[1]=0.0 -- ignore constant
 EVENT1 = WT.normalise(EVENT1) -- ignore scale
 EVENT2 = WT.normalise(EVENT2)
 EVENT3 = WT.normalise(EVENT3)
 local TYPICAL_EVENT = WT.average(EVENT1, EVENT2, EVENT3)
 ...
 local NOW = WT.fwt(WT.sublist(time_series,-16))
 NOW[1] = 0.0
 NOW = WT.normalise(NOW)
 if WT.distance(NOW, TYPICAL_EVENT) < .28 then get_worried() end

=head1 DESCRIPTION

These routines implement fast Hadamard and Walsh Transforms
and their inverse transforms.

Also included are routines
for converting a Hadamard to a Walsh transform and vice versa,
for calculating the Logical Convolution of two lists,
or the Logical Autocorrelation of a list,
and for calculating the Walsh Power Spectrum -
in short, almost everything you ever wanted to do with a Walsh Transform.

Intelligible speech can be reconstructed by transforming
blocks of, say, 64 samples, deleting all but the several largest
transform components, and inverse-transforming;
in other words, these transforms extract from a time-series
the most significant things that are going on.
They should be useful for B<noticing important things>,
for example in software that monitors time-series data such as
system or network administration data, share-price, currency,
ecological, opinion poll, process management data, and so on.

As from version 1.10, Math::WalshTransform uses C routines to perform
the transforms. This runs 25 to 30 times faster than previous versions.

Not yet included are multi-dimensional Hadamard and Walsh Transforms,
conversion between Logical and Arithmetic Autocorrelation Functions,
or conversion between the Walsh Power Spectrum and the Fourier Power Spectrum.

Version 1.17

=head1 SUBROUTINES

Routines which take just one array as argument expect the array itself;
those which take more than one array expect a list of references.



( run in 1.028 second using v1.01-cache-2.11-cpan-39bf76dae61 )