/*
* Encog(tm) Core v3.4 - Java Version
* http://www.heatonresearch.com/encog/
* https://github.com/encog/encog-java-core
* Copyright 2008-2016 Heaton Research, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* For more information on Heaton Research copyrights, licenses
* and trademarks visit:
* http://www.heatonresearch.com/copyright
*/
package org.encog.app.analyst.script;
import java.io.File;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.encog.app.analyst.AnalystError;
import org.encog.app.analyst.script.ml.ScriptOpcode;
import org.encog.app.analyst.script.normalize.AnalystField;
import org.encog.app.analyst.script.process.ProcessField;
import org.encog.app.analyst.script.prop.PropertyConstraints;
import org.encog.app.analyst.script.prop.PropertyEntry;
import org.encog.app.analyst.script.segregate.AnalystSegregateTarget;
import org.encog.app.analyst.script.task.AnalystTask;
import org.encog.persist.EncogWriteHelper;
/**
* Used to save an Encog Analyst script.
*
*/
public class ScriptSave {
/**
* The script to save.
*/
private final AnalystScript script;
/**
* Construct the script.
*
* @param theScript
* The script to save.
*/
public ScriptSave(final AnalystScript theScript) {
this.script = theScript;
}
/**
* Save the script to a stream.
*
* @param stream
* The output stream.
*/
public void save(final OutputStream stream) {
final EncogWriteHelper out = new EncogWriteHelper(stream);
saveSubSection(out, "HEADER", "DATASOURCE");
saveConfig(out);
if (this.script.getFields() != null) {
saveData(out);
saveNormalize(out);
}
saveProcess(out);
saveSubSection(out, "RANDOMIZE", "CONFIG");
saveSubSection(out, "CLUSTER", "CONFIG");
saveSubSection(out, "BALANCE", "CONFIG");
saveSubSection(out, "CODE", "CONFIG");
if (this.script.getSegregate().getSegregateTargets() != null) {
saveSegregate(out);
}
saveSubSection(out, "GENERATE", "CONFIG");
saveMachineLearning(out);
saveTasks(out);
out.flush();
}
private void saveProcess(EncogWriteHelper out) {
saveSubSection(out, "PROCESS", "CONFIG");
out.addSubSection("FIELDS");
out.addColumn("name");
out.addColumn("command");
out.writeLine();
for (final ProcessField field : this.script.getProcess().getFields()) {
out.addColumn(field.getName());
out.addColumn(field.getCommand());
out.writeLine();
}
out.flush();
}
/**
* Save the config info.
*
* @param out
* THe output file.
*/
private void saveConfig(final EncogWriteHelper out) {
saveSubSection(out, "SETUP", "CONFIG");
out.addSubSection("FILENAMES");
final List<String> list = this.script.getProperties().getFilenames();
for (final String key : list) {
final String value = this.script.getProperties().getFilename(key);
final File f = new File(value);
if ((f.getParent() != null)
&& f.getParent()
.equalsIgnoreCase(this.script.getBasePath())) {
out.writeProperty(key, f.getName());
} else {
out.writeProperty(key, value);
}
}
}
/**
* Save the data fields.
*
* @param out
* The output file.
*/
private void saveData(final EncogWriteHelper out) {
saveSubSection(out, "DATA", "CONFIG");
out.addSubSection("STATS");
out.addColumn("name");
out.addColumn("isclass");
out.addColumn("iscomplete");
out.addColumn("isint");
out.addColumn("isreal");
out.addColumn("amax");
out.addColumn("amin");
out.addColumn("mean");
out.addColumn("sdev");
out.addColumn("source");
out.writeLine();
for (final DataField field : this.script.getFields()) {
out.addColumn(field.getName());
out.addColumn(field.isClass());
out.addColumn(field.isComplete());
out.addColumn(field.isInteger());
out.addColumn(field.isReal());
out.addColumn(field.getMax());
out.addColumn(field.getMin());
out.addColumn(field.getMean());
out.addColumn(field.getStandardDeviation());
out.addColumn(field.getSource());
out.writeLine();
}
out.flush();
out.addSubSection("CLASSES");
out.addColumn("field");
out.addColumn("code");
out.addColumn("name");
out.addColumn("count");
out.writeLine();
for (final DataField field : this.script.getFields()) {
if (field.isClass()) {
for (final AnalystClassItem col : field.getClassMembers()) {
out.addColumn(field.getName());
out.addColumn(col.getCode());
out.addColumn(col.getName());
out.addColumn(col.getCount());
out.writeLine();
}
}
}
}
/**
* Save the ML sections.
*
* @param out
* The output file.
*/
private void saveMachineLearning(final EncogWriteHelper out) {
saveSubSection(out, "ML", "CONFIG");
saveSubSection(out, "ML", "TRAIN");
out.addSubSection("OPCODES");
out.addColumn("code");
out.addColumn("count");
out.writeLine();
for( final ScriptOpcode so: this.script.getOpcodes() ) {
out.addColumn(so.getName());
out.addColumn(so.getArgCount());
out.writeLine();
}
}
/**
* Save the normalization data.
*
* @param out
* The output file.
*/
private void saveNormalize(final EncogWriteHelper out) {
saveSubSection(out, "NORMALIZE", "CONFIG");
out.addSubSection("RANGE");
out.addColumn("name");
out.addColumn("io");
out.addColumn("timeSlice");
out.addColumn("action");
out.addColumn("high");
out.addColumn("low");
out.writeLine();
for (final AnalystField field : this.script.getNormalize()
.getNormalizedFields()) {
out.addColumn(field.getName());
if (field.isInput()) {
out.addColumn("input");
} else {
out.addColumn("output");
}
out.addColumn(field.getTimeSlice());
switch (field.getAction()) {
case Ignore:
out.addColumn("ignore");
break;
case Normalize:
out.addColumn("range");
break;
case PassThrough:
out.addColumn("pass");
break;
case OneOf:
out.addColumn("oneof");
break;
case Equilateral:
out.addColumn("equilateral");
break;
case SingleField:
out.addColumn("single");
break;
default:
throw new AnalystError("Unknown action: " + field.getAction());
}
out.addColumn(field.getNormalizedHigh());
out.addColumn(field.getNormalizedLow());
out.writeLine();
}
}
/**
* Save segregate info.
* @param out The output file.
*/
private void saveSegregate(final EncogWriteHelper out) {
saveSubSection(out, "SEGREGATE", "CONFIG");
out.addSubSection("FILES");
out.addColumn("file");
out.addColumn("percent");
out.writeLine();
for (final AnalystSegregateTarget target : this.script.getSegregate()
.getSegregateTargets()) {
out.addColumn(target.getFile());
out.addColumn(target.getPercent());
out.writeLine();
}
}
/**
* Save a subsection.
* @param out The output file.
* @param section The section.
* @param subSection The subsection.
*/
private void saveSubSection(final EncogWriteHelper out,
final String section, final String subSection) {
if (!section.equals(out.getCurrentSection())) {
out.addSection(section);
}
out.addSubSection(subSection);
final List<PropertyEntry> list = PropertyConstraints.getInstance()
.getEntries(section, subSection);
if (list != null) {
Collections.sort(list);
for (final PropertyEntry entry : list) {
final String key = section + ":" + subSection + "_"
+ entry.getName();
final String value = this.script.getProperties()
.getPropertyString(key);
if (value != null) {
out.writeProperty(entry.getName(), value);
} else {
out.writeProperty(entry.getName(), "");
}
}
}
}
/**
* Save the tasks.
* @param out The output file.
*/
private void saveTasks(final EncogWriteHelper out) {
out.addSection("TASKS");
final List<String> list = new ArrayList<String>();
list.addAll(this.script.getTasks().keySet());
Collections.sort(list);
for (final String key : list) {
final AnalystTask task = this.script.getTask(key);
out.addSubSection(task.getName());
for (final String line : task.getLines()) {
out.addLine(line);
}
}
}
}