// the great ART Document Object

#import "ARTDoc.h"
#import "Controller.h"
#import "Pattern.h"
#import "ART_Animator.h"
#import "ART2_Basic.h"
#import "ART_STM.h"

#import <appkit/Application.h>
#import <appkit/Control.h>
#import <appkit/TextField.h>
#import <appkit/Window.h>
#import <appkit/Panel.h>
#import <appkit/Cursor.h>
#import <appkit/Matrix.h>
#import <appkit/Cell.h>
#import <stdlib.h>
#import <string.h>
#import <objc/NXStringTable.h>

#import <libc.h>                // For random(), etc...
#import <dpsclient/wraps.h>	// For PS and DPS function prototypes

#define frand() ((float) rand() / (RAND_MAX+1.0))
/*
int PatRow,PatCol,PatDim,PatNum;
int F2_on=ART_F2_OFF;
char buf[256];
*/
// Animator mesages macro
#define A_MSG(F_msg) [[Animator F_msg] setStringValue:buf]

// preform states
#define ART_PERFORM_NEW  0
#define ART_PERFORM_PRE  1
#define ART_PERFORM_SEARCH 2
#define ART_PERFORM_MATCH  3
#define ART_PERFORM_LEARN_EXOR 4
#define ART_PERFORM_LEARN_ONE 5
#define ART_PERFORM_LEARN_STABLE 6
int perform_flag=ART_PERFORM_NEW;

#define ART_GO 0
#define ART_STOP 1
#define STEP if (go_flag)

@implementation ARTDoc

static void newLocation(NXPoint *p)
{
    static count = 0;
    p->x += (20.0 * count);
    p->y -= (25.0 * count);
    count = (count > 10)? 0 : count+1;
}

int DimMtx(int M,int t)
{
    int i,td=t,tu=t;
    for (i=M-1;i--;) {
      if (0.0==fmod( (double)M,(double)td ))
        return td;
      if (0.0==fmod( (double)M,(double)tu ))
        return tu;
      td--;
      tu++;
      td=( td==1 ) ? 2:td;
      tu=( tu==M ) ? M-1:tu;
      }
    return 0;
}

- init
{
     return [self initFromFile:NULL];
}

- initFromFile:(const char *)file
{
     NXStream *stream;
     NXRect theFrame;
     [super init];
     [NXApp loadNibSection:"ARTDoc.nib" owner:self];
     [window setDelegate:self];
     [window getFrame:&theFrame];
     newLocation(&theFrame.origin);
     [window moveTo:theFrame.origin.x :theFrame.origin.y];

     // getting the object pointer
     //Control=[NXApp delegate];
     Animator=[[NXApp delegate] Animator_id];
     Pat=[[NXApp delegate] Pattern_id];
     stringTable=[[NXApp delegate] stringTable];

     // calc the pattern parameter
     PatDim=[Pat Dimension];
     PatNum=[Pat Quantity]-1;
     // install SearchArray
     [self setSearchArray];

    
     // install the corresponding ART Modul
     ARTModul=[ART2_Basic new];
     artp = (struct ARTModulDefs *)ARTModul;
     if (file) {
       stream=NXMapFile(file,NX_READONLY);
       if (stream) {
	 NX_DURING
           [ARTModul loadfrom:stream];
           NXCloseMemory(stream,NX_FREEBUFFER);
           //NX_VALRETURN(self);
         NX_HANDLER
	   NX_DURING
             NXCloseMemory(stream,NX_FREEBUFFER);
	   NX_HANDLER
	   // ignore any error at this point
	   NX_ENDHANDLER
	   return nil;
	 NX_ENDHANDLER
         }
       else
	 return nil;
       PatDim=artp->M;
       //[self ARTState];
       } // of if file
    else
     // default with the corresponding dimension
     [ARTModul init_M:PatDim N:(int)[Pat Quantity]];

    perform_flag=ART_PERFORM_NEW;
    go_flag=ART_STOP;
    disp_flag=ART_PAT_DISP;

    // update the animator
    PatRow=DimMtx(PatDim,(int)sqrt(PatDim));
    PatCol=(int)PatDim/PatRow;

    [self setAnimator];

    // show the Document
    //[self ARTState];
    [self getARTDefs];

    [window makeKeyAndOrderFront:nil];

    return self;
}
- free
{
     NXZoneFree([self zone],SearchArray);
     [ARTModul free];
     return [super free];
}
- setSearchArray
{
   int i,q;
   q=[Pat Quantity];
   if (SearchArray) NXZoneFree([self zone],SearchArray);
   SearchArray=NXZoneMalloc([self zone],q*sizeof(int));
   for (i=0;i<q;i++) SearchArray[i]=0;
   [queueOut setBackgroundGray:NX_LTGRAY];
   return self;
}
- (BOOL)noSearch
{
   int i,q;
   //(if (!SearchArray) return NO;
   q=[Pat Quantity];
   for (i=0;i<q && (1==SearchArray[i]);i++);
   return (i==(q)) ? YES:NO;
}
- setAnimator
{
     [Animator setDispMode:disp_flag];
     [Animator setRow:PatRow Col:PatCol];
     [Animator setDim:PatDim Mag:[Pat Maximum]*1.1 zMax:1.0/(1-artp->d)];
     [Animator setInVec:artp->zeroP];
     [Animator setPreVec:artp->zeroP];
     [Animator setTmpVec:artp->zeroP];
     [Animator showAll];
     return self;
}

