All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hivemall.smile.vm.StackMachine Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */
package hivemall.smile.vm;

import hivemall.utils.lang.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

// for tree_predict_v1
@Deprecated
public final class StackMachine {
    public static final String SEP = "; ";

    @Nonnull
    private final List code;
    @Nonnull
    private final Map valuesMap;
    @Nonnull
    private final Map jumpMap;
    @Nonnull
    private final Stack programStack;

    /**
     * Instruction pointer
     */
    private int IP;

    /**
     * Stack pointer
     */
    @SuppressWarnings("unused")
    private int SP;

    private int codeLength;
    private boolean[] done;
    private Double result;

    public StackMachine() {
        this.code = new ArrayList();
        this.valuesMap = new HashMap();
        this.jumpMap = new HashMap();
        this.programStack = new Stack();
        this.SP = 0;
        this.result = null;
    }

    public void run(@Nonnull String scripts, @Nonnull double[] features) throws VMRuntimeException {
        compile(scripts);
        eval(features);
    }

    public void run(@Nonnull List opslist, @Nonnull double[] features)
            throws VMRuntimeException {
        compile(opslist);
        eval(features);
    }

    public void compile(@Nonnull String scripts) throws VMRuntimeException {
        List opslist = Arrays.asList(scripts.split(SEP));
        compile(opslist);
    }

    public void compile(@Nonnull List opslist) throws VMRuntimeException {
        for (String line : opslist) {
            String[] ops = line.split(" ", -1);
            if (ops.length == 2) {
                Operation.OperationEnum o = Operation.OperationEnum.valueOfLowerCase(ops[0]);
                code.add(new Operation(o, ops[1]));
            } else {
                Operation.OperationEnum o = Operation.OperationEnum.valueOfLowerCase(ops[0]);
                code.add(new Operation(o));
            }
        }

        int size = opslist.size();
        this.codeLength = size - 1;
        this.done = new boolean[size];
    }

    public void eval(final double[] features) throws VMRuntimeException {
        init();
        bind(features);
        execute(0);
    }

    private void init() {
        valuesMap.clear();
        jumpMap.clear();
        programStack.clear();
        this.SP = 0;
        this.result = null;
        Arrays.fill(done, false);
    }

    private void bind(final double[] features) {
        final StringBuilder buf = new StringBuilder();
        for (int i = 0; i < features.length; i++) {
            String bindKey = buf.append("x[").append(i).append("]").toString();
            valuesMap.put(bindKey, features[i]);
            StringUtils.clear(buf);
        }
    }

    private void execute(int entryPoint) throws VMRuntimeException {
        valuesMap.put("end", -1.0);
        jumpMap.put("last", codeLength);

        IP = entryPoint;

        while (IP < code.size()) {
            if (done[IP]) {
                throw new VMRuntimeException("There is a infinite loop in the Machine code.");
            }
            done[IP] = true;
            Operation currentOperation = code.get(IP);
            if (!executeOperation(currentOperation)) {
                return;
            }
        }
    }

    @Nullable
    public Double getResult() {
        return result;
    }

    private Double pop() {
        SP--;
        return programStack.pop();
    }

    private Double push(Double val) {
        programStack.push(val);
        SP++;
        return val;
    }

    private boolean executeOperation(Operation currentOperation) throws VMRuntimeException {
        if (IP < 0) {
            return false;
        }
        switch (currentOperation.op) {
            case GOTO: {
                if (StringUtils.isInt(currentOperation.operand)) {
                    IP = Integer.parseInt(currentOperation.operand);
                } else {
                    IP = jumpMap.get(currentOperation.operand);
                }
                break;
            }
            case CALL: {
                double candidateIP = valuesMap.get(currentOperation.operand);
                if (candidateIP < 0) {
                    evaluateBuiltinByName(currentOperation.operand);
                    IP++;
                }
                break;
            }
            case IFEQ: {
                double a = pop();
                double b = pop();
                if (a == b) {
                    IP++;
                } else {
                    if (StringUtils.isInt(currentOperation.operand)) {
                        IP = Integer.parseInt(currentOperation.operand);
                    } else {
                        IP = jumpMap.get(currentOperation.operand);
                    }
                }
                break;
            }
            case IFEQ2: {// follow the rule of smile's Math class.
                double a = pop();
                double b = pop();
                if (smile.math.Math.equals(a, b)) {
                    IP++;
                } else {
                    if (StringUtils.isInt(currentOperation.operand)) {
                        IP = Integer.parseInt(currentOperation.operand);
                    } else {
                        IP = jumpMap.get(currentOperation.operand);
                    }
                }
                break;
            }
            case IFGE: {
                double lower = pop();
                double upper = pop();
                if (upper >= lower) {
                    IP++;
                } else {
                    if (StringUtils.isInt(currentOperation.operand)) {
                        IP = Integer.parseInt(currentOperation.operand);
                    } else {
                        IP = jumpMap.get(currentOperation.operand);
                    }
                }
                break;
            }
            case IFGT: {
                double lower = pop();
                double upper = pop();
                if (upper > lower) {
                    IP++;
                } else {
                    if (StringUtils.isInt(currentOperation.operand)) {
                        IP = Integer.parseInt(currentOperation.operand);
                    } else {
                        IP = jumpMap.get(currentOperation.operand);
                    }
                }
                break;
            }
            case IFLE: {
                double lower = pop();
                double upper = pop();
                if (upper <= lower) {
                    IP++;
                } else {
                    if (StringUtils.isInt(currentOperation.operand)) {
                        IP = Integer.parseInt(currentOperation.operand);
                    } else {
                        IP = jumpMap.get(currentOperation.operand);
                    }
                }
                break;
            }
            case IFLT: {
                double lower = pop();
                double upper = pop();
                if (upper < lower) {
                    IP++;
                } else {
                    if (StringUtils.isInt(currentOperation.operand)) {
                        IP = Integer.parseInt(currentOperation.operand);
                    } else {
                        IP = jumpMap.get(currentOperation.operand);
                    }
                }
                break;
            }
            case POP: {
                valuesMap.put(currentOperation.operand, pop());
                IP++;
                break;
            }
            case PUSH: {
                if (StringUtils.isDouble(currentOperation.operand)) {
                    push(Double.parseDouble(currentOperation.operand));
                } else {
                    Double v = valuesMap.get(currentOperation.operand);
                    if (v == null) {
                        throw new VMRuntimeException(
                            "value is not bound: " + currentOperation.operand);
                    }
                    push(v);
                }
                IP++;
                break;
            }
            default:
                throw new VMRuntimeException(
                    "Machine code has wrong opcode :" + currentOperation.op);
        }
        return true;

    }

    private void evaluateBuiltinByName(String name) throws VMRuntimeException {
        if (name.equals("end")) {
            this.result = pop();
        } else {
            throw new VMRuntimeException("Machine code has wrong built-in function :" + name);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy