    001    package org.maltparser.ml.lib;
    002
    003    import java.io.BufferedOutputStream;
    004    import java.io.BufferedReader;
    005    import java.io.BufferedWriter;
    006    import java.io.File;
    007    import java.io.FileNotFoundException;
    008    import java.io.FileOutputStream;
    009    import java.io.IOException;
    010    import java.io.InputStream;
    011    import java.io.InputStreamReader;
    012    import java.io.ObjectInputStream;
    013    import java.io.ObjectOutputStream;
    014    import java.io.OutputStream;
    015
    016    import java.io.OutputStreamWriter;
    017    import java.util.ArrayList;
    018
    019    import org.apache.log4j.Logger;
    020
    021    import java.util.Formatter;
    022    import java.util.LinkedHashMap;
    023    import java.util.Set;
    024    import java.util.jar.JarEntry;
    025    import java.util.regex.Pattern;
    026    import java.util.regex.PatternSyntaxException;
    027
    028
    029    import org.maltparser.core.exception.MaltChainedException;
    030    import org.maltparser.core.feature.FeatureVector;
    031    import org.maltparser.core.feature.function.FeatureFunction;
    032    import org.maltparser.core.feature.value.FeatureValue;
    033    import org.maltparser.core.feature.value.MultipleFeatureValue;
    034    import org.maltparser.core.feature.value.SingleFeatureValue;
    035    import org.maltparser.core.syntaxgraph.DependencyStructure;
    036    import org.maltparser.ml.LearningMethod;
    037    import org.maltparser.parser.DependencyParserConfig;
    038    import org.maltparser.parser.guide.instance.InstanceModel;
    039    import org.maltparser.parser.history.action.SingleDecision;
    040
    041    public abstract class Lib implements LearningMethod {
    042            protected Verbostity verbosity;
    043            public enum Verbostity {
    044                    SILENT, ERROR, ALL
    045            }
    046            protected InstanceModel owner;
    047            protected int learnerMode;
    048            protected String name;
    049            protected int numberOfInstances;
    050            protected boolean saveInstanceFiles;
    051            protected boolean excludeNullValues;
    052            protected BufferedWriter instanceOutput = null;
    053            protected FeatureMap featureMap;
    054            protected String paramString;
    055            protected String pathExternalTrain;
    056            protected LinkedHashMap<String, String> libOptions;
    057            protected String allowedLibOptionFlags;
    058            protected Logger configLogger;
    059            final Pattern tabPattern = Pattern.compile("\t");
    060            final Pattern pipePattern = Pattern.compile("\\|");
    061            private StringBuilder sb = new StringBuilder();
    062            protected MaltLibModel model = null;
    063            /**
    064             * Constructs a Lib learner.
    065             *
    066             * @param owner the guide model owner
    067             * @param learnerMode the mode of the learner BATCH or CLASSIFY
    068             */
    069            public Lib(InstanceModel owner, Integer learnerMode, String learningMethodName) throws MaltChainedException {
    070                    setOwner(owner);
    071                    setLearnerMode(learnerMode.intValue());
    072                    setNumberOfInstances(0);
    073                    setLearningMethodName(learningMethodName);
    074                    verbosity = Verbostity.SILENT;
    075                    configLogger = owner.getGuide().getConfiguration().getConfigLogger();
    076                    initLibOptions();
    077                    initAllowedLibOptionFlags();
    078                    parseParameters(getConfiguration().getOptionValue("lib", "options").toString());
    079                    initSpecialParameters();
    080
    081                    if (learnerMode == BATCH) {
    082                            featureMap = new FeatureMap();
    083                            instanceOutput = new BufferedWriter(getInstanceOutputStreamWriter(".ins"));
    084                    } else if (learnerMode == CLASSIFY) {
    085                            featureMap = loadFeatureMap(getInputStreamFromConfigFileEntry(".map"));
    086                    }
    087            }
    088
    089
    090            public void addInstance(SingleDecision decision, FeatureVector featureVector) throws MaltChainedException {
    091                    if (featureVector == null) {
    092                            throw new LibException("The feature vector cannot be found");
    093                    } else if (decision == null) {
    094                            throw new LibException("The decision cannot be found");
    095                    }
    096
    097                    try {
    098                            sb.append(decision.getDecisionCode()+"\t");
    099                            final int n = featureVector.size();
    100                            for (int i = 0; i < n; i++) {
    101                                    FeatureValue featureValue = featureVector.getFeatureValue(i);
    102                                    if (featureValue == null || (excludeNullValues == true && featureValue.isNullValue())) {
    103                                            sb.append("-1");
    104                                    } else {
    105                                            if (featureValue instanceof SingleFeatureValue) {
    106                                                    SingleFeatureValue singleFeatureValue = (SingleFeatureValue)featureValue;
    107                                                    if (singleFeatureValue.getValue() == 1) {
    108                                                            sb.append(singleFeatureValue.getIndexCode());
    109                                                    } else if (singleFeatureValue.getValue() == 0) {
    110                                                            sb.append("-1");
    111                                                    } else {
    112                                                            sb.append(singleFeatureValue.getIndexCode());
    113                                                            sb.append(":");
    114                                                            sb.append(singleFeatureValue.getValue());
    115                                                    }
    116                                            } else if (featureValue instanceof MultipleFeatureValue) {
    117                                                    Set<Integer> values = ((MultipleFeatureValue)featureValue).getCodes();
    118                                                    int j=0;
    119                                                    for (Integer value : values) {
    120                                                            sb.append(value.toString());
    121                                                            if (j != values.size()-1) {
    122                                                                    sb.append("|");
    123                                                            }
    124                                                            j++;
    125                                                    }
    126                                            } else {
    127                                                    throw new LibException("Don't recognize the type of feature value: "+featureValue.getClass());
    128                                            }
    129                                    }
    130                                    sb.append('\t');
    131                            }
    132                            sb.append('\n');
    133                            instanceOutput.write(sb.toString());
    134                            instanceOutput.flush();
    135                            increaseNumberOfInstances();
    136                            sb.setLength(0);
    137                    } catch (IOException e) {
    138                            throw new LibException("The learner cannot write to the instance file. ", e);
    139                    }
    140            }
    141
    142            public void finalizeSentence(DependencyStructure dependencyGraph) throws MaltChainedException { }
    143
    144            public void moveAllInstances(LearningMethod method,
    145                            FeatureFunction divideFeature,
    146                            ArrayList<Integer> divideFeatureIndexVector)
    147                            throws MaltChainedException {
    148                    if (method == null) {
    149                            throw new LibException("The learning method cannot be found. ");
    150                    } else if (divideFeature == null) {
    151                            throw new LibException("The divide feature cannot be found. ");
    152                    }
    153
    154                    try {
    155                            final BufferedReader in = new BufferedReader(getInstanceInputStreamReader(".ins"));
    156                            final BufferedWriter out = method.getInstanceWriter();
    157                            final StringBuilder sb = new StringBuilder(6);
    158                            int l = in.read();
    159                            char c;
    160                            int j = 0;
    161
    162                            while(true) {
    163                                    if (l == -1) {
    164                                            sb.setLength(0);
    165                                            break;
    166                                    }
    167                                    c = (char)l;
    168                                    l = in.read();
    169                                    if (c == '\t') {
    170                                            if (divideFeatureIndexVector.contains(j-1)) {
    171                                                    out.write(Integer.toString(((SingleFeatureValue)divideFeature.getFeatureValue()).getIndexCode()));
    172                                                    out.write('\t');
    173                                            }
    174                                            out.write(sb.toString());
    175                                            j++;
    176                                            out.write('\t');
    177                                            sb.setLength(0);
    178                                    } else if (c == '\n') {
    179                                            out.write(sb.toString());
    180                                            if (divideFeatureIndexVector.contains(j-1)) {
    181                                                    out.write('\t');
    182                                                    out.write(Integer.toString(((SingleFeatureValue)divideFeature.getFeatureValue()).getIndexCode()));
    183                                            }
    184                                            out.write('\n');
    185                                            sb.setLength(0);
    186                                            method.increaseNumberOfInstances();
    187                                            this.decreaseNumberOfInstances();
    188                                            j = 0;
    189                                    } else {
    190                                            sb.append(c);
    191                                    }
    192                            }
    193                            in.close();
    194                            getFile(".ins").delete();
    195                            out.flush();
    196                    } catch (SecurityException e) {
    197                            throw new LibException("The learner cannot remove the instance file. ", e);
    198                    } catch (NullPointerException  e) {
    199                            throw new LibException("The instance file cannot be found. ", e);
    200                    } catch (FileNotFoundException e) {
    201                            throw new LibException("The instance file cannot be found. ", e);
    202                    } catch (IOException e) {
    203                            throw new LibException("The learner read from the instance file. ", e);
    204                    }
    205            }
    206
    207            public void noMoreInstances() throws MaltChainedException {
    208                    closeInstanceWriter();
    209            }
    210
    211            public boolean predict(FeatureVector featureVector, SingleDecision decision) throws MaltChainedException {
    212                    if (featureVector == null) {
    213                            throw new LibException("The learner cannot predict the next class, because the feature vector cannot be found. ");
    214                    }
    215
    216                    final FeatureList featureList = new FeatureList();
    217                    final int size = featureVector.size();
    218                    for (int i = 1; i <= size; i++) {
    219                            final FeatureValue featureValue = featureVector.getFeatureValue(i-1);
    220                            if (featureValue != null && !(excludeNullValues == true && featureValue.isNullValue())) {
    221                                    if (featureValue instanceof SingleFeatureValue) {
    222                                            SingleFeatureValue singleFeatureValue = (SingleFeatureValue)featureValue;
    223                                            int index = featureMap.getIndex(i, singleFeatureValue.getIndexCode());
    224                                            if (index != -1 && singleFeatureValue.getValue() != 0) {
    225                                                    featureList.add(index,singleFeatureValue.getValue());
    226                                            }
    227                                    } else if (featureValue instanceof MultipleFeatureValue) {
    228                                            for (Integer value : ((MultipleFeatureValue)featureValue).getCodes()) {
    229                                                    int v = featureMap.getIndex(i, value);
    230                                                    if (v != -1) {
    231                                                            featureList.add(v,1);
    232                                                    }
    233                                            }
    234                                    }
    235                            }
    236                    }
    237                    try {
    238                            decision.getKBestList().addList(model.predict(featureList.toArray()));
    239    //                      decision.getKBestList().addList(prediction(featureList));
    240                    } catch (OutOfMemoryError e) {
    241                            throw new LibException("Out of memory. Please increase the Java heap size (-Xmx<size>). ", e);
    242                    }
    243                    return true;
    244            }
    245
    246    //      protected abstract int[] prediction(FeatureList featureList) throws MaltChainedException;
    247
    248            public void train(FeatureVector featureVector) throws MaltChainedException {
    249                    if (featureVector == null) {
    250                            throw new LibException("The feature vector cannot be found. ");
    251                    } else if (owner == null) {
    252                            throw new LibException("The parent guide model cannot be found. ");
    253                    }
    254                    long startTime = System.currentTimeMillis();
    255
    256    //              if (configLogger.isInfoEnabled()) {
    257    //                      configLogger.info("\nStart training\n");
    258    //              }
    259                    if (pathExternalTrain != null) {
    260                            trainExternal(featureVector);
    261                    } else {
    262                            trainInternal(featureVector);
    263                    }
    264    //              long elapsed = System.currentTimeMillis() - startTime;
    265    //              if (configLogger.isInfoEnabled()) {
    266    //                      configLogger.info("Time 1: " +new Formatter().format("%02d:%02d:%02d", elapsed/3600000, elapsed%3600000/60000, elapsed%60000/1000)+" ("+elapsed+" ms)\n");
    267    //              }
    268                    try {
    269    //                      if (configLogger.isInfoEnabled()) {
    270    //                              configLogger.info("\nSaving feature map "+getFile(".map").getName()+"\n");
    271    //                      }
    272                            saveFeatureMap(new BufferedOutputStream(new FileOutputStream(getFile(".map").getAbsolutePath())), featureMap);
    273                    } catch (FileNotFoundException e) {
    274                            throw new LibException("The learner cannot save the feature map file '"+getFile(".map").getAbsolutePath()+"'. ", e);
    275                    }
    276    //              elapsed = System.currentTimeMillis() - startTime;
    277    //              if (configLogger.isInfoEnabled()) {
    278    //                      configLogger.info("Time 2: " +new Formatter().format("%02d:%02d:%02d", elapsed/3600000, elapsed%3600000/60000, elapsed%60000/1000)+" ("+elapsed+" ms)\n");
    279    //              }
    280            }
    281            protected abstract void trainExternal(FeatureVector featureVector) throws MaltChainedException;
    282            protected abstract void trainInternal(FeatureVector featureVector) throws MaltChainedException;
    283
    284            public void terminate() throws MaltChainedException {
    285                    closeInstanceWriter();
    286                    owner = null;
    287                    model = null;
    288            }
    289
    290            public BufferedWriter getInstanceWriter() {
    291                    return instanceOutput;
    292            }
    293
    294            protected void closeInstanceWriter() throws MaltChainedException {
    295                    try {
    296                            if (instanceOutput != null) {
    297                                    instanceOutput.flush();
    298                                    instanceOutput.close();
    299                                    instanceOutput = null;
    300                            }
    301                    } catch (IOException e) {
    302                            throw new LibException("The learner cannot close the instance file. ", e);
    303                    }
    304            }
    305
    306
    307            /**
    308             * Returns the parameter string used for configure the learner
    309             *
    310             * @return the parameter string used for configure the learner
    311             */
    312            public String getParamString() {
    313                    return paramString;
    314            }
    315
    316            public InstanceModel getOwner() {
    317                    return owner;
    318            }
    319
    320            protected void setOwner(InstanceModel owner) {
    321                    this.owner = owner;
    322            }
    323
    324            public int getLearnerMode() {
    325                    return learnerMode;
    326            }
    327
    328            public void setLearnerMode(int learnerMode) throws MaltChainedException {
    329                    this.learnerMode = learnerMode;
    330            }
    331
    332            public String getLearningMethodName() {
    333                    return name;
    334            }
    335
    336            /**
    337             * Returns the current configuration
    338             *
    339             * @return the current configuration
    340             * @throws MaltChainedException
    341             */
    342            public DependencyParserConfig getConfiguration() throws MaltChainedException {
    343                    return owner.getGuide().getConfiguration();
    344            }
    345
    346            public int getNumberOfInstances() throws MaltChainedException {
    347                    if(numberOfInstances!=0)
    348                            return numberOfInstances;
    349                    else{
    350                            BufferedReader reader = new BufferedReader( getInstanceInputStreamReader(".ins"));
    351                            try {
    352                                    while(reader.readLine()!=null){
    353                                            numberOfInstances++;
    354                                            owner.increaseFrequency();
    355                                    }
    356                                    reader.close();
    357                            } catch (IOException e) {
    358                                    throw new MaltChainedException("No instances found in file",e);
    359                            }
    360                            return numberOfInstances;
    361                    }
    362            }
    363
    364            public void increaseNumberOfInstances() {
    365                    numberOfInstances++;
    366                    owner.increaseFrequency();
    367            }
    368
    369            public void decreaseNumberOfInstances() {
    370                    numberOfInstances--;
    371                    owner.decreaseFrequency();
    372            }
    373
    374            protected void setNumberOfInstances(int numberOfInstances) {
    375                    this.numberOfInstances = 0;
    376            }
    377
    378            protected void setLearningMethodName(String name) {
    379                    this.name = name;
    380            }
    381
    382            public String getPathExternalTrain() {
    383                    return pathExternalTrain;
    384            }
    385
    386
    387            public void setPathExternalTrain(String pathExternalTrain) {
    388                    this.pathExternalTrain = pathExternalTrain;
    389            }
    390
    391            protected OutputStreamWriter getInstanceOutputStreamWriter(String suffix) throws MaltChainedException {
    392                    return getConfiguration().getConfigurationDir().getAppendOutputStreamWriter(owner.getModelName()+getLearningMethodName()+suffix);
    393            }
    394
    395            protected InputStreamReader getInstanceInputStreamReader(String suffix) throws MaltChainedException {
    396                    return getConfiguration().getConfigurationDir().getInputStreamReader(owner.getModelName()+getLearningMethodName()+suffix);
    397            }
    398
    399            protected InputStreamReader getInstanceInputStreamReaderFromConfigFile(String suffix) throws MaltChainedException {
    400                    return getConfiguration().getConfigurationDir().getInputStreamReaderFromConfigFile(owner.getModelName()+getLearningMethodName()+suffix);
    401            }
    402
    403            protected InputStream getInputStreamFromConfigFileEntry(String suffix) throws MaltChainedException {
    404                    return getConfiguration().getConfigurationDir().getInputStreamFromConfigFileEntry(owner.getModelName()+getLearningMethodName()+suffix);
    405            }
    406
    407
    408            protected File getFile(String suffix) throws MaltChainedException {
    409                    return getConfiguration().getConfigurationDir().getFile(owner.getModelName()+getLearningMethodName()+suffix);
    410            }
    411
    412            protected JarEntry getConfigFileEntry(String suffix) throws MaltChainedException {
    413                    return getConfiguration().getConfigurationDir().getConfigFileEntry(owner.getModelName()+getLearningMethodName()+suffix);
    414            }
    415
    416            protected void initSpecialParameters() throws MaltChainedException {
    417                    if (getConfiguration().getOptionValue("singlemalt", "null_value") != null && getConfiguration().getOptionValue("singlemalt", "null_value").toString().equalsIgnoreCase("none")) {
    418                            excludeNullValues = true;
    419                    } else {
    420                            excludeNullValues = false;
    421                    }
    422                    saveInstanceFiles = ((Boolean)getConfiguration().getOptionValue("lib", "save_instance_files")).booleanValue();
    423                    if (!getConfiguration().getOptionValue("lib", "external").toString().equals("")) {
    424                            String path = getConfiguration().getOptionValue("lib", "external").toString();
    425                            try {
    426                                    if (!new File(path).exists()) {
    427                                            throw new LibException("The path to the external  trainer 'svm-train' is wrong.");
    428                                    }
    429                                    if (new File(path).isDirectory()) {
    430                                            throw new LibException("The option --lib-external points to a directory, the path should point at the 'train' file or the 'train.exe' file in the libsvm or the liblinear package");
    431                                    }
    432                                    if (!(path.endsWith("train") ||path.endsWith("train.exe"))) {
    433                                            throw new LibException("The option --lib-external does not specify the path to 'train' file or the 'train.exe' file in the libsvm or the liblinear package. ");
    434                                    }
    435                                    setPathExternalTrain(path);
    436                            } catch (SecurityException e) {
    437                                    throw new LibException("Access denied to the file specified by the option --lib-external. ", e);
    438                            }
    439                    }
    440                    if (getConfiguration().getOptionValue("lib", "verbosity") != null) {
    441                            verbosity = Verbostity.valueOf(getConfiguration().getOptionValue("lib", "verbosity").toString().toUpperCase());
    442                    }
    443            }
    444
    445            public String getLibOptions() {
    446                    StringBuilder sb = new StringBuilder();
    447                    for (String key : libOptions.keySet()) {
    448                            sb.append('-');
    449                            sb.append(key);
    450                            sb.append(' ');
    451                            sb.append(libOptions.get(key));
    452                            sb.append(' ');
    453                    }
    454                    return sb.toString();
    455            }
    456
    457            public String[] getLibParamStringArray() {
    458                    final ArrayList<String> params = new ArrayList<String>();
    459
    460                    for (String key : libOptions.keySet()) {
    461                            params.add("-"+key); params.add(libOptions.get(key));
    462                    }
    463                    return params.toArray(new String[params.size()]);
    464            }
    465
    466            public abstract void initLibOptions();
    467            public abstract void initAllowedLibOptionFlags();
    468
    469            public void parseParameters(String paramstring) throws MaltChainedException {
    470                    if (paramstring == null) {
    471                            return;
    472                    }
    473                    final String[] argv;
    474                    try {
    475                            argv = paramstring.split("[_\\p{Blank}]");
    476                    } catch (PatternSyntaxException e) {
    477                            throw new LibException("Could not split the parameter string '"+paramstring+"'. ", e);
    478                    }
    479                    for (int i=0; i < argv.length-1; i++) {
    480                            if(argv[i].charAt(0) != '-') {
    481                                    throw new LibException("The argument flag should start with the following character '-', not with "+argv[i].charAt(0));
    482                            }
    483                            if(++i>=argv.length) {
    484                                    throw new LibException("The last argument does not have any value. ");
    485                            }
    486                            try {
    487                                    int index = allowedLibOptionFlags.indexOf(argv[i-1].charAt(1));
    488                                    if (index != -1) {
    489                                            libOptions.put(Character.toString(argv[i-1].charAt(1)), argv[i]);
    490                                    } else {
    491                                            throw new LibException("Unknown learner parameter: '"+argv[i-1]+"' with value '"+argv[i]+"'. ");
    492                                    }
    493                            } catch (ArrayIndexOutOfBoundsException e) {
    494                                    throw new LibException("The learner parameter '"+argv[i-1]+"' could not convert the string value '"+argv[i]+"' into a correct numeric value. ", e);
    495                            } catch (NumberFormatException e) {
    496                                    throw new LibException("The learner parameter '"+argv[i-1]+"' could not convert the string value '"+argv[i]+"' into a correct numeric value. ", e);
    497                            } catch (NullPointerException e) {
    498                                    throw new LibException("The learner parameter '"+argv[i-1]+"' could not convert the string value '"+argv[i]+"' into a correct numeric value. ", e);
    499                            }
    500                    }
    501            }
    502
    503            protected void finalize() throws Throwable {
    504                    try {
    505                            closeInstanceWriter();
    506                    } finally {
    507                            super.finalize();
    508                    }
    509            }
    510
    511            public String toString() {
    512                    final StringBuffer sb = new StringBuffer();
    513                    sb.append("\n"+getLearningMethodName()+" INTERFACE\n");
    514                    sb.append(getLibOptions());
    515                    return sb.toString();
    516            }
    517
    518            protected int binariesInstance(String line, FeatureList featureList) throws MaltChainedException {
    519                    int y = -1;
    520                    featureList.clear();
    521                    try {
    522                            String[] columns = tabPattern.split(line);
    523
    524                            if (columns.length == 0) {
    525                                    return -1;
    526                            }
    527                            try {
    528                                    y = Integer.parseInt(columns[0]);
    529                            } catch (NumberFormatException e) {
    530                                    throw new LibException("The instance file contain a non-integer value '"+columns[0]+"'", e);
    531                            }
    532                            for(int j = 1; j < columns.length; j++) {
    533                                    final String[] items = pipePattern.split(columns[j]);
    534                                    for (int k = 0; k < items.length; k++) {
    535                                            try {
    536                                                    int colon = items[k].indexOf(':');
    537                                                    if (colon == -1) {
    538                                                            if (Integer.parseInt(items[k]) != -1) {
    539                                                                    int v = featureMap.addIndex(j, Integer.parseInt(items[k]));
    540                                                                    if (v != -1) {
    541                                                                            featureList.add(v,1);
    542                                                                    }
    543                                                            }
    544                                                    } else {
    545                                                            int index = featureMap.addIndex(j, Integer.parseInt(items[k].substring(0,colon)));
    546                                                            double value;
    547                                                            if (items[k].substring(colon+1).indexOf('.') != -1) {
    548                                                                    value = Double.parseDouble(items[k].substring(colon+1));
    549                                                            } else {
    550                                                                    value = Integer.parseInt(items[k].substring(colon+1));
    551                                                            }
    552                                                            featureList.add(index,value);
    553                                                    }
    554                                            } catch (NumberFormatException e) {
    555                                                    throw new LibException("The instance file contain a non-numeric value '"+items[k]+"'", e);
    556                                            }
    557                                    }
    558                            }
    559                    } catch (ArrayIndexOutOfBoundsException e) {
    560                            throw new LibException("Couln't read from the instance file. ", e);
    561                    }
    562                    return y;
    563            }
    564
    565            protected void binariesInstances2SVMFileFormat(InputStreamReader isr, OutputStreamWriter osw) throws MaltChainedException {
    566                    try {
    567                            final BufferedReader in = new BufferedReader(isr);
    568                            final BufferedWriter out = new BufferedWriter(osw);
    569                            final FeatureList featureSet = new FeatureList();
    570                            while(true) {
    571                                    String line = in.readLine();
    572                                    if(line == null) break;
    573                                    int y = binariesInstance(line, featureSet);
    574                                    if (y == -1) {
    575                                            continue;
    576                                    }
    577                                    out.write(Integer.toString(y));
    578
    579                            for (int k=0; k < featureSet.size(); k++) {
    580                                    MaltFeatureNode x = featureSet.get(k);
    581                                            out.write(' ');
    582                                            out.write(Integer.toString(x.getIndex()));
    583                                            out.write(':');
    584                                            out.write(Double.toString(x.getValue()));
    585                                    }
    586                                    out.write('\n');
    587                            }
    588                            in.close();
    589                            out.close();
    590                    } catch (NumberFormatException e) {
    591                            throw new LibException("The instance file contain a non-numeric value", e);
    592                    } catch (IOException e) {
    593                            throw new LibException("Couln't read from the instance file, when converting the Malt instances into LIBSV/LIBLINEAR format. ", e);
    594                    }
    595            }
    596
    597            protected void saveFeatureMap(OutputStream os, FeatureMap map) throws MaltChainedException {
    598                    try {
    599                        ObjectOutputStream output = new ObjectOutputStream(os);
    600                    try{
    601                      output.writeObject(map);
    602                    }
    603                    finally{
    604                      output.close();
    605                    }
    606                    } catch (IOException e) {
    607                            throw new LibException("Save feature map error", e);
    608                    }
    609            }
    610
    611            protected FeatureMap loadFeatureMap(InputStream is) throws MaltChainedException {
    612                    FeatureMap map = new FeatureMap();
    613                    try {
    614                        ObjectInputStream input = new ObjectInputStream(is);
    615                        try {
    616                            map = (FeatureMap)input.readObject();
    617                        } finally {
    618                            input.close();
    619                        }
    620                    } catch (ClassNotFoundException e) {
    621                            throw new LibException("Load feature map error", e);
    622                    } catch (IOException e) {
    623                            throw new LibException("Load feature map error", e);
    624                    }
    625                    return map;
    626            }
    627    }