- setFileName:(char *)aName
{

    if (fileName)
	free(fileName);
    fileName = (char *)malloc(strlen(aName)+1);
    strcpy(fileName,aName);
    [window setTitleAsFilename:fileName];
    return self;
}

- (char *)fileName
{
    return fileName;
}
- save:sender
{
     int fd;
     NXStream *stream;
     volatile BOOL hadAnError = NO;
     if (fileName) {
       fd = open(fileName, O_CREAT | O_WRONLY | O_TRUNC, 0666);
       stream = NXOpenFile(fd, NX_WRITEONLY);
       if (stream) {
         NX_DURING
//           NXWRITE(stream,%s,[self name]);
           [ARTModul saveinto:stream];
           NXFlush(stream);
           NXClose(stream);
           close(fd);
	 NX_HANDLER
	   hadAnError = YES;
	   NX_DURING
             NXFlush(stream);
             NXClose(stream);
             close(fd);
	   NX_HANDLER
	   /* ignore any error at this point */
	   NX_ENDHANDLER
	 NX_ENDHANDLER
         } // if stream
       else
	 hadAnError = YES;

       // message in case of an error
       if (hadAnError) {
	 NXRunAlertPanel(STRTAB("save alert title"),
			 STRTAB("save alert message"),
			 STRTAB("OK"),
			 NULL, NULL,fileName);
	 return nil;
         }
       else {
        [window setDocEdited:NO];
	return self;
        }
       } //of if filename
     return nil;
}

- creatLTMdat:sender
{
    int fd;
    NXStream *stream;
    char *p; 

    if (fileName) {
      strcpy(buf,fileName);
      if (p = rindex(buf,'.')) {
       *++p = '\0';
       strcat(buf,"LTMdat");
       }
      fd = open(buf, O_CREAT | O_WRONLY | O_TRUNC, 0666);
      stream = NXOpenFile(fd, NX_WRITEONLY);
      // write only LTM weigths in ascii file with extension LTMdat
      [[ARTModul LTM] saveinto:stream as:ART_LTM_ASCII];
      NXFlush(stream);
      NXClose(stream);
      close(fd);
      }
    return self;
}


- performNEW
{
  int i;
  // get the NeXT Pattern and show
  if ([[NXApp delegate] Rand_sel])
    PatNum=(int)(frand()*(float)[Pat Quantity]);
  else {
    PatNum++;
    PatNum=(PatNum>=[Pat Quantity]) ? 0:PatNum;
    }
  // assume that this pattern will be coded without search
  SearchArray[PatNum]=1;
  // show the pattern number and clean the textcells
  sprintf(buf,STRTAB("Input is pattern No.: %d"),PatNum);
  A_MSG(F0msg);
  sprintf(buf," ");
  A_MSG(F1msg);
  A_MSG(F2msg);

  [self updateARTDefs];
  // Initialize ART & Animator and show input pattern
  [Animator setInVec:[Pat thePattern:PatNum]];
  [Animator showInVec];
  // Set preprocessed Pattern
  [ARTModul zeroSTMs];
  [ARTModul setPattern:[Pat thePattern:PatNum]];

  // hiding the previous template
  [Animator setTmpVec:[[ARTModul F0] get_U]];
  [Animator showTmpVec];

  // Preprocessing
  i=[ARTModul preproc];
  // show Pattern and iterations
  [Animator setPreVec:[[ARTModul F0] get_P]];
  [Animator showPreVec];
  STEP {
  sprintf(buf,STRTAB("F0 stability after %d iterations"),i);
  A_MSG(F1msg);
  }
  // define the next task
  if (L2_norm([[ARTModul F0] get_P],artp->M)<0.01)
    perform_flag=ART_PERFORM_NEW;
    else
    perform_flag=ART_PERFORM_SEARCH;
  return self;
}

