code: package gr.iti.mklab.reveal.forensics.util.dwt;
  
  /**
   * Author Mark Bishop; 2014
   * License GNU v3; 
   * This class is free software: you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.
  
      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.
  
      You should have received a copy of the GNU General Public License
      along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  /**
   * 		The coefficients were gathered from various sources including:
   *		Wavelab Version 850
   *		Adapted Wavelet Analysis from Theory to Software, Victor Wickerhauser
   *		A Wavelet Tour of Signal Processing, The Sparse Way, 3rd ed., Stephane Mallet
   */
  
  import java.util.ArrayList;
  
  /**
   * Class responsibility: Provide filters for several orthogonal wavelets.
   *
   */
  
  public class OrthogonalFilters {
  
  	/**
  	 * 
  	 * @param H
  	 *            low pass filter for QMF pair
  	 * @return high pass filter for QMF pair
  	 */
  	public static double[] getHighPass(double[] H) {
  		double sign = 1;
  		int n = H.length;
  		double[] G = new double[n];
  		for (int i = 0; i < n; i++) {
  			G[n - i - 1] = H[i] * sign;
  			sign *= -1;
  		}
  		return G;
  	}
  
  	/**
  	 * 
  	 * @param wavelet To be explained
  	 * @param order To be explained
  	 * @return Low Pass filter for QMF pair
  	 */
  	static double[] getLowPass(Wavelet wavelet, int order) {
  		if (wavelet == Wavelet.Haar) {
  			double[] f = { .707106781186547, .707106781186547 };
  			return f;
  		}
  		if (wavelet == Wavelet.Daubechies) {
  			switch (order) {
  			case 4: { // (Wickerhauser)
  				double[] f = { .482962913144534160, .836516303737807940,
  						.224143868042013390, -.129409522551260370 };
  				return f;
  
  			}
  			case 6: {// (Wickerhauser)
  				double[] f = { 0.332670552950082630, 0.806891509311092550,
  						0.459877502118491540, -0.135011020010254580,
  						-0.0854412738820266580, 0.0352262918857095330 };
  				return f;
  
  			}
  			case 8: {// (Wickerhauser but order reversed)
  				double[] f = { 0.2303778133090, 0.7148465705530,
  						0.6308807679300, -0.02798376941700, -0.1870348117190,
  						0.03084138183700, 0.032883011667, -0.01059740178500 };
  
  				return f;
  
  			}
  			case 10: {// (Wickerhauser but order reversed)
  				double[] f = { 0.160102397974, 0.603829269797, 0.724308528438,
  						0.138428145901, -0.242294887066, -0.032244869585,
  						0.07757149384, -0.006241490213, -0.012580751999,
  						0.003335725285 };
  				return f;
  
  			}
  			case 12: {// (Wickerhauser but order reversed)
  				double[] f = { 0.11154074335, 0.494623890398, 0.751133908021,
  						0.315250351709, -0.226264693965, -0.129766867567,
  						0.097501605587, 0.02752286553, -0.031582039318,
  						0.000553842201, 0.004777257511, -0.001077301085 };
  				return f;
  
  			}
  			case 14: {// (Wickerhauser but order reversed)
  				double[] f = { 0.077852054085, 0.396539319482, 0.729132090846,
  						0.469782287405, -0.143906003929, -0.224036184994,
  						0.071309219267, 0.080612609151, -0.038029936935,
  						-0.016574541631, 0.012550998556, 0.000429577973,
  						-0.001801640704, 0.0003537138 };
  				return f;
  
  			}
  			case 16: {// (Wickerhauser but order reversed)
  				double[] f = { 0.054415842243, 0.312871590914, 0.675630736297,
  						0.585354683654, -0.015829105256, -0.284015542962,
  						0.000472484574, 0.12874742662, -0.017369301002,
  						-0.044088253931, 0.013981027917, 0.008746094047,
  						-0.004870352993, -0.000391740373, 0.000675449406,
  						-0.000117476784 };
  				return f;
  
  			}
  			case 18: {// (Wickerhauser but order reversed)
  				double[] f = { 0.038077947364, 0.243834674613, 0.60482312369,
  						0.657288078051, 0.133197385825, -0.293273783279,
  						-0.096840783223, 0.148540749338, 0.030725681479,
  						-0.067632829061, 0.000250947115, 0.022361662124,
  						-0.004723204758, -0.004281503682, 0.001847646883,
  						0.000230385764, -0.000251963189, 0.00003934732 };
  				return f;
  
  			}
  			case 20: {// Wavelab src
  				double[] f = { 0.026670057901, 0.188176800078, 0.527201188932,
  						0.688459039454, 0.281172343661, -0.249846424327,
  						-0.195946274377, 0.127369340336, 0.093057364604,
  						-0.071394147166, -0.029457536822, 0.033212674059,
  						0.003606553567, -0.010733175483, 0.001395351747,
  						0.001992405295, -0.000685856695, -0.000116466855,
  						0.00009358867, -0.000013264203 };
  				return f;
  
  			}
  			}
  		}
  		if (wavelet == Wavelet.Beylkin) { // 18 (Wickerhauser but order
  											// reversed)
  
  			double[] f = { 0.00064048532852124535, -0.00273603162625860610,
  					0.0014842347824723461, 0.01004041184463199,
  					-0.014365807968852611, -0.017460408696028829,
  					0.042916387274192273, 0.01967986604432212,
  					-0.088543630623924835, -0.0175207462665229649,
  					0.1555387318770938, 0.02690030880369032,
  					-0.26449723144638482, -0.1109275983482343,
  					0.44971825114946867, 0.69982521405660590,
  					0.42421536081296141, 0.099305765374353927 };
  
  			return f;
  
  		}
  		if (wavelet == Wavelet.Vaidyanathan) {// length = 24 // Wavelab src
  			double[] f = { -.000062906118, .000343631905, -.000453956620,
  					-.000944897136, .002843834547, .000708137504,
  					-.008839103409, .003153847056, .019687215010,
  					-.014853448005, -.035470398607, .038742619293,
  					.055892523691, -.077709750902, -.083928884366,
  					.131971661417, .135084227129, -.194450471766,
  					-.263494802488, .201612161775, .635601059872,
  					.572797793211, .250184129505, .045799334111 };
  			return f;
  		}
  		if (wavelet == Wavelet.Coiflet) {// Wavelab src
  			switch (order) {
  			case 6: {
  				double[] f = { .038580777748, -.126969125396, -.077161555496,
  						.607491641386, .745687558934, .226584265197 };
  				return f;
  			}
  			case 12: {
  				double[] f = { .016387336463, -.041464936782, -.067372554722,
  						.386110066823, .812723635450, .417005184424,
  						-.076488599078, -.059434418646, .023680171947,
  						.005611434819, -.001823208871, -.000720549445 };
  				;
  				return f;
  			}
  			case 18: {
  				double[] f = { -.003793512864, .007782596426, .023452696142,
  						-.065771911281, -.061123390003, .405176902410,
  						.793777222626, .428483476378, -.071799821619,
  						-.082301927106, .034555027573, .015880544864,
  						-.009007976137, -.002574517688, .001117518771,
  						.000466216960, -.000070983303, -.000034599773 };
  
  				return f;
  
  			}
  			case 24: {
  				double[] f = { .000892313668, -.001629492013, -.007346166328,
  						.016068943964, .026682300156, -.081266699680,
  						-.056077313316, .415308407030, .782238930920,
  						.434386056491, -.066627474263, -.096220442034,
  						.039334427123, .025082261845, -.015211731527,
  						-.005658286686, .003751436157, .001266561929,
  						-.000589020757, -.000259974552, .000062339034,
  						.000031229876, -.000003259680, -.000001784985 };
  				return f;
  
  			}
  			case 30: {
  				double[] f = { -.000212080863, .000358589677, .002178236305,
  						-.004159358782, -.010131117538, .023408156762,
  						.028168029062, -.091920010549, -.052043163216,
  						.421566206729, .774289603740, .437991626228,
  						-.062035963906, -.105574208706, .041289208741,
  						.032683574283, -.019761779012, -.009164231153,
  						.006764185419, .002433373209, -.001662863769,
  						-.000638131296, .000302259520, .000140541149,
  						-.000041340484, -.000021315014, .000003734597,
  						.000002063806, -.000000167408, -.000000095158 };
  				return f;
  
  			}
  			}
  		}
  		if (wavelet == Wavelet.Symmlet) {// Wavelab but normalized by 1/sqrt(2)
  			switch (order) {
  
  			case 4: {
  				double[] f = { -0.07576571478935668, -0.029635527645960395,
  						0.4976186676325629, 0.803738751805386,
  						0.29785779560560505, -0.09921954357695636,
  						-0.012603967262263831, 0.03222310060407815 };
  
  				return f;
  
  			}
  			case 5: {
  				double[] f = { 0.027333068345162827, 0.029519490926071618,
  						-0.039134249302581074, 0.19939753397698343,
  						0.7234076904037638, 0.6339789634569107,
  						0.01660210576442332, -0.17532808990809687,
  						-0.021101834024928552, 0.019538882735385715 };
  
  				return f;
  
  			}
  			case 6: {
  				double[] f = { 0.0154041093273385, 0.003490712084330607,
  						-0.11799011114841682, -0.04831174258600069,
  						0.49105594192766583, 0.7876411410288363,
  						0.3379294217282582, -0.07263752278660392,
  						-0.021060292512696543, 0.04472490177075063,
  						0.0017677118643983668, -0.007800708324765445 };
  
  				return f;
  
  			}
  			case 7: {
  				double[] f = { 0.00268181456811643, -0.0010473848889657486,
  						-0.01263630340315281, 0.0305155131659067,
  						0.06789269350159828, -0.049552834937041906,
  						0.01744125508711021, 0.5361019170907816,
  						0.7677643170045847, 0.28862963175098844,
  						-0.14004724044270553, -0.10780823770361868,
  						0.004010244871703328, 0.01026817670849701 };
  
  				return f;
  
  			}
  			case 8: {
  				double[] f = { 0.0018899503329009007, -3.0292051455166417E-4,
  						-0.014952258336793822, 0.0038087520140603582,
  						0.04913717967348071, -0.027219029916815855,
  						-0.05194583810787925, 0.36444189483598555,
  						0.77718575169981, 0.48135965125923963,
  						-0.06127335906791368, -0.1432942383510657,
  						0.0076074873252853755, 0.03169508781034778,
  						-5.4213233163559E-4, -0.0033824159513597117 };
  
  				return f;
  
  			}
  			case 9: {
  				double[] f = { 0.0010694900326524929, -4.7315449858729915E-4,
  						-0.010264064027672312, 0.00885926749350085,
  						0.062077789302687425, -0.018233770779803246,
  						-0.19155083129625178, 0.03527248803589115,
  						0.6173384491405931, 0.717897082763343,
  						0.23876091460712456, -0.054568958430509365,
  						5.834627463304675E-4, 0.03022487885795232,
  						-0.011528210207970613, -0.013271967781516928,
  						6.197808890541263E-4, 0.0014009155255699105 };
  
  				return f;
  
  			}
  			case 10: {
  				double[] f = { 7.70159808941683E-4, 9.563267076371025E-5,
  						-0.008641299274130404, -0.0014653825830396562,
  						0.045927239214146896, 0.011609893910541074,
  						-0.1594942788241296, -0.07088053579601779,
  						0.4716906667438779, 0.7695100368531889,
  						0.3838267611450017, -0.035536740298026795,
  						-0.03199005682146376, 0.049994972068686125,
  						0.005764912044344502, -0.02035493979968329,
  						-8.043589343685685E-4, 0.004593173582708373,
  						5.703608432707147E-5, -4.5932942045186415E-4 };
  
  				return f;
  			}
  			}
  		}
  
  		// Battle performs comparatively poorly using the coefficients below
  		// (sig figs?).
  		if (wavelet == Wavelet.Battle) {
  			switch (order) {
  
  			case 1: {
  				double[] f = { -0.000122686, -0.000224296, 0.000511636,
  						0.000923371, -0.002201945, -0.003883261, 0.009990599,
  						0.016974805, -0.051945337, -0.06910102, 0.39729643,
  						0.817645956, 0.39729643, -0.06910102, -0.051945337,
  						0.016974805, 0.009990599, -0.003883261, -0.002201945,
  						0.000923371, 0.000511636, -0.000224296, -0.000122686 };
  				return f;
  
  			}
  			case 3: {
  				double[] f = { 0.000146098, -0.000232304, -0.000285414,
  						0.000462093, 0.000559952, -0.000927187, -0.001103748,
  						0.00188212, 0.002186714, -0.003882426, -0.00435384,
  						0.008201477, 0.008685294, -0.017982291, -0.017176331,
  						0.042068328, 0.032080869, -0.110036987, -0.050201753,
  						0.433923147, 0.766130398, 0.433923147, -0.050201753,
  						-0.110036987, 0.032080869, 0.042068328, -0.017176331,
  						-0.017982291, 0.008685294, 0.008201477, -0.00435384,
  						-0.003882426, 0.002186714, 0.00188212, -0.001103748,
  						-0.000927187, 0.000559952, 0.000462093, -0.000285414,
  						-0.000232304, 0.000146098 };
  				return f;
  			}
  			}
  
  		}
  		double[] error = { 0 };
  		return error;
  	}
  
  	/**
  	 * 
  	 * @param wavelet To be explained
  	 * @return List of available orders for a given wavelet.
  	 */
  	public static ArrayList<Integer> validParameters(Wavelet wavelet) {
  		ArrayList<Integer> result = new ArrayList<Integer>();
  		switch (wavelet) {
  		case Haar:
  			result.add(2);
  			break;
  		case Daubechies:
  			for (int i = 4; i <= 20; i += 2) {
  				result.add(i);
  			}
  			break;
  		case Beylkin:
  			result.add(18);
  			break;
  		case Vaidyanathan:
  			result.add(24);
  			break;
  		case Coiflet:
  			for (int i = 6; i <= 30; i += 6) {
  				result.add(i);
  			}
  			break;
  		case Symmlet:
  			for (int i = 4; i <= 10; i++) {
  				result.add(i);
  			}
  			break;
  		case Battle:
  			result.add(1);
  			result.add(3);
  			break;
  		}
  		return result;
  	}
  
  	/**
  	 * 
  	 * @param parameter To be explained
  	 * @param wavelet To be explained
  	 * @param signalLength To be explained
  	 * @return A list of valid scales for a given wavelet and signal length.
  	 * @throws Exception
  	 */
  	public static ArrayList<Integer> validScales(int parameter,
  			Wavelet wavelet, int signalLength) throws Exception {
  		ArrayList<Integer> validScales = new ArrayList<Integer>();
  		int hLength = OrthogonalFilters.getLowPass(wavelet, parameter).length;
  		if (hLength > signalLength) {
  			throw new Exception("The filter is longer than the signal.");
  		}
  		int log2SigLen = (int) (Math.log(signalLength) / Math.log(2));
  		int min = (int) (Math.log(hLength) / Math.log(2));
  		for (int i = min; i <= log2SigLen; i++) {
  			double t = Math.log(hLength);
  			if (t < min) {
  				validScales.add(i);
  			}
  		}
  		return validScales;
  	}
  }
  
  // Some descriptive narrative from the Wavelab project:
  //
  // Description
  // The Haar filter (which could be considered a Daubechies-2) was the
  // first wavelet, though not called as such, and is discontinuous.
  //
  // The Beylkin filter places roots for the frequency response function
  // close to the Nyquist frequency on the real axis.
  //
  // The Coiflet filters are designed to give both the mother and father
  // wavelets 2*Par vanishing moments; here Par may be one of 1,2,3,4 or 5.
  //
  // The Daubechies filters are minimal phase filters that generate wavelets
  // which have a minimal support for a given number of vanishing moments.
  // They are indexed by their length, Par, which may be one of
  // 4,6,8,10,12,14,16,18 or 20. The number of vanishing moments is par/2.
  //
  // Symmlets are also wavelets within a minimum size support for a given
  // number of vanishing moments, but they are as symmetrical as possible,
  // as opposed to the Daubechies filters which are highly asymmetrical.
  // They are indexed by Par, which specifies the number of vanishing
  // moments and is equal to half the size of the support. It ranges
  // from 4 to 10.
  //
  // The Vaidyanathan filter gives an exact reconstruction, but does not
  // satisfy any moment condition. The filter has been optimized for
  // speech coding.
  //
  // The Battle-Lemarie filter generate spline orthogonal wavelet basis.
  // The order Par gives the degree of the spline. The number of
  // vanishing moments is Par+1.
  //
  
  //
  