com.bragi.sonify.composer.lsystem.LSystem.java Source code

Java tutorial

Introduction

Here is the source code for com.bragi.sonify.composer.lsystem.LSystem.java

Source

/*******************************************************************************
 * Copyright (c) 2012 BragiSoft, Inc.
 * This source is subject to the BragiSoft Permissive License.
 * Please see the License.txt file for more information.
 * All other rights reserved.
 * 
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * 
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Contributors:
 * Jan-Christoph Klie - Everything
 * 
 *******************************************************************************/

package com.bragi.sonify.composer.lsystem;

import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * An L-System is a mathematical structure, namely a variant of a formal
 * grammar. It is very similar to a semi-Thue system. 
 * 
 * It consists of a tuple G = (V, , P):
 * 
 * V (the alphabet): is a set of symbols containing elements that can be
 * replaced (variables)
 * 
 *  (start, axiom or initiator): is a string of symbols from V defining the
 * initial state of the system
 * 
 * P is a set of production rules or productions defining the way variables can
 * be replaced with combinations of constants and other variables. A production
 * consists of two strings, the predecessor and the successor. For any symbol A
 * in V which does not appear on the left hand side of a production in P, the
 * identity production A  A is assumed; these symbols are called constants or
 * terminals.
 */
public class LSystem {

    private Log log = LogFactory.getLog(LSystem.class);

    /**
     * The set of symbols which can be replaced by the given rules.
     */
    private Set<Character> alphabet;

    /**
     * The initial state of the system; from it, the process of applying rules starts.
     */
    private final String axiom;

    /**
     * The map of rules which state how the variables  are replaced. Key is the value
     * to replace, value the replacement itself.
     */
    private Map<String, String> rules;

    /**
     * 
     * @param alphabet The set of symbols which can be replaced by the given rules.
     * @param axiom The initial state of the system; from it, the process of applying rules starts.
     * @param rules The set of rules which state how the variables  are replaced.
     */
    public LSystem(Set<Character> alphabet, String axiom, Map<String, String> rules) {
        this.alphabet = alphabet;
        this.axiom = axiom;
        this.rules = rules;
    }

    /**
     * Creates a generation of the string starting with AXIOM (generation = 0) and returns it.
     * In every generating step, every possible replacement is performed. If there is no rule
     * for a symbol, it is seen as constant and not touched, just added to the intermediate result.
     * After finishing, it returns the word of the given generation.
     * 
     * @param generations The generation of the word asked for:
     * generation == 0: the resulting word is the axiom
     * generation > 0:  the resulting word is the word of the generation'th generation
     * generation < 0: not allowed
     * 
     * @return The generation of the word asked for
     */
    public String generate(int generations) {

        if (generations < 0) {
            throw new IllegalArgumentException("Generations cannot be negative! Was " + generations);
        }

        String state = axiom;

        for (int i = 0; i < generations; i++) {
            state = nextStep(state);
            log.debug(state);
        }

        return state;
    }

    /**
     * Creates the next generation of a word from the input given by currentState.
     * @param currentState The current state to work with
     * @return The next generation of the word
     */
    private String nextStep(String currentState) {

        StringBuilder sb = new StringBuilder();

        for (char c : currentState.toCharArray()) {
            if (rules.containsKey(Character.toString(c))) {
                sb.append(rules.get(Character.toString(c)));
            } else {
                sb.append(Character.toString(c));
            }
        }

        return sb.toString();

    }

    @Override
    public String toString() {
        return String.format("Alphabet:\t%s\nAxiom:\t\t%s\nRules:\t\t%s\n", alphabet, axiom, rules);
    }

}