-performSEARCH
{
    float sigT,sigI,sigS;

    // perform the search and in the search methode the exorproc
    F2_on=[ARTModul chooseF2];
    STEP {
    if (F2_on==[[ARTModul LTM] estabNodes])
      sprintf(buf,STRTAB("new template is choosen %d "),F2_on);
    else {
      if (artp->art2_mode) {
        switch(artp->set_type) {
          case ART_MIX:
            sprintf(buf,STRTAB("( Mixset ) choosen template is  %d "),F2_on);
            break;
          case ART_SUP:
            sprintf(buf,STRTAB("( Superset ) choosen template is  %d "),F2_on);
            break;
          case ART_SUB:
            sprintf(buf,STRTAB("( Subset ) choosen template is  %d "),F2_on);
            break;
          case ART_IDE:
           sprintf(buf,STRTAB("( Identical ) choosen template is  %d "),F2_on);
            break;
          }
        // STOP

        /*
        sigS=[ARTModul significance_of:[[ARTModul F0x] get_P]];
        sigT=[ARTModul significance_of:[[ARTModul F0x] get_Q]];
        sigI=[ARTModul significance_of:[[ARTModul F0 ] get_P]];
       
        sprintf(buf,STRTAB("In %5.3f  Tmp %5.3f  Exor %5.3f "),
          sigI,sigT,sigS);
        A_MSG(F1msg);

        if (sigS==0.0) sprintf(buf,"Identical set");
        else {
          sprintf(buf,"Mixed set");
          if ( fabs(sigS+sigT-sigI) < 1.0) sprintf(buf,"Super set");
          if ( fabs(sigS+sigI-sigT) < 1.0) sprintf(buf,"Sub set");
          }

        [Animator setPreVec:[[ARTModul F0x] get_P]];
        [Animator showPreVec];

        */
        // STOP
        }
      else
         sprintf(buf,STRTAB("choosen template is  %d "),F2_on);
      }
    A_MSG(F2msg);
    } // of STEP

    perform_flag=ART_PERFORM_MATCH;
    return self;   
}

- performMATCH
{
     // iterate F1 and decide of good matching
     [ARTModul compair];
     if  ([ARTModul match])  {
       // show template is go and step by step modus
       [Animator setTmpVec:[[ARTModul LTM] TD_of:F2_on]];
       [Animator showTmpVec];
       [ARTModul markActiveNode];
       //
       // extended mode only tricky one
       // In case of extended mode, a real subset input and a stable
       // template, the template will be completely erased to increase
       // the recoding time of the subset to its superset template
      
       if (artp->art2_mode)
         if( ![ARTModul newNode] &&
             [[ARTModul LTM] is:F2_on stable:artp->exor_thresh] &&
             (artp->set_type==ART_SUB) )
           [[ARTModul LTM] zero_template:F2_on with:artp->BU_inst];
       // extended mode end
       //
       if ([ARTModul newNode]) [self setSearchArray];
       perform_flag=ART_PERFORM_LEARN_ONE;
       return self;
       }
     else {
       STEP {
       [Animator setTmpVec:[[ARTModul LTM] TD_of:F2_on]];
       [Animator showTmpVec];
       sprintf(buf,STRTAB("bad match (%4.3f < %4.3f) reset of Node %d"),
       artp->r,artp->tmprho,F2_on);
       A_MSG(F2msg);
       }
       [[ARTModul LTM] resetNode:F2_on];
       // finaly reset all nosearch labels
       [self setSearchArray];

       perform_flag=ART_PERFORM_SEARCH;
       }
     return self;
}

