00001 /* 00002 * V2.H 00003 * 00004 * 00005 * Created by Randolph Voorhies on 11/26/07. 00006 * 00007 */ 00008 #ifndef V2_H 00009 #define V2_H 00010 00011 #define PI 3.14159265f 00012 00013 00014 //Parameters 00015 #define alpha_x 1.0f 00016 #define alpha_y 1.0f 00017 #define x_th 1.0f 00018 #define x_sat 2.0f 00019 #define y_th1 1.0f 00020 #define y_th2 1.2f 00021 #define g1 0.21f 00022 #define g2 2.5f 00023 #define y_sat 300.0f 00024 #define I_o 0.1f 00025 #define I_c 1.0f 00026 #define THETA_LEVELS 24 00027 00028 #include "Image/Point2D.H" 00029 #include "Image/Image.H" 00030 #include "Image/Pixels.H" 00031 #include "Raster/Raster.H" 00032 #include <vector> 00033 #include <math.h> 00034 00035 00036 using namespace std; 00037 00038 class V2 { 00039 public: 00040 V2(Dims size); 00041 00042 //Run the simulation for t steps 00043 void step(); 00044 00045 void setInput(vector< Image<float> > input); 00046 00047 00048 //Helper Functions 00049 float g_x(float x); 00050 float g_y(float y); 00051 float psi(float theta); 00052 float tau(); 00053 float I_normalization(Point2D<int> i, int theta_index); 00054 float phi(float x, float y); 00055 float beta(Point2D<int> i, Point2D<int> j); 00056 float sign(float x); 00057 float theta_one(Point2D<int> i, int i_theta_index, Point2D<int> j); 00058 float theta_two(Point2D<int> i, Point2D<int> j, int j_theta_index); 00059 float theta_one_prime(Point2D<int> i, int i_theta_index, Point2D<int> j); 00060 float theta_two_prime(Point2D<int> i, Point2D<int> j, int j_theta_index); 00061 float theta_plus(float theta_a, float theta_b); 00062 float theta_minus(float theta_a, float theta_b); 00063 void theta_a_b(float &theta_a, float &theta_b, Point2D<int> i, Point2D<int> j, int i_theta_index, int j_theta_index); 00064 float f_1(float d); 00065 float f_2(float d); 00066 float f_T(float d); 00067 float W(Point2D<int> i, int i_theta_index, Point2D<int> j, int j_theta_index); 00068 float J(Point2D<int> i, int i_theta_index, Point2D<int> j, int j_theta_index); 00069 float sumPsiGy(Point2D<int> i, int theta_index); 00070 float sumJGx(Point2D<int> i, int theta_index); 00071 float sumWGx(Point2D<int> i, int theta_index); 00072 00073 float ind2rad(int theta_index); 00074 00075 00076 private: 00077 //The Pyramidal and Inhibitory cells are layed out into the itsX and itsY matrices (respectively). The itsXprime and itsYprime matrices are used to store the next 00078 //step differences which are then added to the itsX and itsY matrices at the end of every step. 00079 vector< Image<float> > itsX; 00080 vector< Image<float> > itsY; 00081 vector< Image<float> > itsXprime; 00082 vector< Image<float> > itsYprime; 00083 00084 //The input, arranged as a matrix 00085 vector< Image<float> > I; 00086 00087 Dims itsDims; 00088 int t; 00089 }; 00090 00091 00092 V2::V2(Dims size) { 00093 itsDims = size; 00094 itsX.resize(THETA_LEVELS, Image<float>(size, ZEROS)); 00095 itsY.resize(THETA_LEVELS, Image<float>(size, ZEROS)); 00096 itsXprime.resize(THETA_LEVELS, Image<float>(size, ZEROS)); 00097 itsYprime.resize(THETA_LEVELS, Image<float>(size, ZEROS)); 00098 00099 t=0; 00100 00101 //Init the random number generator 00102 srand((unsigned) (time(0))); 00103 } 00104 00105 void V2::setInput(vector < Image<float> > input) { 00106 I = input; 00107 } 00108 00109 //This function progresses through one time step for the neural network. First, the pyramidal and inhibitory differentials are computed, 00110 //and then added to their respective activity matrices. 00111 void V2::step() { 00112 float xprime, yprime; 00113 00114 for(int theta_index=0; theta_index<THETA_LEVELS; theta_index++) { 00115 for(int i=0; i<itsDims.w();i++) { 00116 for(int j=0; j<itsDims.h(); j++) { 00117 xprime = -alpha_x*itsX[theta_index].getVal(i,j) - g_y(itsY[theta_index].getVal(i,j)) - sumPsiGy(Point2D<int>(i,j), theta_index) + sumJGx(Point2D<int>(i,j),theta_index) + /*I + */ + I_o + /*N_x*/ + I_normalization(Point2D<int>(i,j),theta_index); 00118 yprime = -alpha_y*itsY[theta_index].getVal(i,j) + g_x(itsX[theta_index].getVal(i,j)) + sumWGx(Point2D<int>(i,j), theta_index) + I_c /*+ N_y*/; 00119 00120 itsXprime[theta_index].setVal(i,j,xprime); 00121 itsYprime[theta_index].setVal(i,j,yprime); 00122 } 00123 } 00124 } 00125 00126 for(int theta_index=0; theta_index<THETA_LEVELS; theta_index++) { 00127 itsX[theta_index] += itsXprime[theta_index]; 00128 itsY[theta_index] += itsYprime[theta_index]; 00129 } 00130 00131 t++; 00132 } 00133 00134 float V2::sumPsiGy(Point2D<int> i, int theta_index) { 00135 float sum = 0; 00136 00137 for(int d_theta_index=1; d_theta_index<THETA_LEVELS; d_theta_index++) { 00138 for(int x=0; x<itsDims.w();x++) { 00139 for(int y=0; y<itsDims.h(); y++) { 00140 sum += psi(ind2rad(d_theta_index)) * g_y(itsY[((theta_index + d_theta_index)%THETA_LEVELS)].getVal(i)); 00141 } 00142 } 00143 } 00144 return sum; 00145 } 00146 00147 //NOTE: May need to provide constant Taus here? 00148 float V2::sumJGx(Point2D<int> i, int theta_index) { 00149 float sum = 0; 00150 00151 for(int x=0; x<itsDims.w(); x++) { 00152 for(int y=0; y<itsDims.h(); y++) { 00153 if(Point2D<int>(x,y) == i) continue; 00154 for(int theta_prime_index = 0; theta_prime_index < THETA_LEVELS; theta_prime_index++) { 00155 sum += J(i, theta_index, Point2D<int>(x,y), theta_prime_index) * g_x(itsX[theta_prime_index].getVal(x,y) * (t - tau())); 00156 } 00157 } 00158 } 00159 return sum; 00160 } 00161 00162 //NOTE: May need to provide constant Taus here? 00163 float V2::sumWGx(Point2D<int> i, int theta_index) { 00164 float sum = 0; 00165 for(int x=0; x<itsDims.w(); x++) { 00166 for(int y=0; y<itsDims.h(); y++) { 00167 if(i == Point2D<int>(x,y)) continue; 00168 for(int theta_prime_index = 0; theta_prime_index < THETA_LEVELS; theta_prime_index++) { 00169 sum += W(i, theta_index, Point2D<int>(x,y),theta_prime_index) * g_x(itsX[theta_prime_index].getVal(x,y)*(t-tau())); 00170 } 00171 } 00172 } 00173 return sum; 00174 } 00175 00176 00177 //Takes a theta index (an integer specifying a level of theta), and returns the actual radians which that level represents between 0 and 2PI 00178 float V2::ind2rad(int theta_index) { 00179 return (theta_index/THETA_LEVELS)*(2.0f*PI); 00180 } 00181 00182 float V2::g_x(float x) { 00183 if(x < x_th) 00184 return 0.0f; 00185 else if(x >= x_th && x <= x_sat) 00186 return x - x_th; 00187 else if(x > x_sat) 00188 return x_sat - x_th; 00189 else { 00190 LERROR("ERROR! x out of bounds"); 00191 return -1.0f; 00192 } 00193 } 00194 00195 float V2::g_y(float y) { 00196 if(y < y_th1) 00197 return 0.0f; 00198 else if(y >= y_th1 && y <= y_th2) 00199 return g1*(y - y_th1); 00200 else if(y >= y_th2 && y <= y_sat) 00201 return g2*(y - y_th2) + g1*(y_th2 - y_th1); 00202 else if(y > y_sat) 00203 return g2*(y_sat - y_th2) + g1*(y_th2 - y_th1); 00204 else { 00205 LERROR("ERROR! y out of bounds"); 00206 return -1.0f; 00207 } 00208 } 00209 00210 float V2::psi(float theta) { 00211 if(fabs(theta) == PI/12.0f) 00212 return 0.8f; 00213 if(fabs(theta) == PI/6.0f) 00214 return 0.1f; 00215 else 00216 return 0.0f; 00217 } 00218 00219 float V2::tau() { 00220 return rand()/(float(RAND_MAX)+1.0f)*(1.0f - 0.8f)+0.8f; 00221 } 00222 00223 float V2::I_normalization(Point2D<int> i, int theta_index) { 00224 00225 float a_hat = 0.0f; 00226 Point2D<int> index; 00227 00228 for(int _x = i.i-2; _x < i.i+2; _x++) { 00229 for(int _y = i.j-2; _y < i.j+2; _y++) { 00230 index = Point2D<int>(_x, _y); 00231 index.clampToDims(itsDims); 00232 a_hat += itsX[theta_index].getVal(index); 00233 } 00234 } 00235 00236 return pow(a_hat, 2.0f)/128.0f; 00237 } 00238 00239 float V2::phi(float x, float y) { 00240 float diff = x-y; 00241 00242 if(diff > -PI && diff <= PI) { 00243 return diff; 00244 } 00245 else if(diff <= -PI) { 00246 return diff + 2.0f*PI; 00247 } 00248 else if(diff > PI) { 00249 return diff - 2.0f*PI; 00250 } 00251 LERROR("Diff Out Of Bounds!"); 00252 exit(0); 00253 return 1.0f; 00254 00255 } 00256 00257 float V2::beta(Point2D<int> i, Point2D<int> j) { 00258 float beta; 00259 00260 float o = j.j - i.j; 00261 float a = j.i - i.i; 00262 00263 //float o = i.j - j.j; 00264 //float a = i.i - j.i; 00265 00266 if(a == 0.0f) { 00267 if(o > 0.0f) 00268 return PI/2.0f; 00269 else 00270 return 3.0f*PI/2.0f; 00271 } 00272 00273 beta = atan(o/a); 00274 if(o > 0.0f && a < 0.0f) { 00275 beta = PI+beta; 00276 } 00277 else if(o <= 0.0f && a < 0.0f) { 00278 beta = PI + beta; 00279 } 00280 else if(o < 0.0f && a > 0.0f) { 00281 beta = 2.0f*PI + beta; 00282 } 00283 00284 return beta; 00285 } 00286 00287 float V2::sign(float x) { 00288 if(x >= 0.0f) 00289 return 1.0f; 00290 else 00291 return -1.0f; 00292 } 00293 00294 float V2::theta_one(Point2D<int> i, int i_theta_index, Point2D<int> j) { 00295 return phi(2.0f*(PI/(float)THETA_LEVELS)*(float)i_theta_index, beta(i,j)); 00296 } 00297 00298 float V2::theta_two(Point2D<int> i, Point2D<int> j, int j_theta_index) { 00299 return phi(beta(i,j), 2.0f*(PI/(float)THETA_LEVELS)*(float)j_theta_index); 00300 } 00301 00302 float V2::theta_one_prime(Point2D<int> i, int i_theta_index, Point2D<int> j) { 00303 float _theta_one = theta_one(i,i_theta_index,j); 00304 return sign(_theta_one)*fabs(PI-fabs(_theta_one)); 00305 } 00306 00307 float V2::theta_two_prime(Point2D<int> i, Point2D<int> j, int j_theta_index) { 00308 float _theta_two = theta_two(i,j,j_theta_index); 00309 return sign(_theta_two)*fabs(PI-fabs(_theta_two)); 00310 } 00311 00312 void V2::theta_a_b(float &theta_a, float &theta_b, Point2D<int> i, Point2D<int> j, int i_theta_index, int j_theta_index) { 00313 float _theta_one = theta_one(i, i_theta_index, j); 00314 float _theta_two = theta_two(i, j, j_theta_index); 00315 float _theta_one_prime = theta_one_prime(i, i_theta_index, j); 00316 float _theta_two_prime = theta_two_prime(i, j, j_theta_index); 00317 00318 if(fabs(_theta_one) + fabs(_theta_two) <= fabs(_theta_one_prime) + fabs(_theta_two_prime)) { 00319 theta_a = _theta_one; 00320 theta_b = _theta_two; 00321 } 00322 else { 00323 theta_a = _theta_one_prime; 00324 theta_b = _theta_two_prime; 00325 } 00326 } 00327 00328 float V2::theta_plus(float theta_a, float theta_b) { 00329 float theta_prime_plus = theta_a + theta_b; 00330 00331 if(theta_prime_plus >= -PI && theta_prime_plus <= PI) 00332 return theta_prime_plus; 00333 else if(theta_prime_plus > PI) 00334 return 2.0f*PI - theta_prime_plus; 00335 else 00336 return -2.0f*PI - theta_prime_plus; 00337 } 00338 00339 float V2::theta_minus(float theta_a, float theta_b) { 00340 float theta_prime_minus = theta_a - theta_b; 00341 00342 if(theta_prime_minus >= -PI && theta_prime_minus <= PI) 00343 return theta_prime_minus; 00344 else if(theta_prime_minus > PI) 00345 return 2.0f*PI - theta_prime_minus; 00346 else 00347 return -2.0f*PI - theta_prime_minus; 00348 } 00349 00350 float V2::f_1(float d) { 00351 if(d > 10.0f || d == 0.0f) 00352 return 0.0f; 00353 00354 return exp(-pow(d/9.0f,2.0f)); 00355 } 00356 00357 float V2::f_2(float d) { 00358 if(d > 10.0f || d == 0.0f) 00359 return 0.0f; 00360 00361 return exp(-d/5.0f); 00362 } 00363 00364 float V2::f_T(float d) { 00365 return (11.0f/90.0f)*exp(-d/6.0f); 00366 } 00367 00368 //Calculate the synaptic strength between pyramidal neurons 00369 float V2::J(Point2D<int> i, int i_theta_index, Point2D<int> j, int j_theta_index) { 00370 float theta_a, theta_b; 00371 float _theta_plus, _theta_minus; 00372 float d = fabs(i.distance(j)); 00373 float ret; 00374 00375 //Calculate theta_a and theta_b 00376 theta_a_b(theta_a, theta_b, i, j, i_theta_index, j_theta_index); 00377 //Calculate theta_plus and theta_minus 00378 _theta_plus = theta_plus(theta_a, theta_b); 00379 _theta_minus = theta_minus(theta_a, theta_b); 00380 00381 //LINFO("\ntheta_a=%f\ntheta_b=%f\ni.i=%d\ni.j=%d\nj.i=%d\nj.j=%d\ntheta_plus=%f\ntheta_minus=%f\n", theta_a, theta_b, i.i, i.j, j.i,j.j,theta_plus,theta_minus); 00382 00383 if(d > 0.0f && d <= 2.0f && fabs(theta_a*d) < 0.5f && fabs(theta_b) > PI/3.1f && fabs(theta_b) < 2.0f*PI/3.1f) { 00384 00385 if(theta_b < 0.0f) 00386 return f_T(d)*exp(-2.0f*fabs(theta_a*d)); 00387 else 00388 return 0.0f; 00389 } 00390 else if(d > 0.0f && d <= 2.0f && fabs(theta_b*d) < 0.5f && fabs(theta_a) > PI/3.1f && fabs(theta_a) < 2.0f*PI/3.1f) { 00391 00392 if(theta_a < 0.0f) 00393 return 3.0f*f_T(d)*exp(-2.0f*fabs(theta_b*d)); 00394 else 00395 return 0.0f; 00396 } 00397 00398 00399 00400 if(fabs(theta_a) <= PI/11.0f && fabs(theta_b) <= PI/11.0f) { 00401 //LINFO("1"); 00402 ret = (11.0f/108.0f) * exp(-(3.0f - 2.5f*sign(_theta_plus))*fabs(_theta_plus)/(5.0f*PI) - 2.0f * pow(_theta_minus, 2.0f)/pow(PI, 2.0f))*f_1(d); 00403 } 00404 else if(theta_a >= 0.0f && theta_b >= 0.0f && _theta_plus < PI/2.01f) { 00405 //LINFO("2"); 00406 ret = (11.0f/81.0f) * exp(-3.0f*_theta_plus/(5.0f*PI) - 2.0f*pow(_theta_minus,2.0f)/pow(PI,2.0f))/f_2(d); 00407 } 00408 else if(theta_a >= 0.0f && theta_b >= 0.0f && _theta_plus >= PI/2.01f && fabs(_theta_minus) < PI/2.01f) { 00409 //LINFO("3"); 00410 ret = (11.0f/81.0f) * exp(-pow((9.0f*_theta_plus)/(8.0f*PI),2.0f) - 2.0f*pow(_theta_minus,2.0f)/pow(PI,2.0f))*f_2(d); 00411 } 00412 else if(theta_a >= 0.0f && theta_b >= 0.0f && _theta_plus >= PI/2.01f && fabs(_theta_minus) >= PI/2.01f) { 00413 //LINFO("4"); 00414 ret = (11.0f/81.0f) * exp(-pow(9.0f*_theta_plus/(8.0f*PI),2.0f) - 0.5f*pow((_theta_minus/(PI/2.0f)),6.0f))*f_2(d); 00415 } 00416 else if(theta_a <= 0.0f && theta_b <= 0.0f) { 00417 //LINFO("5"); 00418 ret = (11.0f/81.0f) * exp(-4.0f*pow(_theta_plus/PI,2.0f) - 9.0f*pow(_theta_minus, 2.0f)/pow(PI, 2.0f))*f_2(d); 00419 } 00420 else if(theta_a*theta_b <= 0.0f && fabs(_theta_minus) < PI/2.01f) { 00421 //LINFO("6\n11./81.=%f\nf_2(d)=%f",11./81., f_2(d)); 00422 ret = (11.0f/81.0f) * exp(11.5f*sign(_theta_plus)*pow(_theta_plus,2.0f)/pow(PI,2.0f) - 14.0f*pow(_theta_minus,2.0f)/pow(PI,2.0f))*f_2(d); 00423 } 00424 else if(theta_a*theta_b <= 0.0f && fabs(_theta_minus) >= PI/2.01f) { 00425 //LINFO("7"); 00426 ret = (11.0f/81.0f) * exp(11.5f*sign(_theta_plus)*pow(_theta_plus,2.0f)/pow(PI,2.0f) - (15.0f/4.0f)*pow((2.0f*_theta_minus/PI),6.0f))*f_2(d); 00427 } 00428 else { 00429 LERROR("theta_a and theta_b slipped through the cracks! \n theta_a=%f \n theta_b=%f \n theta_plus=%f \n theta_minus=%f\n", theta_a, theta_b, _theta_plus, _theta_minus); 00430 LINFO("ERROR!"); 00431 exit(0); 00432 return 1.0f; 00433 } 00434 00435 //LINFO("\ntheta_a=%f\ntheta_b=%f\nd=%f\nret=%f", theta_a, theta_b,d,ret); 00436 //Raster::waitForKey(); 00437 00438 return ret; 00439 } 00440 00441 float V2::W(Point2D<int> i, int i_theta_index, Point2D<int> j, int j_theta_index) { 00442 float theta_a, theta_b, c; 00443 float d = fabs(i.distance(j)); 00444 00445 theta_a_b(theta_a, theta_b, i, j, i_theta_index, (j_theta_index+THETA_LEVELS/2)%THETA_LEVELS); 00446 00447 if(d > 0.0f && d <= 2.0f && fabs(theta_a*d) < 0.5f && fabs(theta_b) > PI/3.1f && fabs(theta_b) < 2.0f*PI/3.1f) { 00448 if(theta_b < 0.0f) 00449 return 0.0f; 00450 //return f_T(d)*exp(-2*fabs(theta_a*d)); 00451 else 00452 return 0.0f; 00453 } 00454 else if(d > 0.0f && d <= 2.0f && fabs(theta_b*d) < 0.5f && fabs(theta_a) > PI/3.1f && fabs(theta_a) < 2.0f*PI/3.1f) { 00455 if(theta_a < 0.0f) 00456 return 0.0f; 00457 //return 3*f_T(d)*exp(-2*fabs(theta_b*d)); 00458 else 00459 return 0.0f; 00460 } 00461 00462 00463 if(fabs(theta_a) <= PI/11.0f && fabs(theta_b) <= PI/11.0f) 00464 c = 0.0147f; 00465 else 00466 c = 0.02646f; 00467 00468 return c*(J(i, (i_theta_index+THETA_LEVELS/2)%THETA_LEVELS, j, j_theta_index) + J(i, i_theta_index, j, (j_theta_index+THETA_LEVELS/2)%THETA_LEVELS)/J(i, 0, Point2D<int>(i.i+1, i.j), 0)); 00469 00470 00471 } 00472 00473 #endif