001/* ***** BEGIN LICENSE BLOCK ***** 002 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 003 * 004 * The contents of this file are subject to the Mozilla Public License Version 005 * 1.1 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * http://www.mozilla.org/MPL/ 008 * 009 * Software distributed under the License is distributed on an "AS IS" basis, 010 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 011 * for the specific language governing rights and limitations under the 012 * License. 013 * 014 * The Original Code is JTransforms. 015 * 016 * The Initial Developer of the Original Code is 017 * Piotr Wendykier, Emory University. 018 * Portions created by the Initial Developer are Copyright (C) 2007-2009 019 * the Initial Developer. All Rights Reserved. 020 * 021 * Alternatively, the contents of this file may be used under the terms of 022 * either the GNU General Public License Version 2 or later (the "GPL"), or 023 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 024 * in which case the provisions of the GPL or the LGPL are applicable instead 025 * of those above. If you wish to allow use of your version of this file only 026 * under the terms of either the GPL or the LGPL, and not to allow others to 027 * use your version of this file under the terms of the MPL, indicate your 028 * decision by deleting the provisions above and replace them with the notice 029 * and other provisions required by the GPL or the LGPL. If you do not delete 030 * the provisions above, a recipient may use your version of this file under 031 * the terms of any one of the MPL, the GPL or the LGPL. 032 * 033 * ***** END LICENSE BLOCK ***** */ 034 035package edu.emory.mathcs.jtransforms.dht; 036 037import java.util.concurrent.Future; 038 039import edu.emory.mathcs.jtransforms.fft.FloatFFT_1D; 040import edu.emory.mathcs.utils.ConcurrencyUtils; 041 042/** 043 * Computes 1D Discrete Hartley Transform (DHT) of real, single precision data. 044 * The size of the data can be an arbitrary number. It uses FFT algorithm. This 045 * is a parallel implementation optimized for SMP systems. 046 * 047 * @author Piotr Wendykier (piotr.wendykier@gmail.com) 048 */ 049public class FloatDHT_1D { 050 private int n; 051 private FloatFFT_1D fft; 052 053 /** 054 * Creates new instance of FloatDHT_1D. 055 * 056 * @param n 057 * size of data 058 */ 059 public FloatDHT_1D(int n) { 060 this.n = n; 061 fft = new FloatFFT_1D(n); 062 } 063 064 /** 065 * Computes 1D real, forward DHT leaving the result in <code>a</code>. 066 * 067 * @param a 068 * data to transform 069 */ 070 public void forward(float[] a) { 071 forward(a, 0); 072 } 073 074 /** 075 * Computes 1D real, forward DHT leaving the result in <code>a</code>. 076 * 077 * @param a 078 * data to transform 079 * @param offa 080 * index of the first element in array <code>a</code> 081 */ 082 public void forward(final float[] a, final int offa) { 083 if (n == 1) 084 return; 085 fft.realForward(a, offa); 086 final float[] b = new float[n]; 087 System.arraycopy(a, offa, b, 0, n); 088 int nd2 = n / 2; 089 int nthreads = ConcurrencyUtils.getNumberOfThreads(); 090 if ((nthreads > 1) && (nd2 > ConcurrencyUtils.getThreadsBeginN_1D_FFT_2Threads())) { 091 nthreads = 2; 092 final int k1 = nd2 / nthreads; 093 Future<?>[] futures = new Future[nthreads]; 094 for (int i = 0; i < nthreads; i++) { 095 final int firstIdx = 1 + i * k1; 096 final int lastIdx = (i == (nthreads - 1)) ? nd2 : firstIdx + k1; 097 futures[i] = ConcurrencyUtils.submit(new Runnable() { 098 099 @Override 100 public void run() { 101 int idx1, idx2; 102 for (int i = firstIdx; i < lastIdx; i++) { 103 idx1 = 2 * i; 104 idx2 = idx1 + 1; 105 a[offa + i] = b[idx1] - b[idx2]; 106 a[offa + n - i] = b[idx1] + b[idx2]; 107 } 108 } 109 110 }); 111 } 112 ConcurrencyUtils.waitForCompletion(futures); 113 } else { 114 int idx1, idx2; 115 for (int i = 1; i < nd2; i++) { 116 idx1 = 2 * i; 117 idx2 = idx1 + 1; 118 a[offa + i] = b[idx1] - b[idx2]; 119 a[offa + n - i] = b[idx1] + b[idx2]; 120 } 121 } 122 if ((n % 2) == 0) { 123 a[offa + nd2] = b[1]; 124 } else { 125 a[offa + nd2] = b[n - 1] - b[1]; 126 a[offa + nd2 + 1] = b[n - 1] + b[1]; 127 } 128 129 } 130 131 /** 132 * Computes 1D real, inverse DHT leaving the result in <code>a</code>. 133 * 134 * @param a 135 * data to transform 136 * @param scale 137 * if true then scaling is performed 138 */ 139 public void inverse(float[] a, boolean scale) { 140 inverse(a, 0, scale); 141 } 142 143 /** 144 * Computes 1D real, inverse DHT leaving the result in <code>a</code>. 145 * 146 * @param a 147 * data to transform 148 * @param offa 149 * index of the first element in array <code>a</code> 150 * @param scale 151 * if true then scaling is performed 152 */ 153 public void inverse(final float[] a, final int offa, boolean scale) { 154 if (n == 1) 155 return; 156 forward(a, offa); 157 if (scale) { 158 scale(n, a, offa); 159 } 160 } 161 162 private void scale(final float m, final float[] a, int offa) { 163 final float norm = (float) (1.0 / m); 164 int nthreads = ConcurrencyUtils.getNumberOfThreads(); 165 if ((nthreads > 1) && (n >= ConcurrencyUtils.getThreadsBeginN_1D_FFT_2Threads())) { 166 nthreads = 2; 167 final int k = n / nthreads; 168 Future<?>[] futures = new Future[nthreads]; 169 for (int i = 0; i < nthreads; i++) { 170 final int firstIdx = offa + i * k; 171 final int lastIdx = (i == (nthreads - 1)) ? offa + n : firstIdx + k; 172 futures[i] = ConcurrencyUtils.submit(new Runnable() { 173 174 @Override 175 public void run() { 176 for (int i = firstIdx; i < lastIdx; i++) { 177 a[i] *= norm; 178 } 179 } 180 }); 181 } 182 ConcurrencyUtils.waitForCompletion(futures); 183 } else { 184 int lastIdx = offa + n; 185 for (int i = offa; i < lastIdx; i++) { 186 a[i] *= norm; 187 } 188 189 } 190 } 191}