-performLEARN_ONE
{
     float z;
     // perform learning and set window edited
     z=[ARTModul learning];
     [Animator showTmpVec];
     [window setDocEdited:YES];
     STEP {
     sprintf(buf,STRTAB("good match (%4.3f > %4.3f) stable %4.3f"),
       artp->r,artp->tmprho,z);
     A_MSG(F2msg);
     }
     //
     // define NeXT task
     if (artp->learn_mode)
       perform_flag=ART_PERFORM_LEARN_STABLE;
     else
       // only in extended mode
       if (artp->art2_mode)
         perform_flag=ART_PERFORM_LEARN_EXOR;
       else
         perform_flag=ART_PERFORM_NEW;

     return self;
}
-performLEARN_STABLE
{
     float z;
     // perform the stable learning in the slow modus i.e.
     // after every learning the F1 is set zero and will be newly
     // iterated
     [[ARTModul F1] set_zero];
     [ARTModul compair];
     z=[ARTModul learning];
     //
     STEP {
     sprintf(buf,STRTAB("good match (%4.3f > %4.3f) stable %4.3f"),
     artp->r,artp->tmprho,z);
     A_MSG(F2msg);
     }
     [Animator showTmpVec];
     //
     // looking for stability of the weights and define NeXT task
     if( (artp->z_diff<z) && [ARTModul match] )
       perform_flag=ART_PERFORM_LEARN_STABLE;
     else
       if (artp->art2_mode)
         // only in extended mode :
         perform_flag=ART_PERFORM_LEARN_EXOR;
       else
         perform_flag=ART_PERFORM_NEW;
    return self;
}

-performLEARN_EXOR
{
     // Note that the EXOR Pattern P is the part of the input
     // that the template need additional to figure the input.
     // Hence the EXOR pattern should be presented to the system
     // virually as a new pattern. This pattern is also orthogonal
     // to its source.
     // The input Pattern should be :
     //   1. superset
     //   2. stable learned template
     //
     if ( (artp->set_type==ART_SUP)
          && [ [ARTModul LTM] is:F2_on stable:artp->exor_thresh ]
        ) {
       // in this case the Pointer to F0x is set to F1 so that
       // for further search the vector P of F0x, containing
       // the processed EXOR-pattern is going to be treated as
       // a new pattern with full ART ability.
       L2_norm_Vec([[ARTModul F0x] get_P],
                   [[ARTModul F0 ] get_P],artp->M);
       // 
       [[ARTModul LTM ] newPattern]; 
       perform_flag=ART_PERFORM_SEARCH;
       //
       // show the action and clean template textcell and graph
       STEP {
       sprintf(buf,STRTAB("Exor pattern features"));
       A_MSG(F1msg);
       sprintf(buf," ");
       A_MSG(F2msg);
       }
       // hiding the previous template
       [Animator setTmpVec:artp->zeroP];
       [Animator showTmpVec];
       // show Pattern and iterations
       [Animator setPreVec:[[ARTModul F0] get_P]];
       [Animator showPreVec];
       }
     else
       perform_flag=ART_PERFORM_NEW;
     return self;
}

- step:sender
{
  switch(perform_flag) {
    case ART_PERFORM_NEW:       
      [self performNEW];
      break;
    case ART_PERFORM_MATCH:
      [self performMATCH];
      break;
    case ART_PERFORM_SEARCH:
      if ([ARTModul resizeART]) {
        sprintf(buf,STRTAB("ART is resized to %d"),artp->N);
        [queueOut setStringValue:buf];
      }
      [self performSEARCH];
      break;
    case ART_PERFORM_LEARN_ONE:
      [self performLEARN_ONE];
      [self ARTState]; 
      break;
    case ART_PERFORM_LEARN_STABLE:
      [self performLEARN_STABLE];
      break;
    case ART_PERFORM_LEARN_EXOR:
      [self performLEARN_EXOR];
      break;
    }
  return self;
}

void PerformIt(DPSTimedEntry te, double timeNow, void *data)
{
    [(id)data animate];
}
- animate
{
    NXEvent dummyEvent;  // For peeking at the event queue. 
    do {
     [self step:nil];
    } while ([NXApp peekNextEvent:NX_ALLEVENTS
		    into:&dummyEvent 
		    waitFor:0.0
		    threshold:NX_BASETHRESHOLD] == NULL);
    return self;
}
- (BOOL)isPerforming
{
     return (ART_GO==go_flag) ? YES:NO;
}
- (BOOL)matchWithPat
{
     return ( [Pat Dimension]==artp->M ) ? YES:NO ;
}

- set_go
{
     if (go_flag==ART_STOP) {
     // Call the PerformIt() function as often as possible...
       ARTTimedEntry=DPSAddTimedEntry(0.0, &PerformIt,
                                       self,NX_BASETHRESHOLD);
       go_flag=ART_GO;
     }
     return self;
}
- set_stop
{
     if (go_flag==ART_GO) {
       DPSRemoveTimedEntry(ARTTimedEntry);
      // [self finishCycle];
       go_flag=ART_STOP;
     }
     return self;
}

