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

nl.uu.cs.ape.utils.APEUtils Maven / Gradle / Ivy

Go to download

APE is a command line tool and an API for the automated exploration of possible computational pipelines (workflows) from large collections of computational tools.

The newest version!
package nl.uu.cs.ape.utils;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import nl.uu.cs.ape.configuration.APERunConfig;
import nl.uu.cs.ape.domain.APEDomainSetup;
import nl.uu.cs.ape.models.ConstraintTemplateData;
import nl.uu.cs.ape.models.Module;
import nl.uu.cs.ape.models.Pair;
import nl.uu.cs.ape.models.SATAtomMappings;
import nl.uu.cs.ape.models.Type;
import nl.uu.cs.ape.models.enums.LogicOperation;
import nl.uu.cs.ape.models.logic.constructs.PredicateLabel;
import nl.uu.cs.ape.models.logic.constructs.TaxonomyPredicate;
import nl.uu.cs.ape.models.sltlxStruc.SLTLxAtom;
import nl.uu.cs.ape.models.sltlxStruc.SLTLxAtomVar;
import nl.uu.cs.ape.solver.minisat.SATSynthesisEngine;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.IntStream;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * The {@link APEUtils} class provide static helper methods used within the
 * project.
 * 
 * @author Vedran Kasalica
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class APEUtils {

	private static final Map timers = new HashMap<>();
	private static final PrintStream original = System.err;
	private static final PrintStream nullStream = new PrintStream(new OutputStream() {
		@Override
		public void write(int b) {
		}
	});

	/**
	 * Create the full class IRI (ID) based on the label and the OWL prefix.
	 *
	 * @param label             Label of the current term.
	 * @param ontologyPrefixIRI OWL prefix information.
	 * @return String representing full OWL class IRI.
	 * @throws IllegalArgumentException Error if the given label is an empty String.
	 */
	public static String createClassIRI(String label, String ontologyPrefixIRI) throws IllegalArgumentException {
		if (label == null || label.equals("")) {
			throw new IllegalArgumentException("The OWL object label cannot be an empty String.");
		} else if (label.startsWith("http")) {
			return label;
		} else {
			return ontologyPrefixIRI + label;
		}
	}

	/**
	 * Create the full set of class IRI's (ID) based on the labels and the OWL
	 * prefix.
	 *
	 * @param taxonomyTerms     Tool labels.
	 * @param ontologyPrefixIRI OWL prefix information.
	 * @return Set of strings representing full OWL class IRI.
	 */
	public static Set createIRIsFromLabels(Set taxonomyTerms, String ontologyPrefixIRI) {
		Set taxonomyTermIRIs = new HashSet<>();
		for (String taxonomyTermLabel : taxonomyTerms) {
			taxonomyTermIRIs.add(createClassIRI(taxonomyTermLabel, ontologyPrefixIRI));
		}
		return taxonomyTermIRIs;
	}

	/**
	 * The method return a list of {@link JSONObject} elements that correspond to a
	 * given key in a Json file. If the key corresponds to a {@link JSONArray} all
	 * the elements are put in a {@link List}, otherwise if the key corresponds to a
	 * {@link JSONObject} list will contain only that object.
	 *
	 * @param jsonFile File instance containing a json file.
	 * @param key      Key label that corresponds to the elements.
	 * @return List of elements that corresponds to the key. If the key does not
	 *         exists returns empty list.
	 * @throws IOException Error in handling a JSON file.
	 */
	public static List getListFromJson(File jsonFile, String key) throws IOException, JSONException {
		String content = FileUtils.readFileToString(jsonFile, StandardCharsets.UTF_8);
		JSONObject jsonObject = new JSONObject(content);

		return getListFromJson(jsonObject, key, JSONObject.class);

	}

	/**
	 * The method return a list of {@code } elements that correspond to a given
	 * key in the given json object. If the key corresponds to a {@link JSONArray}
	 * all the elements are put in a {@link List}, otherwise if the key corresponds
	 * to a {@code } list will contain only that object.
	 *
	 * @param         Class to which the elements should belong to.
	 * @param jsonObject {@link JSONObject} that is being explored.
	 * @param key        Key label that corresponds to the elements.
	 * @param clazz      Class to which the elements should belong to.
	 * @return List of elements that corresponds to the key. If the key does not
	 *         exists returns empty list.
	 */
	public static  List getListFromJson(JSONObject jsonObject, String key, Class clazz) {
		List jsonList = new ArrayList<>();
		try {
			Object tmp = jsonObject.get(key);
			try {
				if (tmp instanceof JSONArray) {
					jsonList = getListFromJsonList((JSONArray) tmp, clazz);
				} else {
					T element = (T) tmp;
					jsonList.add(element);
				}
			} catch (JSONException e) {
				log.warn("Json parsing error. Expected object '" + clazz.getSimpleName() + "' under the tag '"
						+ key + "'. The following object does not match the provided format:\n"
						+ jsonObject.toString());
				return jsonList;
			}
			return jsonList;
		} catch (JSONException e) {
			// Return empty list in case the key doesn't exist.
			return jsonList;
		}
	}

	/**
	 * The method converts the {@link JSONArray} object to {@link List} of objects
	 * of the given structure.
	 *
	 * @param        Class to which the elements should belong to.
	 * @param jsonArray JSON array object.
	 * @param clazz     Class type that the elements of the array are.
	 * @return List of objects of type {@link T}.
	 */
	@SuppressWarnings("unchecked")
	public static  List getListFromJsonList(JSONArray jsonArray, Class clazz) {
		List newList = new ArrayList<>();
		for (int i = 0; i < jsonArray.length(); i++) {
			T element = (T) jsonArray.get(i);
			newList.add(element);
		}
		return newList;
	}

	/**
	 * Debug printout.
	 *
	 * @param runConfig   Configuration of the APE run.
	 * @param domainSetup Domain information, including all the existing tools and
	 *                    types.
	 */
	public static void debugPrintout(APERunConfig runConfig, APEDomainSetup domainSetup) {
		String line = "-------------------------------------------------------------";

		if (runConfig.getDebugMode()) {

			/*
			 * Printing the constraint templates
			 */
			log.debug(line);
			log.debug("\tConstraint templates:");
			log.debug(line);
			log.debug(domainSetup.getConstraintFactory().printConstraintsCodes() + "\n");

			/*
			 * Printing the Module and Taxonomy Tree
			 */
			log.debug(line);
			log.debug("\tTool Taxonomy:");
			log.debug(line);
			domainSetup.getAllModules().getRootModule().printTree(" ", domainSetup.getAllModules());
			log.debug("\n" + line);
			log.debug("\tData Taxonomy dimensions:");
			for (TaxonomyPredicate dimension : domainSetup.getAllTypes().getRootPredicates()) {
				log.debug("\n" + line);
				log.debug("\t" + dimension.getPredicateLabel() + "Taxonomy:");
				log.debug(line);
				dimension.printTree(" ", domainSetup.getAllTypes());
			}
			log.debug(line);
			log.debug("\tLabels Taxonomy:");
			log.debug(line);
			domainSetup.getAllTypes().getLabelRoot().printTree(" ", domainSetup.getAllTypes());

			/*
			 * Printing the tool annotations
			 */
			boolean noTools = true;
			log.debug(line);
			log.debug("\tAnnotated tools:");
			log.debug(line);
			for (TaxonomyPredicate module : domainSetup.getAllModules().getModules()) {
				if (module instanceof Module) {
					log.debug(module.toString());
					noTools = false;
				}
			}
			if (noTools) {
				log.debug("\tNo annotated tools.");
			}

			/*
			 * Print out the constraints
			 */
			log.debug(line);
			log.debug("\tConstraints:");
			log.debug(line);
			for (ConstraintTemplateData constr : domainSetup.getUnformattedConstr()) {
				log.debug(domainSetup.getConstraintFactory().getDescription(constr));
			}
			if (domainSetup.getUnformattedConstr().isEmpty()) {
				log.debug("\tNo constraints.");
			}
			log.debug(line);

			int i = 1;
			for (Type input : runConfig.getProgramInputs()) {
				log.debug((i++) + ". program input is " + input.toShortString());
			}
			log.debug(line);
			i = 1;
			for (Type output : runConfig.getProgramOutputs()) {
				log.debug((i++) + ". program output is " + output.toShortString());
			}
			log.debug(line);
		}
	}

	/**
	 * Print header to illustrate the part of the synthesis that is being performed.
	 *
	 * @param argument Order number of the (sub)title.
	 * @param title    The mail content of the title.
	 */
	public static void printHeader(Integer argument, String... title) {
		String line = "-------------------------------------------------------------";

		String arg = (argument == null) ? "" : (" " + argument);

		log.info(line);
		log.info("\t" + title[0] + arg);
		if (title.length > 1) {
			log.info("\t" + title[1] + arg);
		}
		log.info(line);
	}

	/**
	 * Provide a safe interface for iteration trough a list/set.
	 *
	 * @param       Any type.
	 * @param currList List/set that is being evaluated.
	 * @return An empty list in case of {@code currList == null}, or
	 *         {@code currList} otherwise.
	 */
	public static  Collection safe(Collection currList) {
		return currList == null ? Collections.emptyList() : currList;
	}

	/**
	 * Provide a safe interface for getting an element from a list. In order to
	 * bypass "index out of bounds" error.
	 *
	 * @param       Any type.
	 * @param currList List of elements.
	 * @param index    Index of the element that is to be returned.
	 * @return Element of the list, or null if the index is out of bounds.
	 */
	public static  E safeGet(List currList, int index) {
		if (currList == null || index < 0 || currList.size() <= index) {
			return null;
		} else {
			return currList.get(index);
		}
	}

	/**
	 * Functions sets an element into a list at a specific place, if the element
	 * already exists, it overrides it. If the element is out of bound it creates
	 * null elements to fit the given size of the array and then adds the new
	 * element. If the index is negative number it does not change the array.
	 *
	 * @param      Any type.
	 * @param list    List that is manipulated.
	 * @param index   Absolute position of the new element.
	 * @param element New element to be added to the list.
	 * @throws IndexOutOfBoundsException Exception if the index is out of range
	 *                                   (index < 0).
	 */
	public static  void safeSet(List list, int index, E element) {
		if (index < 0) {
			throw new IndexOutOfBoundsException();
		}
		if (list.size() == index) {
			list.add(element);
		} else if (list.size() >= index) {
			list.set(index, element);
		}
		if (list.size() < index) {
			for (int i = list.size(); i < index; i++) {
				list.add(null);
			}
			list.add(element);
		}
	}

	/**
	 * Count number of new lines in a Sting.
	 *
	 * @param inputString String that is evaluated.
	 * @return Number of lines in the String.
	 * @throws IOException In case that the string.
	 */
	public static int countNewLines(String inputString) throws IOException {
		try (InputStream stream = IOUtils.toInputStream(inputString, StandardCharsets.UTF_8)) {
			byte[] c = new byte[1024];

			int readChars = stream.read(c);
			if (readChars == -1) {
				// bail out if nothing to read
				return 1;
			}

			// make it easy for the optimizer to tune this loop
			int count = 0;
			while (readChars == 1024) {
				for (int i = 0; i < 1024;) {
					if (c[i++] == '\n') {
						++count;
					}
				}
				readChars = stream.read(c);
			}

			// count remaining characters
			while (readChars != -1) {
				for (int i = 0; i < readChars; ++i) {
					if (c[i] == '\n') {
						++count;
					}
				}
				readChars = stream.read(c);
			}

			return count == 0 ? 1 : count;
		}
	}

	/**
	 * Timer start if in debug mode.
	 *
	 * @param timerID   the timer id
	 * @param debugMode the debug mode
	 */
	public static void timerStart(String timerID, Boolean debugMode) {
		if (Boolean.TRUE.equals(debugMode)) {
			timers.put(timerID, System.currentTimeMillis());
		} else {
			timers.put(timerID, (long) -1);
		}
	}

	/**
	 * Return the time left on the timer in milliseconds.
	 * 
	 * @param timerID Timer ID, used to identify the timer.
	 * @param timeout Set timeout (for the synthesis).
	 * @return Time left on the timer in milliseconds.
	 */
	public static long timerTimeLeft(String timerID, long timeout) {
		if (timers.get(timerID) == -1) {
			return 0;
		}

		long elapsedTimeMs = System.currentTimeMillis() - timers.get(timerID);
		return timeout - elapsedTimeMs;
	}

	/**
	 * Timer restart and print.
	 *
	 * @param timerID     the timer id
	 * @param printString the print string
	 */
	public static void timerRestartAndPrint(String timerID, String printString) {
		if (timers.get(timerID) == -1) {
			return;
		}
		long printTime = System.currentTimeMillis() - timers.get(timerID);
		log.info(printString + " setup time: " + (printTime / 1000F) + " sec.");
		timers.put(timerID, System.currentTimeMillis());

		// APEUtils.printMemoryStatus(true);
	}

	/**
	 * Timer print solutions.
	 *
	 * @param timerID        the timer id
	 * @param solutionsFound the solutions found
	 * @return The time counted by the timer.
	 */
	public static long timerPrintSolutions(String timerID, int solutionsFound) {
		if (timers.get(timerID) == -1) {
			return -1;
		}
		long printTime = System.currentTimeMillis() - timers.get(timerID);
		log.info("APE found " + solutionsFound + " solutions.");
		log.info("Total APE runtime: \t\t" + (printTime / 1000F) + " sec.");
		log.info("Total encoding time: \t\t" + (SATSynthesisEngine.getTotalEncodingTime() / 1000F) + " sec.");
		log.info("Total SAT solving time: \t" + (SATSynthesisEngine.getTotalSolvingTime() / 1000F) + " sec.");
		return printTime;
	}

	/**
	 * Timer print text.
	 *
	 * @param timerID the timer id
	 * @param text    the text
	 */
	public static void timerPrintText(String timerID, String text) {
		if (timers.get(timerID) == -1) {
			return;
		}
		long printTime = System.currentTimeMillis() - timers.get(timerID);
		log.info(text + " Running time: " + (printTime / 1000F) + " sec.");
	}

	/**
	 * Convert cnf 2 human readable string.
	 *
	 * @param tempSatInput the temp sat input
	 * @param mappings     the mappings
	 * @return the string
	 */
	public static String convertCNF2humanReadable(InputStream tempSatInput, SATAtomMappings mappings) {
		StringBuilder humanReadable = new StringBuilder();
		Scanner scanner = new Scanner(tempSatInput);
		scanner.nextLine();
		while (scanner.hasNextInt()) {
			int intAtom = scanner.nextInt();

			if (intAtom == 0) {
				humanReadable.append("\n");
			} else if (intAtom > -3 & intAtom < 3) {
				if (intAtom == 1 || intAtom == -2) {
					humanReadable.append("true ");
				} else {
					humanReadable.append("false ");
				}
			} else if (intAtom > 0) {
				SLTLxAtom atom = mappings.findOriginal(intAtom);
				if (atom == null) {
					SLTLxAtomVar varAtom = mappings.findOriginalVar(intAtom);
					humanReadable.append(varAtom.toString()).append(" ");
				} else {
					humanReadable.append(atom.toString()).append(" ");
				}

			} else if (intAtom < 0) {
				SLTLxAtom atom = mappings.findOriginal(-intAtom);
				if (atom == null) {
					SLTLxAtomVar varAtom = mappings.findOriginalVar(-intAtom);
					if (varAtom == null) {
						log.error("Error: Could not find atom for " + intAtom);
					} else {
						humanReadable.append("-").append(varAtom.toString()).append(" ");
					}
				} else {
					humanReadable.append("-").append(atom.toString()).append(" ");
				}

			}
		}
		scanner.close();

		return humanReadable.toString();
	}

	/**
	 * Return the string without its last character.
	 *
	 * @param str Given string.
	 * @return A copy of the given string without its last character.
	 */
	public static String removeLastChar(String str) {
		if (str != null && str.length() > 0) {
			str = str.substring(0, str.length() - 1);
		}
		return str;
	}

	/**
	 * Return the string without its last N characters.
	 *
	 * @param str Given string.
	 * @param n   Number of characters to be removed.
	 * @return A copy of the given string without its last character.
	 */
	public static String removeNLastChar(String str, int n) {
		if (str != null && str.length() > 0) {
			str = str.substring(0, str.length() - n);
		}
		return str;
	}

	/**
	 * Method creates a label based on the list of predicates and the logical
	 * operator.
	 *
	 * @param relatedPredicates List of predicates that should be used to create the
	 *                          new label.
	 * @param logicOp           Logical operator that configures the label.
	 * @return String representing a new label made based on the predicates and the
	 *         logical operator.
	 */
	public static String getLabelFromList(SortedSet relatedPredicates, LogicOperation logicOp) {
		StringBuilder abstractLabel = new StringBuilder(logicOp.toStringSign());
		for (TaxonomyPredicate label : relatedPredicates) {
			abstractLabel.append(label.getPredicateLabel()).append(logicOp.toStringSign());
		}

		return abstractLabel.toString();
	}

	/**
	 * Print a warning to the console for the user to see.
	 *
	 * @param message The warning message.
	 * @param params  additional parameters (uses String.format)
	 */
	public static void printWarning(String message, Object... params) {
		log.warn("\u001B[35mWARNING: " + String.format(message, params) + "\u001B[0m");
	}

	/**
	 * Disable System.err temporarily, enable again with {@link #enableErr}.
	 * 
	 */
	public static void disableErr() {
		System.setErr(nullStream);
	}

	/**
	 * Reset System.err to normal.
	 * 
	 */
	public static void enableErr() {
		System.setErr(original);
	}

	/**
	 * Clone the given JSON object
	 * 
	 * @param original - original JSON object
	 * @return copy of the original JSONObject.
	 */
	public static JSONObject clone(JSONObject original) {
		return new JSONObject(original, JSONObject.getNames(original));
	}

	/**
	 * Count the number of lines in a file.
	 * 
	 * @param cnfEncoding - file to count lines
	 * @return number of lines
	 */
	public static int countLines(File cnfEncoding) {
		int lines = 0;
		try (BufferedReader b = new BufferedReader(new FileReader(cnfEncoding))) {
			while (b.readLine() != null) {
				lines++;

			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return lines;
	}

	/**
	 * Visualises in the command line the memory status of the VM at the given step,
	 * if debug mode is on.
	 * 
	 * @param debugMode - true if debug mode is on
	 */
	public static void printMemoryStatus(boolean debugMode) {
		if (!debugMode) {
			return;
		}
		double currMemMB = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 / 1024;
		double totalMemMB = (Runtime.getRuntime().totalMemory()) / 1024 / 1024;
		double oneCharValueMB = 100;
		int currMemChars = (int) Math.ceil(currMemMB / oneCharValueMB);
		int totalMemChars = (int) Math.ceil(totalMemMB / oneCharValueMB);

		StringBuilder memoryStatus = new StringBuilder();
		IntStream.range(0, currMemChars).forEach(step -> memoryStatus.append("#"));
		IntStream.range(currMemChars, totalMemChars).forEach(step -> memoryStatus.append(" "));
		log.info("\n[" + memoryStatus.toString() + "]\t" + totalMemMB + "\tMB \r");

	}

	/**
	 * Get all unique pairs of PredicateLabels within the collection.
	 * 
	 * @param set - Set of PredicateLabel that should be used to create the pairs
	 * @return Set of unique pairs.
	 */
	public static Set> getUniquePairs(Collection set) {
		Set> pairs = new HashSet<>();
		set.stream().forEach(ele1 -> set.stream().filter(ele2 -> ele1.compareTo(ele2) < 0)
				.forEach(ele2 -> pairs.add(new Pair<>(ele1, ele2))));
		return pairs;

	}

	/**
	 * Get unique pairs of elements within 2 collections.
	 * 
	 * @param set1 - Set of elements that should be used to create the first
	 *             elements of the pairs
	 * @param set2 - Set of elements that should be used to create the second
	 *             elements of the pairs
	 * @return Set of unique pairs.
	 */
	public static  Set> getUniquePairs(Collection set1, Collection set2) {
		Set> pairs = new HashSet<>();
		set1.stream().forEach(ele1 -> set2.stream().forEach(ele2 -> pairs.add(new Pair<>(ele1, ele2))));
		return pairs;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy