8 #include "ANNLayer.hpp" 9 #include "layers/updateStateFunctions.h" 12 void ANNLayer_vertices_update_state(
32 void ANNLayer_threshminmax_update_state(
55 ANNLayer::ANNLayer() { initialize_base(); }
57 ANNLayer::ANNLayer(
const char *name, HyPerCol *hc) {
62 ANNLayer::~ANNLayer() {
68 int ANNLayer::initialize_base() {
73 int ANNLayer::initialize(
const char *name, HyPerCol *hc) {
76 if (status == PV_SUCCESS) {
80 if (status == PV_SUCCESS) {
83 if (status == PV_SUCCESS) {
92 if (parent->parameters()->arrayPresent(name,
"verticesV")) {
93 verticesListInParams =
true;
100 verticesListInParams =
false;
112 pvAssert(verticesListInParams);
113 int numVerticesTmp = numVertices;
114 this->parent->parameters()->ioParamArray(
115 ioFlag, this->getName(),
"verticesV", &verticesV, &numVerticesTmp);
116 if (ioFlag == PARAMS_IO_READ) {
117 if (numVerticesTmp == 0) {
118 if (this->parent->columnId() == 0) {
119 ErrorLog().printf(
"%s: verticesV cannot be empty\n", getDescription_c());
121 MPI_Barrier(this->parent->getCommunicator()->communicator());
124 if (numVertices != 0 && numVerticesTmp != numVertices) {
125 if (this->parent->columnId() == 0) {
127 "%s: verticesV (%d elements) and verticesA (%d elements) must have the same " 133 MPI_Barrier(this->parent->getCommunicator()->communicator());
136 assert(numVertices == 0 || numVertices == numVerticesTmp);
137 numVertices = numVerticesTmp;
142 pvAssert(verticesListInParams);
143 int numVerticesA = numVertices;
144 this->parent->parameters()->ioParamArray(
145 ioFlag, this->getName(),
"verticesA", &verticesA, &numVerticesA);
146 if (ioFlag == PARAMS_IO_READ) {
147 if (numVerticesA == 0) {
148 if (this->parent->columnId() == 0) {
149 ErrorLog().printf(
"%s: verticesA cannot be empty\n", getDescription_c());
151 MPI_Barrier(this->parent->getCommunicator()->communicator());
154 if (numVertices != 0 && numVerticesA != numVertices) {
155 if (this->parent->columnId() == 0) {
157 "%s: verticesV (%d elements) and verticesA (%d elements) must have the same " 163 MPI_Barrier(this->parent->getCommunicator()->communicator());
166 assert(numVertices == 0 || numVertices == numVerticesA);
167 numVertices = numVerticesA;
172 pvAssert(verticesListInParams);
173 parent->parameters()->ioParamValue(
174 ioFlag, name,
"slopeNegInf", &slopeNegInf, slopeNegInf ,
true );
178 pvAssert(verticesListInParams);
179 parent->parameters()->ioParamValue(
180 ioFlag, name,
"slopePosInf", &slopePosInf, slopePosInf ,
true );
184 pvAssert(!verticesListInParams);
185 parent->parameters()->ioParamValue(ioFlag, name,
"VThresh", &VThresh, VThresh);
189 pvAssert(!verticesListInParams);
190 pvAssert(!parent->parameters()->presentAndNotBeenRead(name,
"VThresh"));
191 parent->parameters()->ioParamValue(
200 pvAssert(!verticesListInParams);
201 parent->parameters()->ioParamValue(ioFlag, name,
"AMax", &AMax, AMax);
205 pvAssert(!verticesListInParams);
206 parent->parameters()->ioParamValue(ioFlag, name,
"AShift", &AShift, AShift);
210 pvAssert(!verticesListInParams);
211 parent->parameters()->ioParamValue(ioFlag, name,
"VWidth", &VWidth, VWidth);
219 if (parent->columnId() == 0) {
221 "%s: interpreting negative VWidth as setting VThresh=%f and VWidth=%f\n",
228 float limfromright = VThresh + VWidth - AShift;
229 if (AMax < limfromright)
232 if (AMin > limfromright) {
233 if (parent->columnId() == 0) {
236 "%s: nonmonotonic transfer function, jumping from %f to %f at Vthresh=%f\n",
239 (
double)limfromright,
244 "%s: nonmonotonic transfer function, changing from %f to %f as V goes from " 245 "VThresh=%f to VThresh+VWidth=%f\n",
248 (
double)limfromright,
250 (
double)(VThresh + VWidth));
256 slopeNegInf = std::numeric_limits<double>::quiet_NaN();
257 slopePosInf = std::numeric_limits<double>::quiet_NaN();
258 std::vector<float> vectorV;
259 std::vector<float> vectorA;
262 if (VThresh <= -(
float)0.999 * FLT_MAX) {
264 vectorV.push_back((
float)0);
265 vectorA.push_back(-AShift);
269 assert(VWidth >= (
float)0);
270 if (VWidth == (
float)0
271 && (
float)VThresh - AShift == AMin) {
273 vectorV.push_back(VThresh);
274 vectorA.push_back(AMin);
278 vectorV.push_back(VThresh);
279 vectorV.push_back(VThresh + VWidth);
280 vectorA.push_back(AMin);
281 vectorA.push_back(VThresh + VWidth - AShift);
285 if (AMax < (
float)0.999 * FLT_MAX) {
286 assert(slopePosInf == 1.0f);
287 if (vectorA[numVertices - 1] < AMax) {
288 float interval = AMax - vectorA[numVertices - 1];
289 vectorV.push_back(vectorV[numVertices - 1] + (
float)interval);
290 vectorA.push_back(AMax);
297 for (v = numVertices - 1; v >= 0; v--) {
298 if (vectorA[v] < AMax) {
304 assert(v + 1 < numVertices && vectorA[v] < AMax && vectorA[v + 1] >= AMax);
305 float interval = AMax - vectorA[v];
307 vectorA.resize(numVertices);
308 vectorV.resize(numVertices);
309 vectorV.push_back(vectorV[v] + (
float)interval);
310 vectorA.push_back(AMax);
321 vectorA.resize(numVertices);
322 vectorV.resize(numVertices);
323 if (slopeNegInf > 0) {
324 float intervalA = vectorA[0] - AMax;
325 float intervalV = (float)(intervalA / slopeNegInf);
326 vectorV[0] = vectorV[0] - intervalV;
334 vectorV[0] = (float)0;
344 assert(slopeNegInf == slopeNegInf && slopePosInf == slopePosInf && numVertices > 0);
345 assert(vectorA.size() == numVertices && vectorV.size() == numVertices);
346 verticesV = (
float *)malloc((
size_t)numVertices *
sizeof(*verticesV));
347 verticesA = (
float *)malloc((
size_t)numVertices *
sizeof(*verticesA));
348 if (verticesV == NULL || verticesA == NULL) {
350 "%s: unable to allocate memory for vertices:%s\n", getDescription_c(), strerror(errno));
353 memcpy(verticesV, &vectorV[0], numVertices *
sizeof(*verticesV));
354 memcpy(verticesA, &vectorA[0], numVertices *
sizeof(*verticesA));
360 pvAssert(numVertices > 0);
361 pvAssert(verticesA !=
nullptr);
362 pvAssert(verticesV !=
nullptr);
363 slopes = (
float *)pvMallocError(
364 (
size_t)(numVertices + 1) *
sizeof(*slopes),
365 "%s: unable to allocate memory for transfer function slopes: %s\n",
368 slopes[0] = slopeNegInf;
369 for (
int k = 1; k < numVertices; k++) {
370 float V1 = verticesV[k - 1];
371 float V2 = verticesV[k];
373 slopes[k] = (verticesA[k] - verticesA[k - 1]) / (V2 - V1);
376 slopes[k] = verticesA[k] > verticesA[k - 1]
377 ? std::numeric_limits<float>::infinity()
378 : verticesA[k] < verticesA[k - 1]
379 ? -std::numeric_limits<float>::infinity()
380 : std::numeric_limits<float>::quiet_NaN();
383 slopes[numVertices] = slopePosInf;
387 int status = PV_SUCCESS;
388 for (
int v = 1; v < numVertices; v++) {
389 if (verticesV[v] < verticesV[v - 1]) {
391 if (this->parent->columnId() == 0) {
393 "%s: vertices %d and %d: V-coordinates decrease from %f to %f.\n",
397 (
double)verticesV[v - 1],
398 (
double)verticesV[v]);
401 if (verticesA[v] < verticesA[v - 1]) {
402 if (this->parent->columnId() == 0) {
404 "%s: vertices %d and %d: A-coordinates decrease from %f to %f.\n",
408 (
double)verticesA[v - 1],
409 (
double)verticesA[v]);
416 int ANNLayer::resetGSynBuffers(
double timef,
double dt) {
417 return HyPerLayer::resetGSynBuffers(timef, dt);
420 Response::Status ANNLayer::updateState(
double time,
double dt) {
422 float *A = clayer->activity->data;
424 int num_channels = getNumChannels();
425 float *gSynHead = GSyn == NULL ? NULL : GSyn[0];
429 int num_neurons = nx * ny * nf;
430 int nbatch = loc->nbatch;
432 ANNLayer_vertices_update_state(
452 ANNLayer_threshminmax_update_state(
472 return Response::SUCCESS;
475 int ANNLayer::setActivity() {
480 PVHalo const *halo = &loc->halo;
481 int num_neurons = nx * ny * nf;
482 int nbatch = loc->nbatch;
484 status = setActivity_PtwiseLinearTransferLayer(
487 getCLayer()->activity->data,
510 void ANNLayer_vertices_update_state(
512 const int numNeurons,
529 updateV_ANNLayer_vertices(
549 void ANNLayer_threshminmax_update_state(
551 const int numNeurons,
569 updateV_ANNLayer_threshminmax(
virtual void ioParam_verticesV(enum ParamsIOFlag ioFlag)
verticesV: An array of membrane potentials at points where the transfer function jumps or changes slo...
virtual int ioParamsFillGroup(enum ParamsIOFlag ioFlag) override
bool layerListsVerticesInParams() const
virtual void ioParam_AShift(enum ParamsIOFlag ioFlag)
AShift: Only read if verticesV is absent. When membrane potential V is above the threshold VThresh...
virtual void ioParam_slopeNegInf(enum ParamsIOFlag ioFlag)
slopeNegInf: The slope of the transfer function when x is less than the first element of verticesV...
virtual void ioParam_verticesA(enum ParamsIOFlag ioFlag)
verticesA: An array of activities of points where the transfer function jumps or changes slope...
virtual void ioParam_AMin(enum ParamsIOFlag ioFlag)
AMin: Only read if verticesV is absent. When membrane potential V is below the threshold VThresh...
int initialize(const char *name, HyPerCol *hc)
virtual void ioParam_AMax(enum ParamsIOFlag ioFlag)
AMax: Only read if verticesV is absent. Activity that would otherwise be greater than AMax is truncat...
virtual void ioParam_slopePosInf(enum ParamsIOFlag ioFlag)
slopePosInf: The slope of the transfer function when x is greater than the last element of verticesV...
virtual void ioParam_VWidth(enum ParamsIOFlag ioFlag)
VWidth: Only read if verticesV is absent. When the membrane potential is between VThresh and VThresh+...
virtual void ioParam_VThresh(enum ParamsIOFlag ioFlag)
VThresh: Only read if verticesV is absent. The threshold value for the membrane potential. Below this value, the output activity will be AMin. Above, it will obey the transfer function as specified by AMax, VWidth, and AShift. Default is -infinity.
virtual int setVertices()
virtual int checkVertices() const
virtual int ioParamsFillGroup(enum ParamsIOFlag ioFlag) override