- stepPattern
{
     do {
       [self step:nil];
       }
     while (perform_flag!=ART_PERFORM_NEW);
     return self;
}

- finishCycle
{
     while (perform_flag!=ART_PERFORM_NEW) {
       [self step:nil];
       }
     return self;
}

- resetLTM:sender
{
    // finish for n new pattern
    [self finishCycle];
    [ARTModul resetLTM];
    [self setSearchArray];
    return self;
}
- ARTState
{
     int i;
     char a[100];
     int *PQ=artp->PatQueue;
     [inputOut setIntValue:PatNum];  
  //   sprintf(buf,STRTAB("%d of %d"),[[ARTModul LTM] estabNodes],artp->N);
  //   [estabOut setStringValue:buf];
     [estabOut setIntValue:[[ARTModul LTM] estabNodes]];
     buf[0]='\0';
     for(i=0; PQ[i]!=ART_F2_OFF; i++) {
       sprintf(a,"%d ",PQ[i]);
       strcat(buf,a);
       }
     // for no search print out additional
     if (SearchArray[PatNum]==1) {
       sprintf(a,"no search");
       strcat(buf,a);
       }

     // for no search amoung the patternwell highlight textfield
     if ([self noSearch])
       [queueOut setBackgroundGray:NX_WHITE];
     else
       [queueOut setBackgroundGray:NX_LTGRAY];

     if (strlen(buf)) { 
       [queueOut setStringValue:buf];
       strcpy(a,buf);
       // Animator Output F0msg
       sprintf(buf,STRTAB("Input is pattern No.: %d"),PatNum);
       A_MSG(F0msg);
       // Animator Output F01msg
       sprintf(buf,"coding to : ");
       strcat(buf,a);
       A_MSG(F01msg);
       }
     return self;
}

- setRow:sender
{
    int r=[RowIn intValue];
    r=(r<1 || r>PatDim) ? PatRow:r;
    PatRow=DimMtx(PatDim,r);
    PatCol=(int)PatDim/PatRow;
    [RowIn setIntValue:PatRow];
    [ColIn setIntValue:PatCol];
    [Animator setRow:PatRow Col:PatCol ];
    [Animator showAll];
    return self;
}
- setCol:sender
{
    int c=[ColIn intValue];
    c=(c<1 || c>PatDim) ? PatCol:c;
    PatCol=DimMtx(PatDim,c);
    PatRow=(int)PatDim/PatCol;
    [RowIn setIntValue:PatRow];
    [ColIn setIntValue:PatCol];
    [Animator setRow:PatRow Col:PatCol];
    [Animator showAll];
    return self;
}
- setVecModus:sender
{
    if (disp_flag!=ART_VEC_DISP) {
      disp_flag=ART_VEC_DISP;
      [Animator setDispMode:disp_flag];
      [Animator showAll];
      }
    return self;
}
- setPatModus:sender
{
    if (disp_flag!=ART_PAT_DISP) {
      disp_flag=ART_PAT_DISP;
      [Animator setDispMode:disp_flag];
      [Animator showAll];
      }
    return self;
}

- setDelegate:anObject
{
    return self;
}
// comunication

- (int)inputPattern
{
     return PatNum;
}
- (int)codesNodes
{
     int i;
     for(i=0; artp->PatQueue[i]!=ART_F2_OFF; i++);
     return i;
}
- (int *)PatQueue
{
     return artp->PatQueue;
}
- (int)F2Nodes
{
     return [[ARTModul LTM] estabNodes];
}
- (float *)theTemplate:(int)i
{
     return [[ARTModul LTM] TD_of:i];
}

// tricky delegations
- windowDidBecomeMain:sender
{
    [window makeFirstResponder:window];
    if ([[NXApp delegate] document] != self) {
      [[NXApp delegate]  stopAll];
      if ([self matchWithPat]) {
        [[NXApp delegate]  unlookCTRL];
        if ([self isPerforming])
          [[NXApp delegate]  setGoState];
        else {
          perform_flag=ART_PERFORM_NEW;
          [[NXApp delegate]  setStopState];
          }
        }
      else {
        [[NXApp delegate]  lookCTRL];
        [[NXApp delegate]  MisMatchAlert];
        }
      [[NXApp delegate] setDocument:self];
      [self setAnimator];
      }
    return self;
}

