Unified · Split
| @@ -0,0 +1,40 @@ | |||
| 1 | TARGETS = fir_interp | ||
| 2 | |||
| 3 | CXX = g++ | ||
| 4 | CXXFLAGS = -g -O3 -Wall -W -Werror -Wstrict-prototypes -Wmissing-prototypes | ||
| 5 | |||
| 6 | GMATH_INC = $(shell pkg-config --cflags GMath) | ||
| 7 | GMATH_LIB = $(shell pkg-config --libs GMath) | ||
| 8 | |||
| 9 | FFTW_INC = $(shell pkg-config --cflags fftw3) | ||
| 10 | FFTW_LIB = $(shell pkg-config --libs fftw3) | ||
| 11 | |||
| 12 | |||
| 13 | |||
| 14 | all: $(TARGETS) | ||
| 15 | |||
| 16 | clean: | ||
| 17 | rm -f $(TARGETS) *.o | ||
| 18 | |||
| 19 | check: $(TARGETS) | ||
| 20 | ./fir_interp | ||
| 21 | |||
| 22 | fir_interp: fir_interp.o mag_spectrum.o demin.o | ||
| 23 | $(CXX) $(CXXFLAGS) $+ $(GMATH_LIB) $(FFTW_LIB) -o $@ | ||
| 24 | |||
| 25 | #--------------------------------------------------------------------- | ||
| 26 | |||
| 27 | fir_interp.o : fir_interp.cc mag_spectrum.hh | ||
| 28 | $(CXX) $(CXXFLAGS) $(GMATH_INC) -c fir_interp.cc -o $@ | ||
| 29 | |||
| 30 | mag_spectrum.o : mag_spectrum.cc mag_spectrum.hh | ||
| 31 | $(CXX) $(CXXFLAGS) $(FFTW_INC) -c mag_spectrum.cc -o $@ | ||
| 32 | |||
| 33 | demin.o : demin.cc | ||
| 34 | $(CXX) $(CXXFLAGS) $(GMATH_INC) -c $+ -o $@ | ||
| 35 | |||
| 36 | # Do not edit or modify anything in this comment block. | ||
| 37 | # The arch-tag line is a file identity tag for the GNU Arch | ||
| 38 | # revision control system. | ||
| 39 | # | ||
| 40 | # arch-tag: 34b6b183-dca1-4085-9089-c8b7d5b09099 | ||
| @@ -0,0 +1,268 @@ | |||
| 1 | /* | ||
| 2 | ** Copyright (C) 1998-2004 Erik de Castro Lopo <erikd@mega-nerd.com> | ||
| 3 | ** | ||
| 4 | ** The copyright above and this notice must be preserved in all | ||
| 5 | ** copies of this source code. The copyright above does not | ||
| 6 | ** evidence any actual or intended publication of this source code. | ||
| 7 | ** | ||
| 8 | ** This is unpublished proprietary trade secret of Erik de Castro | ||
| 9 | ** Lopo. This source code may not be copied, disclosed, | ||
| 10 | ** distributed, demonstrated or licensed except as authorized by | ||
| 11 | ** Erik de Castro Lopo. | ||
| 12 | ** | ||
| 13 | ** No part of this program or publication may be reproduced, | ||
| 14 | ** transmitted, transcribed, stored in a retrieval system, | ||
| 15 | ** or translated into any language or computer language in any | ||
| 16 | ** form or by any means, electronic, mechanical, magnetic, | ||
| 17 | ** optical, chemical, manual, or otherwise, without the prior | ||
| 18 | ** written permission of Erik de Castro Lopo. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <stdio.h> | ||
| 22 | #include <unistd.h> | ||
| 23 | |||
| 24 | #include <Minimize.hh> | ||
| 25 | #include <PsuedoRand.hh> | ||
| 26 | |||
| 27 | class DEmin | ||
| 28 | { private : | ||
| 29 | u_int PopSize, FuncCalcs, Generations ; | ||
| 30 | |||
| 31 | PsuedoRand Rand ; | ||
| 32 | |||
| 33 | GMatrix *MainVector, *Vector2 ; | ||
| 34 | double *MainCost, *Cost2 ; | ||
| 35 | double *ScaleFactor, *ScaleFactor2 ; | ||
| 36 | double *Crossover, *Crossover2 ; | ||
| 37 | |||
| 38 | MinFunc Function ; | ||
| 39 | |||
| 40 | public : | ||
| 41 | DEmin (void) ; | ||
| 42 | ~DEmin (void) ; | ||
| 43 | |||
| 44 | void Setup (MinFunc func, const GMatrix& start, u_int popsize, double range, u_long seed) ; | ||
| 45 | |||
| 46 | GMatrix Minimize (double tol, u_int maxgen) ; | ||
| 47 | |||
| 48 | void PrintStats (void) ; | ||
| 49 | |||
| 50 | } ; // class DEmin | ||
| 51 | |||
| 52 | //====================================================================================== | ||
| 53 | |||
| 54 | inline | ||
| 55 | void Swap (GMatrix **a, GMatrix **b) | ||
| 56 | { GMatrix *temp ; | ||
| 57 | temp = *a ; *a = *b ; *b = temp ; | ||
| 58 | } ; // | ||
| 59 | |||
| 60 | inline void | ||
| 61 | Swap (double **a, double **b) | ||
| 62 | { double *temp ; | ||
| 63 | temp = *a ; *a = *b ; *b = temp ; | ||
| 64 | } ; // Swap | ||
| 65 | |||
| 66 | inline double | ||
| 67 | Max (double a, double b) | ||
| 68 | { return (a > b) ? a : b ; | ||
| 69 | } ; // Max | ||
| 70 | |||
| 71 | inline double | ||
| 72 | Min (double a, double b) | ||
| 73 | { return (a < b) ? a : b ; | ||
| 74 | } ; // Max | ||
| 75 | |||
| 76 | //====================================================================================== | ||
| 77 | |||
| 78 | double | ||
| 79 | MinDiffEvol (MinFunc Function, GMatrix& start, double Ftol, double range, u_long seedval) | ||
| 80 | { DEmin *pfmin ; | ||
| 81 | u_int dimensions ; | ||
| 82 | |||
| 83 | dimensions = start.GetElements () ; | ||
| 84 | |||
| 85 | pfmin = new DEmin ; | ||
| 86 | |||
| 87 | pfmin -> Setup (Function, start, dimensions * 5, range, seedval) ; | ||
| 88 | |||
| 89 | Ftol = (Ftol < 1e-8) ? 1e-8 : Ftol ; | ||
| 90 | |||
| 91 | start = pfmin -> Minimize (Ftol, dimensions * 5000) ; | ||
| 92 | |||
| 93 | delete pfmin ; | ||
| 94 | |||
| 95 | return Function (start) ; | ||
| 96 | } ; // MinDiffEvol | ||
| 97 | |||
| 98 | |||
| 99 | //====================================================================================== | ||
| 100 | |||
| 101 | DEmin::DEmin (void) | ||
| 102 | { PopSize = 0 ; | ||
| 103 | FuncCalcs = 0 ; | ||
| 104 | Generations = 0 ; | ||
| 105 | MainVector = NULL ; | ||
| 106 | MainCost = NULL ; | ||
| 107 | ScaleFactor = NULL ; | ||
| 108 | Crossover = NULL ; | ||
| 109 | Vector2 = NULL ; | ||
| 110 | Cost2 = NULL ; | ||
| 111 | ScaleFactor2 = NULL ; | ||
| 112 | Crossover2 = NULL ; | ||
| 113 | } ; // DEmin constructor | ||
| 114 | |||
| 115 | DEmin::~DEmin (void) | ||
| 116 | { if (PopSize) | ||
| 117 | { delete [] MainVector ; | ||
| 118 | delete MainCost ; | ||
| 119 | delete ScaleFactor ; | ||
| 120 | delete Crossover ; | ||
| 121 | delete [] Vector2 ; | ||
| 122 | delete Cost2 ; | ||
| 123 | delete ScaleFactor2 ; | ||
| 124 | delete Crossover2 ; | ||
| 125 | } ; | ||
| 126 | PopSize = 0 ; | ||
| 127 | } ; // DEmin destructor | ||
| 128 | |||
| 129 | void | ||
| 130 | DEmin::Setup (MinFunc func, const GMatrix& start, u_int popsize, double range, u_long seed) | ||
| 131 | { u_int k ; | ||
| 132 | u_short rows, cols ; | ||
| 133 | |||
| 134 | Generations = 0 ; | ||
| 135 | Function = func ; | ||
| 136 | |||
| 137 | PopSize = (popsize < 2) ? popsize + 2 : popsize ; | ||
| 138 | |||
| 139 | MainVector = new GMatrix [PopSize] ; | ||
| 140 | MainCost = new double [PopSize] ; | ||
| 141 | ScaleFactor = new double [PopSize] ; | ||
| 142 | Crossover = new double [PopSize] ; | ||
| 143 | Vector2 = new GMatrix [PopSize] ; | ||
| 144 | Cost2 = new double [PopSize] ; | ||
| 145 | ScaleFactor2 = new double [PopSize] ; | ||
| 146 | Crossover2 = new double [PopSize] ; | ||
| 147 | |||
| 148 | Rand.Seed (seed + 1234567) ; | ||
| 149 | |||
| 150 | rows = start.GetRows () ; | ||
| 151 | cols = start.GetCols () ; | ||
| 152 | |||
| 153 | GMatrix::PsuedoRandSeed (123123) ; | ||
| 154 | |||
| 155 | if (IsComplex (start)) | ||
| 156 | for (k = 0 ; k < PopSize ; k++) | ||
| 157 | { MainVector [k].SetSizeComplex (rows, cols) ; | ||
| 158 | MainVector [k].PsuedoRandomize () ; | ||
| 159 | MainVector [k] = (2.0 * range) * (MainVector [k] - Complex (0.5, 0.5)) ; | ||
| 160 | } | ||
| 161 | else | ||
| 162 | for (k = 0 ; k < PopSize ; k++) | ||
| 163 | { MainVector [k].SetSizeDouble (rows, cols) ; | ||
| 164 | MainVector [k].PsuedoRandomize () ; | ||
| 165 | MainVector [k] = (2.0 * range) * (MainVector [k] - 0.5) ; | ||
| 166 | } ; | ||
| 167 | |||
| 168 | MainVector [0] = start ; // Must include given vector. | ||
| 169 | |||
| 170 | for (k = 0 ; k < PopSize ; k++) | ||
| 171 | { MainCost [k] = Function (MainVector [k]) ; | ||
| 172 | FuncCalcs ++ ; | ||
| 173 | ScaleFactor [k] = 1.2 * Rand.UDDouble () ; | ||
| 174 | Crossover [k] = Rand.UDDouble () ; | ||
| 175 | } ; | ||
| 176 | |||
| 177 | return ; | ||
| 178 | } ; // DEmin::Setup | ||
| 179 | |||
| 180 | GMatrix | ||
| 181 | DEmin::Minimize (double Ftol, u_int maxgen) | ||
| 182 | { u_int k, a, b, c ; | ||
| 183 | GMatrix temp ; | ||
| 184 | double scalefactor, crossover, cost, improvement, best ; | ||
| 185 | |||
| 186 | improvement = 100 * Ftol ; | ||
| 187 | best = 10e10 ; | ||
| 188 | |||
| 189 | while (Generations < maxgen && best > Ftol) | ||
| 190 | { Swap (&MainVector, &Vector2) ; | ||
| 191 | Swap (&MainCost, &Cost2) ; | ||
| 192 | Swap (&ScaleFactor, &ScaleFactor2) ; | ||
| 193 | Swap (&Crossover, &Crossover2) ; | ||
| 194 | |||
| 195 | improvement = 0.0 ; | ||
| 196 | |||
| 197 | for (k = 0 ; k < PopSize ; k++) | ||
| 198 | { do | ||
| 199 | a = u_int (double (PopSize) * Rand.UDDouble ()) ; | ||
| 200 | while (a == k) ; | ||
| 201 | do | ||
| 202 | b = u_int (double (PopSize) * Rand.UDDouble ()) ; | ||
| 203 | while (b == k || b == a) ; | ||
| 204 | do | ||
| 205 | c = u_int (double (PopSize) * Rand.UDDouble ()) ; | ||
| 206 | while (c == k || c == a || c == b) ; | ||
| 207 | |||
| 208 | if (a >= PopSize) { printf ("a - very bad.\n") ; exit (0) ; } ; | ||
| 209 | if (b >= PopSize) { printf ("b - very bad.\n") ; exit (0) ; } ; | ||
| 210 | if (c >= PopSize) { printf ("c - very bad.\n") ; exit (0) ; } ; | ||
| 211 | |||
| 212 | scalefactor = 0.5 * (ScaleFactor2 [b] + ScaleFactor2 [c]) ; | ||
| 213 | |||
| 214 | temp = Vector2 [a] + scalefactor * (Vector2 [b] - Vector2 [c]) ; | ||
| 215 | |||
| 216 | crossover = 0.5 * (Crossover2 [k] + Crossover2 [a]) ; | ||
| 217 | |||
| 218 | temp.CrossOver (Vector2 [k], crossover) ; | ||
| 219 | |||
| 220 | cost = Function (temp) ; | ||
| 221 | FuncCalcs ++ ; | ||
| 222 | |||
| 223 | if (cost < Cost2 [k]) | ||
| 224 | { MainVector [k] = temp ; | ||
| 225 | MainCost [k] = cost ; | ||
| 226 | ScaleFactor [k] = scalefactor ; | ||
| 227 | Crossover [k] = crossover ; | ||
| 228 | improvement = 0.5 * (improvement + Max (improvement, Cost2 [k] - cost)) ; | ||
| 229 | best = Min (best, cost) ; | ||
| 230 | } | ||
| 231 | else | ||
| 232 | { MainVector [k] = Vector2 [k] ; | ||
| 233 | MainCost [k] = Cost2 [k] ; | ||
| 234 | ScaleFactor [k] = ScaleFactor2 [k] ; | ||
| 235 | Crossover [k] = Crossover2 [k] ; | ||
| 236 | } ; // if | ||
| 237 | } ; // for k | ||
| 238 | |||
| 239 | Generations ++ ; | ||
| 240 | } ; // while | ||
| 241 | |||
| 242 | // Now find best vector. | ||
| 243 | |||
| 244 | for (a = 0, k = 1 ; k < PopSize ; k++) | ||
| 245 | if (MainCost [k] < MainCost [a]) | ||
| 246 | a = k ; | ||
| 247 | temp = MainVector [a] ; | ||
| 248 | |||
| 249 | return temp ; | ||
| 250 | } ; // DEmin::Minimize | ||
| 251 | |||
| 252 | void | ||
| 253 | DEmin::PrintStats (void) | ||
| 254 | { printf ("Generations : %8d\n", Generations) ; | ||
| 255 | printf ("Function evaluations : %8d\n", FuncCalcs) ; | ||
| 256 | putchar ('\n') ; | ||
| 257 | } ; // DEmin::PrintStats | ||
| 258 | |||
| 259 | //====================================================================================== | ||
| 260 | |||
| 261 | |||
| 262 | |||
| 263 | // Do not edit or modify anything in this comment block. | ||
| 264 | // The arch-tag line is a file identity tag for the GNU Arch | ||
| 265 | // revision control system. | ||
| 266 | // | ||
| 267 | // arch-tag: e874ad11-7294-4757-9370-fd1e6e1261d0 | ||
| 268 | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | /* | ||
| 2 | ** Copyright (C) 2004 Erik de Castro Lopo <erikd@mega-nerd.com> | ||
| 3 | ** | ||
| 4 | ** The copyright above and this notice must be preserved in all | ||
| 5 | ** copies of this source code. The copyright above does not | ||
| 6 | ** evidence any actual or intended publication of this source code. | ||
| 7 | ** | ||
| 8 | ** This is unpublished proprietary trade secret of Erik de Castro | ||
| 9 | ** Lopo. This source code may not be copied, disclosed, | ||
| 10 | ** distributed, demonstrated or licensed except as authorized by | ||
| 11 | ** Erik de Castro Lopo. | ||
| 12 | ** | ||
| 13 | ** No part of this program or publication may be reproduced, | ||
| 14 | ** transmitted, transcribed, stored in a retrieval system, | ||
| 15 | ** or translated into any language or computer language in any | ||
| 16 | ** form or by any means, electronic, mechanical, magnetic, | ||
| 17 | ** optical, chemical, manual, or otherwise, without the prior | ||
| 18 | ** written permission of Erik de Castro Lopo. | ||
| 19 | */ | ||
| 20 | |||
| 21 | |||
| 22 | #include <cstdio> | ||
| 23 | #include <cstdlib> | ||
| 24 | #include <ctime> | ||
| 25 | #include <cstring> | ||
| 26 | #include <complex> | ||
| 27 | |||
| 28 | #include <GMatrix.hh> | ||
| 29 | #include <Minimize.hh> | ||
| 30 | |||
| 31 | #include "mag_spectrum.hh" | ||
| 32 | |||
| 33 | |||
| 34 | #define ARRAY_LEN(x) (sizeof (x) / sizeof ((x) [0])) | ||
| 35 | |||
| 36 | /* | ||
| 37 | ** Number of half cycles of impulse response to the left and right | ||
| 38 | ** of the center. | ||
| 39 | ** left_half_offset <= right_half_cycles | ||
| 40 | */ | ||
| 41 | |||
| 42 | // static int left_half_cycles = 5 ; | ||
| 43 | // static int right_half_cycles = 15 ; | ||
| 44 | |||
| 45 | |||
| 46 | typedef struct | ||
| 47 | { | ||
| 48 | double sinc_time_fudge ; | ||
| 49 | |||
| 50 | /* Window coefficients (all in range [0, 1]). */ | ||
| 51 | double left_ak [5], right_ak [5] ; | ||
| 52 | |||
| 53 | } FIR_PARAMS ; | ||
| 54 | |||
| 55 | static double fir_error (const GMatrix& gm) ; | ||
| 56 | |||
| 57 | int | ||
| 58 | main (void) | ||
| 59 | { static double data [32] ; | ||
| 60 | GMatrix gm_start ; | ||
| 61 | double error ; | ||
| 62 | int k, param_count ; | ||
| 63 | |||
| 64 | param_count = sizeof (FIR_PARAMS) / sizeof (double) ; | ||
| 65 | |||
| 66 | srandom (time (NULL)) ; | ||
| 67 | for (k = 0 ; k < param_count ; k++) | ||
| 68 | data [k] = 3.0 * ((1.0 * random ()) / INT_MAX - 0.5) ; | ||
| 69 | |||
| 70 | gm_start = GMatrix (param_count, 1, data) ; | ||
| 71 | |||
| 72 | fir_error (gm_start) ; | ||
| 73 | |||
| 74 | do | ||
| 75 | error = MinDiffEvol (fir_error, gm_start, 1e-15, 2.0, random ()) ; | ||
| 76 | while (error > 10.0) ; | ||
| 77 | |||
| 78 | printf ("error : %f\n", error) ; | ||
| 79 | |||
| 80 | return 0 ; | ||
| 81 | } /* main */ | ||
| 82 | |||
| 83 | /*============================================================================== | ||
| 84 | */ | ||
| 85 | |||
| 86 | static double | ||
| 87 | fir_error (const GMatrix& gm) | ||
| 88 | { FIR_PARAMS params ; | ||
| 89 | double error = 0.0 ; | ||
| 90 | unsigned param_count ; | ||
| 91 | |||
| 92 | |||
| 93 | param_count = sizeof (params) / sizeof (double) ; | ||
| 94 | |||
| 95 | if (gm.GetData (param_count, (double*) ¶ms) != param_count) | ||
| 96 | { printf ("\n\nError : GetData should return 2.\n") ; | ||
| 97 | exit (1) ; | ||
| 98 | } ; | ||
| 99 | |||
| 100 | return error ; | ||
| 101 | } /* fir_error */ | ||
| 102 | |||
| 103 | /* | ||
| 104 | ** Do not edit or modify anything in this comment block. | ||
| 105 | ** The following line is a file identity tag for the GNU Arch | ||
| 106 | ** revision control system. | ||
| 107 | ** | ||
| 108 | ** arch-tag: 3ce7ca6f-394e-432c-aeaa-f228afc05afd | ||
| 109 | */ | ||
| @@ -0,0 +1,62 @@ | |||
| 1 | /* | ||
| 2 | ** Copyright (C) 2004 Erik de Castro Lopo <erikd@mega-nerd.com> | ||
| 3 | ** | ||
| 4 | ** The copyright above and this notice must be preserved in all | ||
| 5 | ** copies of this source code. The copyright above does not | ||
| 6 | ** evidence any actual or intended publication of this source code. | ||
| 7 | ** | ||
| 8 | ** This is unpublished proprietary trade secret of Erik de Castro | ||
| 9 | ** Lopo. This source code may not be copied, disclosed, | ||
| 10 | ** distributed, demonstrated or licensed except as authorized by | ||
| 11 | ** Erik de Castro Lopo. | ||
| 12 | ** | ||
| 13 | ** No part of this program or publication may be reproduced, | ||
| 14 | ** transmitted, transcribed, stored in a retrieval system, | ||
| 15 | ** or translated into any language or computer language in any | ||
| 16 | ** form or by any means, electronic, mechanical, magnetic, | ||
| 17 | ** optical, chemical, manual, or otherwise, without the prior | ||
| 18 | ** written permission of Erik de Castro Lopo. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <cstdio> | ||
| 22 | #include <cstdlib> | ||
| 23 | #include <cstring> | ||
| 24 | #include <cmath> | ||
| 25 | |||
| 26 | #include <fftw3.h> | ||
| 27 | |||
| 28 | void | ||
| 29 | mag_spectrum (double *input, int len, double *magnitude, double scale) | ||
| 30 | { static fftw_plan plan = NULL ; | ||
| 31 | |||
| 32 | double maxval ; | ||
| 33 | int k ; | ||
| 34 | |||
| 35 | if (input == NULL || magnitude == NULL) | ||
| 36 | return ; | ||
| 37 | |||
| 38 | if (plan == NULL) | ||
| 39 | { plan = fftw_plan_r2r_1d (len, input, magnitude, FFTW_R2HC, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT) ; | ||
| 40 | if (plan == NULL) | ||
| 41 | { printf ("%s : line %d : create plan failed.\n", __FILE__, __LINE__) ; | ||
| 42 | exit (1) ; | ||
| 43 | } ; | ||
| 44 | } ; | ||
| 45 | |||
| 46 | fftw_execute (plan) ; | ||
| 47 | |||
| 48 | /* (k < N/2 rounded up) */ | ||
| 49 | maxval = 0.0 ; | ||
| 50 | for (k = 0 ; k < len / 2 ; k++) | ||
| 51 | magnitude [k] = scale * sqrt (magnitude [k] * magnitude [k] + magnitude [len - k - 1] * magnitude [len - k - 1]) ; | ||
| 52 | |||
| 53 | memset (magnitude + len / 2, 0, len / 2 * sizeof (magnitude [0])) ; | ||
| 54 | |||
| 55 | return ; | ||
| 56 | } /* mag_spectrum */ | ||
| 57 | |||
| 58 | // Do not edit or modify anything in this comment block. | ||
| 59 | // The following line is a file identity tag for the GNU Arch | ||
| 60 | // revision control system. | ||
| 61 | // | ||
| 62 | // arch-tag: 58aa43ee-b8e1-4178-8861-7621399fa049 | ||
| @@ -0,0 +1,27 @@ | |||
| 1 | /* | ||
| 2 | ** Copyright (C) 2004 Erik de Castro Lopo <erikd@mega-nerd.com> | ||
| 3 | ** | ||
| 4 | ** The copyright above and this notice must be preserved in all | ||
| 5 | ** copies of this source code. The copyright above does not | ||
| 6 | ** evidence any actual or intended publication of this source code. | ||
| 7 | ** | ||
| 8 | ** This is unpublished proprietary trade secret of Erik de Castro | ||
| 9 | ** Lopo. This source code may not be copied, disclosed, | ||
| 10 | ** distributed, demonstrated or licensed except as authorized by | ||
| 11 | ** Erik de Castro Lopo. | ||
| 12 | ** | ||
| 13 | ** No part of this program or publication may be reproduced, | ||
| 14 | ** transmitted, transcribed, stored in a retrieval system, | ||
| 15 | ** or translated into any language or computer language in any | ||
| 16 | ** form or by any means, electronic, mechanical, magnetic, | ||
| 17 | ** optical, chemical, manual, or otherwise, without the prior | ||
| 18 | ** written permission of Erik de Castro Lopo. | ||
| 19 | */ | ||
| 20 | |||
| 21 | void mag_spectrum (double *input, int len, double *magnitude, double scale) ; | ||
| 22 | |||
| 23 | // Do not edit or modify anything in this comment block. | ||
| 24 | // The following line is a file identity tag for the GNU Arch | ||
| 25 | // revision control system. | ||
| 26 | // | ||
| 27 | // arch-tag: cc5db1c8-4c67-49f7-9c2f-6c5021a69970 | ||