# Build a neural net using Joone 
# This program reads data, train and then test NN using
# last raws of data (not used for the trainning)
# 
# You have to read API of JooneTools
# This example is a rewrite of the JAVA example
# which is located in samples/engine/helpers
# of the Joone package: http://www.jooneworld.com/
# Note: only joone-engine.jar  is used.
# S.Chekanov. JHepwWork
#
from  java.io import *
from  org.joone.engine import *
from  org.joone.helpers.factory import JooneTools
from  org.joone.io import *;
from  org.joone.net import *
from  org.joone.util import NormalizerPlugIn


# path to the files of this example
filePath =SystemDir+fSep+"macros"+fSep+"examples"+fSep+"neural_net"+fSep;

# input data for training and testing 
fileName=filePath+"wine_train.txt"

# log file from the training
logName=filePath+"wine_train.log"

# output file with saved trained NN
nnOutput=filePath+"nn_wine.snet"


# number of raws to train the NN
# the rest is used for validation
trainingRows = 150


fileIn = FileInputSynapse();
fileIn.setInputFile(File(fileName));
fileIn.setAdvancedColumnSelector("1-14")



# Input data normalized between -1 and 1
normIn = NormalizerPlugIn()
normIn.setAdvancedSerieSelector("2-14")
normIn.setMin(-1)
normIn.setMax(1)
fileIn.addPlugIn(normIn)

# Target data normalized between 0 and 1
normOut = NormalizerPlugIn();
normOut.setAdvancedSerieSelector("1")
fileIn.addPlugIn(normOut)

"""
 Extracts a subset of data from the StreamInputSynapse passed as parameter.
 @return A 2D array of double containing the extracted data
 @param dataSet The input StreamInputSynapse. Must be buffered.
 @param firstRow The first row (relative to the internal buffer) to extract
 @param lastRow The last row (relative to the internal buffer) to extract
 @param firstCol The first column (relative to the internal buffer) to extract
 @param lastCol The last column (relative to the internal buffer) to extract
"""

# Extract the training data
inputTrain = JooneTools.getDataFromStream(fileIn,1,trainingRows,2,14)
desiredTrain = JooneTools.getDataFromStream(fileIn,1,trainingRows,1,1)


# Extract the test data for validation 
inputTest = JooneTools.getDataFromStream(fileIn,trainingRows+1,178,2,14)
desiredTest = JooneTools.getDataFromStream(fileIn,trainingRows+1,178,1,1)


"""
 * Creates a feed forward neural network without I/O components.
 * @param nodes array of integers containing the nodes of each layer
 * @param outputType the type of output layer. One of 'LINEAR', 'SOFTMAX', 'LOGISTIC'
 * @return The neural network created
 @throws java.lang.IllegalArgumentException .
"""

# 13 input nodes, 4 hiden, 1 output
nodes = [13, 4, 1]
nnet = JooneTools.create_standard(nodes,JooneTools.LOGISTIC)
# Set optimal values for learning rate and momentum
nnet.getMonitor().setLearningRate(0.3)
nnet.getMonitor().setMomentum(0.5)


# output stream to the log file
sout=PrintStream( FileOutputStream(logName) )

"""
* Trains a neural network using the input/desired pairs contained in 2D arrays of double.
* If Monitor.trainingPatterns = 0, all the input array's rows will be used for training.
* @param nnet The neural network to train
* @param input 2D array of double containing the training data. The # of columns must be equal to the # of input nodes
* @param desired 2D array of double containing the target data. The # of columns must be equal to the # of output nodes
* @param epochs Number of max training epochs
* @param stopRMSE The desired min error at which the training must stop. If zero, the training continues until the last epoch is reached.
* @param epochs_btw_reports Number of epochs between the notifications on the stdOut
* @param stdOut The object representing the output. It can be either a PrintStream or a NeuralNetListener instance. If null, no notifications will be made.
* @param async if true, the method returns after having stated the network, without waiting for the completition. In this case, the value returned is zero.
* @return The final training RMSE (or MSE)
"""
print "wait.. training.."
nnwt=JooneTools.train(nnet,inputTrain,desiredTrain,5000,0.010,100,sout,0)


# Gets and prints the final values
attrib = nnet.getDescriptor()

out_text1="\nLast training rmse="+str(attrib.getTrainingError())
out_text1=out_text1+" at epoch "+str(attrib.getLastEpoch())
print  out_text1
sout.print( out_text1+"\n")


mess="write the trained NN to a serialized file"
sout.print("\n--------- "+mess+" ----------------\n");

# clean up from the input:
# we do not need to put all such information
# in serialized form
# however, if you want to contibue with training,
# do not resert anything!
nnet.resetInput()
nnet.removeAllOutputs()
nnet.removeAllInputs()
# save it
JooneTools.save(nnet,nnOutput)




"""
 * Compare the output and target data of a trained neural network using 2D array of double as the input/desired data sources.
 * If Monitor.validationPatterns = 0, all the input array's rows will be used for testing.
 * @param nnet The neural network to test
 * @param input 2D array of double containing the test data. The # of columns must be equal to the # of input nodes
 * @param desired 2D array of double containing the target data. The # of columns must be equal to the # of output nodes
 * @return a 2D of double containing the output+desired data for each pattern.
"""

# now compare outputs, i.e. verify the sample
out = JooneTools.compare(nnet,inputTest,desiredTest)
sout.print("\nComparion of the last "+str(out.__len__())+ " rows:\n")
cols = (out[0].__len__())/2

for i in range(out.__len__()):
        sout.print('\n NN Output: ')
        for x in range(cols):
             sout.print(out[i][x])
      
        sout.print ('\t Expected Target=')
        for x in range( cols, cols*2  ):
             sout.print (out[i][x])
             sout.print (" ")



print "Log file is",logName
view.open( logName, 0  )






          












# jHepWork @S.Chekanov