- windowDidResignMain:sender
{
   //Animator=nil;
   //if (perform_flag!=ART_PERFORM_NEW) [self set_stop];
   // if ([[NXApp delegate] document] == self)
   //	[[NXApp delegate] setDocument:nil];
    return self;
}

- windowDidMiniaturize:sender
{
    return self;
}

- windowWillClose:sender
{
    int choice;
    if ([window isDocEdited]) {
	if (!stringTable)
	    stringTable = [[NXApp delegate] stringTable];
	choice = NXRunAlertPanel(
            STRTAB("Close"),
            STRTAB("ART Save it?"),
	    STRTAB("Yes"),
	    STRTAB("No"),
	    STRTAB("Cancel"));
	switch (choice) {
	    case NX_ALERTALTERNATE:
		break;
	    case NX_ALERTDEFAULT:
		[[NXApp delegate] save:nil];
		break;
	    case NX_ALERTOTHER:
		return nil;
	}
    }
    [self windowDidResignMain:nil];
    [window setDelegate:nil];
    [self set_stop];
    [self free];
    return sender;
}


- updateARTDefs // from the display and set the ARTModul
{
  // ARTMode
  artp->art2_mode=[[ARTModeMtx selectedCell] tag];
  // Learning
  artp->learn_mode=[[ARTLearnMtx selectedCell] tag];
  // field const
  artp->a=MAX(0.1,MIN([f_a floatValue],50.0));
  artp->b=MAX(0.1,MIN([f_b floatValue],50.0));

  // special check cause there is a dependance between d and c
  // c has changed
  if (artp->c!=[f_c floatValue]) { 
    artp->c=MAX(1E-03,MIN([f_c floatValue],(1.0-artp->d)/artp->d ));
   // artp->d=MAX(1E-03,MIN([f_d floatValue],1/(1.0+artp->c) ));
    }
  // d has changed
  if (artp->d!=[f_d floatValue]) {
    artp->d=MAX(1E-03,MIN([f_d floatValue],1/(1.0+artp->c) ));
   // artp->c=MAX(1E-03,MIN([f_c floatValue],(1.0-artp->d)/artp->d ));
    }

  // vigilance
  //if ([f_rho floatValue] > 1.0) artp->rho=1.0;
  //if ([f_rho floatValue] < 0.0) artp->rho=0.0;

  artp->rho=MAX(0.0,MIN([f_rho floatValue],0.9999999999999));
  artp->rhoset=MAX(0.0,MIN([f_rhoset floatValue],1.0));

  // thresh
  artp->theta=MAX(0.0,MIN([f_theta floatValue],1.0));

  // integration
  artp->z_diff=MAX(1E-10,MIN([f_z_diff floatValue],1.0));
  artp->h=MAX(1E-5,MIN([f_h floatValue],10.0));

  // activity
  artp->ac_diff=MAX(1E-10,MIN([f_ac_diff floatValue],1.0));
  // i_min has changed
  if (artp->i_min!=[f_min intValue])
    artp->i_min=MAX(1,MIN([f_min intValue],artp->i_max));
  // i_max has changed
  if (artp->i_max!=[f_max intValue])
    artp->i_min=MAX(artp->i_min+1,MIN([f_max intValue],1000));

  // BU
  artp->BU_inst=MAX(1E-10,MIN([f_BU_inst floatValue],1.0));

  // and finaly
  [ARTModul update_syspara];
  return self;
}

- getARTDefs // from the ARTModul and show
{
  // ARTMode
  [ARTModeMtx selectCellWithTag:(artp->art2_mode)];
  // Learning
  [ARTLearnMtx selectCellWithTag:(artp->learn_mode)];
  // field const
  [f_a setFloatValue:artp->a];
  [f_b setFloatValue:artp->b];
  [f_c setFloatValue:artp->c];
  [f_d setFloatValue:artp->d];

  // vigilance
  [f_rho setFloatValue:artp->rho];
  [f_rhoset setFloatValue:artp->rhoset];

  // thresh
  [f_theta setFloatValue:artp->theta];

  // integration
  [f_z_diff setFloatValue:artp->z_diff];
  [f_h setFloatValue:artp->h];

  // activity
  [f_ac_diff setFloatValue:artp->ac_diff];
  [f_min setIntValue:artp->i_min];
  [f_max setIntValue:artp->i_max];

  // BU
  [f_BU_inst setFloatValue:artp->BU_inst];

  // pattern parameter
  [DimOut setIntValue:PatDim];
  [RowIn setIntValue:PatRow];
  [ColIn setIntValue:PatCol];

  return self;
}
@end
