diff --git a/integraal/integraal-component/src/main/java/fr/boreal/component_builder/AlgorithmParameters.java b/integraal/integraal-component/src/main/java/fr/boreal/component_builder/AlgorithmParameters.java index d547d3027649b030ac9c8f751f795b1e68c3e397..6a309e457e6514c661fe77e34b38fe6f3b9473d0 100644 --- a/integraal/integraal-component/src/main/java/fr/boreal/component_builder/AlgorithmParameters.java +++ b/integraal/integraal-component/src/main/java/fr/boreal/component_builder/AlgorithmParameters.java @@ -1,41 +1,30 @@ package fr.boreal.component_builder; -import java.lang.reflect.Field; -import java.time.Duration; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Optional; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import fr.boreal.component_builder.api.algorithm.IAlgorithmParameters; import fr.boreal.component_builder.externalHaltingConditions.ExternalAlgorithmHaltingConditions; import fr.boreal.component_builder.utils.StringUtils; import fr.boreal.configuration.keywords.InteGraalKeywords; import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms; -import fr.boreal.configuration.keywords.InteGraalKeywords.InternalStorageConfiguration; import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms.Answers; import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms.Images; +import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms.Parameters.Chase.*; import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms.Parameters.Compilation; -import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms.Parameters.Chase.Applier; -import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms.Parameters.Chase.Checker; -import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms.Parameters.Chase.Computer; -import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms.Parameters.Chase.Evaluator; -import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms.Parameters.Chase.Scheduler; -import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms.Parameters.Chase.Namer; -import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms.Parameters.Chase.Transformer; -import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms.Parameters.Explanation.ExplainerVerbosity; -import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms.Parameters.Explanation.ExplainerSolver; -import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms.Parameters.Explanation.GraphOfRuleInstancesComputation; -import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms.Parameters.Explanation.ExplanationSupportType; -import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms.Parameters.Explanation.GraphOfRuleInstancesType; +import fr.boreal.configuration.keywords.InteGraalKeywords.Algorithms.Parameters.Explanation.*; +import fr.boreal.configuration.keywords.InteGraalKeywords.InternalStorageConfiguration; import fr.boreal.configuration.keywords.InteGraalKeywords.InternalStorageConfiguration.DBMSDriverParameters; import fr.boreal.configuration.keywords.InteGraalKeywords.InternalStorageConfiguration.DBType; import fr.boreal.configuration.keywords.InteGraalKeywords.InternalStorageConfiguration.DriverType; import fr.boreal.configuration.keywords.InteGraalKeywords.InternalStorageConfiguration.StorageLayout; import fr.boreal.configuration.parameters.IGParameter; import fr.lirmm.boreal.util.enumerations.EnumUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Field; +import java.time.Duration; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Optional; /** * Default implementation for {@link IAlgorithmParameters}. @@ -49,850 +38,892 @@ import fr.lirmm.boreal.util.enumerations.EnumUtils; */ public class AlgorithmParameters implements IAlgorithmParameters { - /// ////////////////////////////////////// - /// / FIELDS - /// ////////////////////////////////////// - - static final Logger LOG = LoggerFactory.getLogger(AlgorithmParameters.class); - private final boolean parametereSetAtConstruction; - - // Core configuration fields - private final Algorithms algorithm; - protected final String name; - - // Closed parameters from enumeration - // chase - private Scheduler scheduler; - private Checker checker; - private Computer computer; - private Applier applier; - private Namer skolem; - private Evaluator evaluator; // added by Michel - private Transformer transformer; // added by Michel - // TODO check transfer of IntegralParameters to AlgorithmParameters - // storage - private DBType dbtype; - private DriverType driverType; - private StorageLayout storageLayout; - - // query rewriting - private Compilation compilation; - - // Open parameters, with names defined from a parent enumeration - // database - private String DBMSDriverParameters_URL; - private String DBMSDriverParameters_PORT; - private String DBMSDriverParameters_DATABASE_NAME; - private String DBMSDriverParameters_USER_NAME; - private String DBMSDriverParameters_USER_PASSWORD; - private String DBMSDriverParameters_CLEAR_DB; - - // Open parameters, with names not defined from a parent enumeration - private Integer max; - private Integer rank; - private Duration timeout; - - // query answering - private Answers answers; - private Images images; - - // Alternative for setting timeout and rank - private ExternalAlgorithmHaltingConditions externalHaltingConditions; - - private ExplainerVerbosity explainerVerbosity; - private ExplainerSolver explainerSolver; - private GraphOfRuleInstancesComputation graphOfRuleInstancesComputation; - private ExplanationSupportType explanationSupportType; - private GraphOfRuleInstancesType graphOfRuleInstancesType; - private Algorithms.Parameters.Explanation explanation; - ///////////////////////////////////////// - //// CONSTRUCTORS - ///////////////////////////////////////// - - /** - * Constructs a new {@code AlgorithmParameters} instance. - * - * @param name the name of the configuration - * @param algorithmType the algorithm type (e.g., KB_CHASE, OMQA_CHASE) - */ - public AlgorithmParameters(String name, Algorithms algorithmType) { - this.name = name; - this.algorithm = algorithmType; - this.parametereSetAtConstruction = false; - initDefaultValues(); - } - - /** - * Constructs a new {@code AlgorithmParameters} instance and immediately sets - * parameters from the specified {@link IGParameter} object. - * - * @param name the name of the configuration - * @param algorithmType the algorithm type - * @param params an {@code IGParameter} containing parameter metadata - */ - public AlgorithmParameters(String name, Algorithms algorithmType, IGParameter<InteGraalKeywords, ?>... params) { - this.name = name; - this.algorithm = algorithmType; - initDefaultValues(); - this.parametereSetAtConstruction = setParams(params); - } - - ///////////////////////////////////////// - //// OVERRIDDEN / PUBLIC METHODS - ///////////////////////////////////////// - - /** - * Returns the name of the configuration concatenated with the algorithm name. - * - * @return the name of the configuration (e.g., "MyConfig_OMQA_CHASE") - */ - public String getName() { - return this.name + "_" + this.algorithm.toString(); - } - - /** - * Returns the current algorithm type. - * - * @return the current {@link InteGraalKeywords.Algorithms} enum value - */ - public InteGraalKeywords.Algorithms getAlgorithm() { - return algorithm; - } - - @Override - public boolean usesSaturationAlgorithm() { - return algorithm.equals(InteGraalKeywords.Algorithms.KB_CHASE) - || algorithm.equals(InteGraalKeywords.Algorithms.OMQA_CHASE) - || algorithm.equals(InteGraalKeywords.Algorithms.QUERY_ANSWERING_VIA_HYBRID_STRATEGY); - } - - @Override - public boolean usesQueryRewritingAlgorithm() { - return algorithm.equals(InteGraalKeywords.Algorithms.OMQ_REWRITING) - || algorithm.equals(InteGraalKeywords.Algorithms.OMQA_REW); - } - - @Override - public boolean usesQueryAnsweringAlgorithm() { - return algorithm.equals(InteGraalKeywords.Algorithms.QUERY_ANSWERING); - } - - @Override - public boolean usesRuleCompilationAlgorithm() { - return algorithm.equals(InteGraalKeywords.Algorithms.RULE_COMPILATION) || usesQueryRewritingAlgorithm(); - } - - @Override - public boolean usesOMQASaturationAlgorithm() { - return algorithm.equals(InteGraalKeywords.Algorithms.OMQA_CHASE); - } - - @Override - public boolean usesOMQARewritingAlgorithm() { - return algorithm.equals(InteGraalKeywords.Algorithms.OMQA_REW); - } - - @Override - public boolean usesOMQAHybridAlgorithm() { - return algorithm.equals(InteGraalKeywords.Algorithms.QUERY_ANSWERING_VIA_HYBRID_STRATEGY); - } - - @Override - public boolean usesStorage() { - return usesSaturationAlgorithm() || usesQueryAnsweringAlgorithm() || usesOMQASaturationAlgorithm() - || usesOMQARewritingAlgorithm() || usesOMQAHybridAlgorithm(); - } - - @Override - public Optional<Applier> getRuleApplier() { - return Optional.ofNullable(applier); - } - - @Override - public Optional<Scheduler> getScheduler() { - return Optional.ofNullable(scheduler); - } - - @Override - public Optional<Checker> getCriterion() { - return Optional.ofNullable(checker); - } - - @Override - public Optional<Computer> getComputer() { - return Optional.ofNullable(computer); - } - - @Override - public Optional<Namer> getSkolemization() { - return Optional.ofNullable(skolem); - } - - @Override - public Optional<Evaluator> getEvaluator() { - return Optional.ofNullable(evaluator); - } - - @Override - public Optional<Transformer> getTransformer() { - return Optional.ofNullable(transformer); - } - - @Override - public Optional<DBType> getStorageType() { - return Optional.ofNullable(dbtype); - } - - @Override - public Optional<DriverType> getDBDriver() { - return Optional.ofNullable(driverType); - } - - @Override - public Optional<StorageLayout> getDBStrategy() { - return Optional.ofNullable(storageLayout); - } - - @Override - public Optional<Compilation> getCompilation() { - return Optional.ofNullable(compilation); - } - - @Override - public Optional<Integer> getRank() { - return Optional.ofNullable(this.rank); - } - - @Override - public Optional<Integer> getMax() { - return Optional.ofNullable(this.max); - } - - @Override - public Optional<Duration> getTimeout() { - return Optional.ofNullable(this.timeout); - } - - @Override - public Answers getResultType() { - return this.answers; - } - - @Override - public Images getImageType() { - return this.images; - } - - @Override - public void setResultType(Answers type) { - this.answers = type; - } - - @Override - public void setImageType(Images type) { - this.images = type; - } - - @Override - public boolean asksLists() { - return this.answers.equals(Answers.LIST); - } - - @Override - public boolean asksSet() { - return this.answers.equals(Answers.SET); - } - - @Override - public boolean asksCountOnly() { - return this.answers.equals(Answers.COUNT_ONLY); - } - - @Override - public ExternalAlgorithmHaltingConditions getExternalHaltingConditions() { - if (this.externalHaltingConditions == null) { - this.externalHaltingConditions = ExternalAlgorithmHaltingConditions.defaultConditions(); - } - return this.externalHaltingConditions; - } - - @Override - public Optional<Map<DBMSDriverParameters, String>> getDBMSDriverParameters() { - Map<DBMSDriverParameters, String> result = new LinkedHashMap<>(); - - if (DBMSDriverParameters_URL != null) { - result.put(DBMSDriverParameters.URL, DBMSDriverParameters_URL); - } - if (DBMSDriverParameters_PORT != null) { - result.put(DBMSDriverParameters.PORT, DBMSDriverParameters_PORT); - } - if (DBMSDriverParameters_DATABASE_NAME != null) { - result.put(DBMSDriverParameters.DATABASE_NAME, DBMSDriverParameters_DATABASE_NAME); - } - if (DBMSDriverParameters_USER_NAME != null) { - result.put(DBMSDriverParameters.USER_NAME, DBMSDriverParameters_USER_NAME); - } - if (DBMSDriverParameters_USER_PASSWORD != null) { - result.put(DBMSDriverParameters.USER_PASSWORD, DBMSDriverParameters_USER_PASSWORD); - } - if (DBMSDriverParameters_CLEAR_DB != null) { - result.put(DBMSDriverParameters.CLEAR_DB, DBMSDriverParameters_CLEAR_DB); - } - - if (result.isEmpty()) { - return Optional.empty(); - } else { - return Optional.of(result); - } - } - - - /// ////////////////////////////////////// - /// / OVERRIDDEN / PUBLIC SETTER METHODS - /// ////////////////////////////////////// - - @Override - public IAlgorithmParameters setExternalHaltingConditions(ExternalAlgorithmHaltingConditions hc) { - if (parametereSetAtConstruction) { - LOG.error("parameters have been already set ; wrong usage of the method"); - } - this.externalHaltingConditions = hc; - this.rank = externalHaltingConditions.rank(); - this.timeout = externalHaltingConditions.timeout(); - return this; - } - - @Override - public IAlgorithmParameters setMax(Integer max) { - this.max = max; - return this; - } - - @Override - public IAlgorithmParameters setRank(Integer rank) { - this.rank = rank; - return this; - } - - @Override - public IAlgorithmParameters setTimeout(Duration timeout) { - this.timeout = timeout; - return this; - } - - /** - * Sets the DB storage type (e.g., PostgreSQL, H2) by matching the input string - * to an enum constant and then calling {@link #setParameter(Enum)}. - * - * @param storageDBTypeName the name of the storage type (e.g., "H2", - * "POSTGRESQL") - * @return this {@link IAlgorithmParameters} instance for method chaining - */ - public IAlgorithmParameters setStorageType(String storageDBTypeName) { - return setParameter(EnumUtils.findEnumFromString(storageDBTypeName, InternalStorageConfiguration.DBType.class)); - } - - @Override - public IAlgorithmParameters setStorageType(DBType storage) { - return setParameter(storage); - } - - /** - * Sets the database driver type (e.g., "JDBC") by matching the input string to - * an enum constant and then calling {@link #setParameter(Enum)}. - * - * @param storageDriverName the name of the driver type - * @return this {@link IAlgorithmParameters} instance for method chaining - */ - public IAlgorithmParameters setDBDriver(String storageDriverName) { - return setParameter( - EnumUtils.findEnumFromString(storageDriverName, InternalStorageConfiguration.DriverType.class)); - } - - @Override - public IAlgorithmParameters setDBDriver(DriverType storageDriver) { - return setParameter(storageDriver); - } - - /** - * Sets the storage layout strategy (e.g., "DEFAULT") by matching the input - * string to an enum constant and then calling {@link #setParameter(Enum)}. - * - * @param storageStrategyName the name of the storage layout - * @return this {@link IAlgorithmParameters} instance for method chaining - */ - public IAlgorithmParameters setDBStrategy(String storageStrategyName) { - return setParameter( - EnumUtils.findEnumFromString(storageStrategyName, InternalStorageConfiguration.StorageLayout.class)); - } - - @Override - public IAlgorithmParameters setDBStrategy(StorageLayout storageStrategy) { - return setParameter(storageStrategy); - } - - - /** - * Sets the chase rule applier by matching the input string to an enum constant - * and then calling {@link #setParameter(Enum)}. - * - * @param applierName the name of the rule applier - * @return this {@link IAlgorithmParameters} instance for method chaining - */ - public IAlgorithmParameters setRuleApplier(String applierName) { - return setParameter( - EnumUtils.findEnumFromString(applierName, InteGraalKeywords.Algorithms.Parameters.Chase.Applier.class)); - } - - @Override - public IAlgorithmParameters setRuleApplier(Applier applier) { - return setParameter(applier); - } - - /** - * Sets the scheduler by matching the input string to an enum constant and then - * calling {@link #setParameter(Enum)}. - * - * @param scheduler the name of the scheduler - * @return this {@link IAlgorithmParameters} instance for method chaining - */ - public IAlgorithmParameters setScheduler(String scheduler) { - return setParameter( - EnumUtils.findEnumFromString(scheduler, InteGraalKeywords.Algorithms.Parameters.Chase.Scheduler.class)); - } - - @Override - public IAlgorithmParameters setScheduler(Scheduler scheduler) { - return setParameter(scheduler); - } - - /** - * Sets the chase criterion (checker) by matching the input string to an enum - * constant and then calling {@link #setParameter(Enum)}. - * - * @param criterionName the name of the chase checker - * @return this {@link IAlgorithmParameters} instance for method chaining - */ - public IAlgorithmParameters setCriterion(String criterionName) { - return setParameter(EnumUtils.findEnumFromString(criterionName, - InteGraalKeywords.Algorithms.Parameters.Chase.Checker.class)); - } - - @Override - public IAlgorithmParameters setCriterion(Checker criterion) { - return setParameter(criterion); - } - - /** - * Sets the chase computer by matching the input string to an enum constant and - * then calling {@link #setParameter(Enum)}. - * - * @param computerName the name of the chase computer - * @return this {@link IAlgorithmParameters} instance for method chaining - */ - public IAlgorithmParameters setComputer(String computerName) { - return setParameter(EnumUtils.findEnumFromString(computerName, - InteGraalKeywords.Algorithms.Parameters.Chase.Computer.class)); - } - - @Override - public IAlgorithmParameters setComputer(Computer computer) { - return setParameter(computer); - } - - /** - * Sets the chase Skolemization approach by matching the input string to an enum - * constant and then calling {@link #setParameter(Enum)}. - * - * @param skolemizationName the name of the Skolemization approach - * @return this {@link IAlgorithmParameters} instance for method chaining - */ - public IAlgorithmParameters setSkolemization(String skolemizationName) { - return setParameter(EnumUtils.findEnumFromString(skolemizationName, - InteGraalKeywords.Algorithms.Parameters.Chase.Namer.class)); - } - - @Override - public IAlgorithmParameters setSkolemization(Namer skolemization) { - return setParameter(skolemization); - } - - /** - * Sets the chase evaluator by matching the input string to an enum - * constant and then calling {@link #setParameter(Enum)}. - * - * @param evaluatorName the name of the evaluator - * @return this {@link IAlgorithmParameters} instance for method chaining - */ - public IAlgorithmParameters setEvaluator(String evaluatorName) { - return setParameter(EnumUtils.findEnumFromString(evaluatorName, - InteGraalKeywords.Algorithms.Parameters.Chase.Evaluator.class)); - } - - @Override - public IAlgorithmParameters setEvaluator(Evaluator evaluator) { - return setParameter(evaluator); - } - - - /** - * Sets the chase transformer by matching the input string to an enum - * constant and then calling {@link #setParameter(Enum)}. - * - * @param transformerName the name of the transformer - * @return this {@link IAlgorithmParameters} instance for method chaining - */ - public IAlgorithmParameters setTransformer(String transformerName) { - return setParameter(EnumUtils.findEnumFromString(transformerName, - InteGraalKeywords.Algorithms.Parameters.Chase.Transformer.class)); - } - - @Override - public IAlgorithmParameters setTransformer(Transformer transformer) { - return setParameter(transformer); - } - - - /** - * Sets the compilation approach (e.g., "DEFAULT") by matching the input string - * to an enum constant and then calling {@link #setParameter(Enum)}. - * - * @param compilationName the name of the compilation type - * @return this {@link IAlgorithmParameters} instance for method chaining - */ - public IAlgorithmParameters setCompilation(String compilationName) { - return setParameter(EnumUtils.findEnumFromString(compilationName, - InteGraalKeywords.Algorithms.Parameters.Compilation.class)); - } - - @Override - public IAlgorithmParameters setCompilation(Compilation compilation) { - return setParameter(compilation); - } - - /** - * Sets a DBMS driver parameter based on the provided parameter name and value. - * The parameter name is mapped to an enum instance of - * {@link DBMSDriverParameters}, and then the appropriate field in this class is - * updated. - * - * @param paramName the name of the DBMS driver parameter, e.g., "URL" or - * "PORT" - * @param paramValue the value to set for the specified parameter - * @throws IllegalArgumentException if {@code paramName} does not match any - * known {@link DBMSDriverParameters} value - * @see #setDBMSDriverParameters(DBMSDriverParameters, String) - */ - public void setDBMSDriverParameters(String paramName, String paramValue) { - setDBMSDriverParameters(EnumUtils.findEnumFromString(paramName, DBMSDriverParameters.class), paramValue); - } - - @Override - public IAlgorithmParameters setDBMSDriverParameters(DBMSDriverParameters paramName, String value) { - switch (paramName) { - case DATABASE_NAME -> this.DBMSDriverParameters_DATABASE_NAME = value; - case PORT -> this.DBMSDriverParameters_PORT = value; - case URL -> this.DBMSDriverParameters_URL = value; - case USER_NAME -> this.DBMSDriverParameters_USER_NAME = value; - case USER_PASSWORD -> this.DBMSDriverParameters_USER_PASSWORD = value; - case CLEAR_DB -> this.DBMSDriverParameters_CLEAR_DB = value; - default -> throw new IllegalArgumentException("Unexpected parameter: " + paramName); - } - return this; - } - - ///////////////////////////////////////// - //// PRIVATE / HELPER METHODS - ///////////////////////////////////////// - - /** - * Iterates over the provided {@code params}, handling each based on its - * category (enumeration, open parameter from an enumeration, or open - * parameter). - * - * @param params one or more {@link IGParameter} objects that define parameter - * names and values - * @return {@code true} if all parameters were handled successfully; - * {@code false} if an unrecognized parameter was encountered - */ - @SuppressWarnings("unchecked") - private boolean setParams(IGParameter<InteGraalKeywords, ?>... params) { - for (var param : params) { - switch (param.name()) { - // enumeration with closed set of values - case InteGraalKeywords k when k.isEnumeration() -> setParameter((Enum<?>) param.value()); - - // open set of values, but defined within an enumeration (e.g., - // DBConnectionParams) - case InteGraalKeywords k when !k.isEnumeration() && k.getParentEnum().isPresent() -> - setOpenParameterFromEnumeration(k.getParentEnum().get(), param.name().toString(), - param.value().toString()); - - // open set of values (e.g., Rank, Timeout) - case InteGraalKeywords k when !k.isEnumeration() && !k.getParentEnum().isPresent() -> - setOpenParameter(k, param.value()); - - default -> { - LOG.error("Cannot handle parameter " + param); - return false; - } - } - } - return true; - } - - /** - * Sets the value of a parameter based on the provided enum constant. This - * method uses reflection to dynamically identify and set the field within this - * class that corresponds to the enum type of the given constant. The field name - * is expected to match the simple name of the enum's class, with the first - * letter lowercased (following Java naming conventions) - * - * @param enumValue The enum constant to set as the value of the corresponding - * field. The enum's class simple name (lowercased) should - * match the name of the field in this class. - * @throws RuntimeException If no matching field is found for the enum type, or - * if an error occurs while attempting to set the - * field's value. This includes cases where the field - * is not accessible or if the field name does not - * match the expected naming convention. - * @see Field#setAccessible(boolean) - */ - public IAlgorithmParameters setParameter(Enum<?> enumValue) { - LOG.debug("Setting parameter {} for {}", enumValue, this.name); - validateParameter(enumValue); - String fieldName = enumValue.getClass().getSimpleName(); - try { - Field field = null; - for (Field f : this.getClass().getDeclaredFields()) { - if (fieldName.equalsIgnoreCase(f.getName())) { - field = f; - break; - } - } - if (field == null) { - LOG.error("Cannot set parameter {}", enumValue); - throw new RuntimeException( - String.format("[%s::setParameter] Cannot set parameter: %s.", this.getClass(), enumValue)); - } else { - field.setAccessible(true); - field.set(this, enumValue); - } - } catch (IllegalAccessException e) { - LOG.error("Failed to set parameter: {}\n{}", fieldName, e.getMessage()); - throw new RuntimeException( - String.format("[%s::setParameter] Failed to set parameter: %s.", this.getClass(), fieldName), e); - } - return this; - } - - /** - * Sets an open parameter (defined within a known enumeration) by mapping the - * given {@code propertyName} to the appropriate enum constant in - * {@code className}, and assigning the provided {@code value}. - * <p> - * Currently, this is primarily used for {@code DBMSDriverParameters}. - * </p> - * - * @param className the enum's class, e.g., - * {@code DBMSDriverParameters.class} - * @param propertyName the name of the enum constant, e.g., "URL" or "USER_NAME" - * @param value the string value to assign to this parameter - * @return this {@link IAlgorithmParameters} instance for method chaining - * @throws IllegalArgumentException if {@code propertyName} does not match any - * known constant in {@code className} - */ - public IAlgorithmParameters setOpenParameterFromEnumeration(Class<? extends Enum<?>> className, String propertyName, - String value) { - LOG.debug("Setting parameter {} for {} with value {} for {} ", propertyName, className.getSimpleName(), value, - this.name); - - switch (className.getSimpleName().toUpperCase()) { - case "DBMSDRIVERPARAMETERS" -> setDBMSDriverParameters(propertyName, value); - default -> throw new IllegalArgumentException("Unexpected value: " + className); - } - return this; - } - - /** - * Similar to {@link #setOpenParameterFromEnumeration(Class, String, String)}, - * but takes an {@code enumName} instead of the enum {@code className}. This - * method is used to handle open parameters where the parent enumeration is - * already determined. - * - * @param enumName the enumeration constant representing the parameter - * category - * @param propertyName the name of the specific parameter within that category - * @param value the string value to assign to the parameter - * @return this {@link IAlgorithmParameters} instance for method chaining - * @throws IllegalArgumentException if {@code propertyName} does not match any - * recognized constant for the given - * {@code enumName} - */ - public IAlgorithmParameters setOpenParameterFromEnumeration(Enum<?> enumName, String propertyName, String value) { - LOG.debug("Setting parameter {} for {} with value {} for {} ", propertyName, enumName.name(), value, this.name); - - switch (enumName.name().toUpperCase()) { - case "DBMSDRIVERPARAMETERS" -> setDBMSDriverParameters(propertyName, value); - default -> throw new IllegalArgumentException("Unexpected value: " + enumName); - } - return this; - } - - /** - * Sets an open parameter (one that is not tied to a closed enumeration of - * values) by matching its name to one of the fields declared in this class. If - * found, the field is updated with the provided {@code value}. - * - * @param k the keyword representing the parameter name - * @param value the value to set (type {@code Object} because parameters can - * vary) - * @return this {@link IAlgorithmParameters} instance for method chaining - * @throws RuntimeException if the parameter field cannot be found or set - * @see Field#setAccessible(boolean) - */ - public IAlgorithmParameters setOpenParameter(InteGraalKeywords k, Object value) { - LOG.debug("Setting parameter {} with value {} for {}", k, value, this.name); - String fieldName = k.name(); - try { - Field field = null; - for (Field f : this.getClass().getDeclaredFields()) { - if (fieldName.equalsIgnoreCase(f.getName())) { - field = f; - break; - } - } - if (field == null) { - LOG.error("Cannot set parameter {}", k); - throw new RuntimeException( - String.format("[%s::setParameter] Cannot set parameter: %s.", this.getClass(), value)); - } else { - field.setAccessible(true); - field.set(this, value); - } - } catch (IllegalAccessException e) { - LOG.error("Failed to set parameter: {}\n{}", k, e.getMessage()); - throw new RuntimeException( - String.format("[%s::setParameter] Failed to set parameter: %s.", this.getClass(), k), e); - } - return this; - } - - /** - * Validates whether the specified enum value is allowable based on the current - * algorithm's capabilities. For example, chase parameters cannot be used with - * an algorithm that does not support chase. - * - * @param enumValue the enum constant to validate - * @throws IllegalArgumentException if the enum value is incompatible with the - * current algorithm - */ - private void validateParameter(Enum<?> enumValue) { - if (enumValue.getClass().getEnclosingClass() == InteGraalKeywords.Algorithms.Parameters.Chase.class - && !usesSaturationAlgorithm()) { - throw new IllegalArgumentException( - "Chase parameter " + enumValue + " cannot be set for " + getAlgorithm() + " algorithms."); - } - - if (enumValue.getClass().getEnclosingClass() == InteGraalKeywords.Algorithms.Parameters.Compilation.class - && !usesRuleCompilationAlgorithm()) { - throw new IllegalArgumentException( - "Compilation parameter " + enumValue + " cannot be set for " + getAlgorithm() + " algorithms."); - } - - if (enumValue.getClass().getEnclosingClass() == InteGraalKeywords.InternalStorageConfiguration.class - && !usesStorage()) { - throw new IllegalArgumentException( - "Storage parameter " + enumValue + " cannot be set for " + getAlgorithm() + " algorithms."); - } - } - - private void initDefaultValues() { - - this.answers = Answers.SET; - - this.max = 1_000_000; - this.rank = 1_00_00; - this.timeout = Duration.ofHours(1); - } - - ///////////////////////////////////////// - //// toString() - ///////////////////////////////////////// - - /** - * Returns a string representation of this {@code AlgorithmParameters} object, - * which includes key fields and values. - * - * @return a string describing the fields in this class - */ - public String toString() { - return StringUtils.print(this); - } - - @Override - public Optional<Algorithms.Parameters.Explanation> getExplanation() { - return Optional.ofNullable(explanation); - } - - @Override - public IAlgorithmParameters setExplanationCategory(Algorithms.Parameters.Explanation explanationCategory) { - this.explanation =explanationCategory; - return this; - } - - @Override - public Optional<ExplainerSolver> getExplainerSolver() { - return Optional.ofNullable(explainerSolver); - } - - @Override - public IAlgorithmParameters setExplainerSolver(ExplainerSolver solver) { - this.explainerSolver = solver; - return this; - } - - @Override - public Optional<ExplanationSupportType> getExplanationSupportType() { - return Optional.ofNullable(explanationSupportType); - } - - @Override - public IAlgorithmParameters setExplanationSupportType(ExplanationSupportType explanationSupportType) { - this.explanationSupportType = explanationSupportType; - return this; - } - - @Override - public Optional<ExplainerVerbosity> getExplainerVerbosity() { - return Optional.ofNullable(this.explainerVerbosity); - } - - @Override - public IAlgorithmParameters setExplainerVerbosity(ExplainerVerbosity verbosity) { - this.explainerVerbosity = verbosity; - return this; - } - - @Override - public Optional<GraphOfRuleInstancesType> getGraphOfRuleInstancesType() { - return Optional.ofNullable(this.graphOfRuleInstancesType); - } - - @Override - public IAlgorithmParameters setGraphOfRuleInstancesType(GraphOfRuleInstancesType griType) { - this.graphOfRuleInstancesType = griType; - return this; - } - - @Override - public Optional<GraphOfRuleInstancesComputation> getGraphOfRuleInstancesComputation() { - return Optional.ofNullable(this.graphOfRuleInstancesComputation); - } - - @Override - public IAlgorithmParameters setGraphOfRuleInstancesType(GraphOfRuleInstancesComputation griComputation) { - this.graphOfRuleInstancesComputation = griComputation; - return this; - } + /// ////////////////////////////////////// + /// / FIELDS + /// ////////////////////////////////////// + + static final Logger LOG = LoggerFactory.getLogger(AlgorithmParameters.class); + private final boolean parametereSetAtConstruction; + + // Core configuration fields + private final Algorithms algorithm; + protected final String name; + + // Closed parameters from enumeration + // chase + private Scheduler scheduler; + private Checker checker; + private Computer computer; + private Applier applier; + private Namer skolem; + private Evaluator evaluator; // added by Michel + private Transformer transformer; // added by Michel + // TODO check transfer of IntegralParameters to AlgorithmParameters + // storage + private DBType dbtype; + private DriverType driverType; + private StorageLayout storageLayout; + + // query rewriting + private Compilation compilation; + + // Open parameters, with names defined from a parent enumeration + // database + private String DBMSDriverParameters_URL; + private String DBMSDriverParameters_PORT; + private String DBMSDriverParameters_DATABASE_NAME; + private String DBMSDriverParameters_USER_NAME; + private String DBMSDriverParameters_USER_PASSWORD; + private String DBMSDriverParameters_CLEAR_DB; + + // Open parameters, with names not defined from a parent enumeration + private Integer max; + private Integer rank; + private Duration timeout; + + // query answering + private Answers answers; + private Images images; + + // Alternative for setting timeout and rank + private ExternalAlgorithmHaltingConditions externalHaltingConditions; + + private ExplainerVerbosity explainerVerbosity; + private ExplainerSolver explainerSolver; + private GraphOfRuleInstancesComputation graphOfRuleInstancesComputation; + private ExplanationSupportType explanationSupportType; + private GraphOfRuleInstancesType graphOfRuleInstancesType; + private Algorithms.Parameters.Explanation explanation; + private Integer GSATSolverParameters_SMART_SOLVER_TRESHOLD; + private String GSATSolverParameters_MARCO_PATH_TO_EXECUTABLE; + ///////////////////////////////////////// + //// CONSTRUCTORS + ///////////////////////////////////////// + + /** + * Constructs a new {@code AlgorithmParameters} instance. + * + * @param name the name of the configuration + * @param algorithmType the algorithm type (e.g., KB_CHASE, OMQA_CHASE) + */ + public AlgorithmParameters(String name, Algorithms algorithmType) { + this.name = name; + this.algorithm = algorithmType; + this.parametereSetAtConstruction = false; + initDefaultValues(); + } + + /** + * Constructs a new {@code AlgorithmParameters} instance and immediately sets + * parameters from the specified {@link IGParameter} object. + * + * @param name the name of the configuration + * @param algorithmType the algorithm type + * @param params an {@code IGParameter} containing parameter metadata + */ + public AlgorithmParameters(String name, Algorithms algorithmType, IGParameter<InteGraalKeywords, ?>... params) { + this.name = name; + this.algorithm = algorithmType; + initDefaultValues(); + this.parametereSetAtConstruction = setParams(params); + } + + ///////////////////////////////////////// + //// OVERRIDDEN / PUBLIC METHODS + ///////////////////////////////////////// + + /** + * Returns the name of the configuration concatenated with the algorithm name. + * + * @return the name of the configuration (e.g., "MyConfig_OMQA_CHASE") + */ + public String getName() { + return this.name + "_" + this.algorithm.toString(); + } + + /** + * Returns the current algorithm type. + * + * @return the current {@link InteGraalKeywords.Algorithms} enum value + */ + public InteGraalKeywords.Algorithms getAlgorithm() { + return algorithm; + } + + @Override + public boolean usesSaturationAlgorithm() { + return algorithm.equals(InteGraalKeywords.Algorithms.KB_CHASE) + || algorithm.equals(InteGraalKeywords.Algorithms.OMQA_CHASE) + || algorithm.equals(InteGraalKeywords.Algorithms.QUERY_ANSWERING_VIA_HYBRID_STRATEGY); + } + + @Override + public boolean usesQueryRewritingAlgorithm() { + return algorithm.equals(InteGraalKeywords.Algorithms.OMQ_REWRITING) + || algorithm.equals(InteGraalKeywords.Algorithms.OMQA_REW); + } + + @Override + public boolean usesQueryAnsweringAlgorithm() { + return algorithm.equals(InteGraalKeywords.Algorithms.QUERY_ANSWERING); + } + + @Override + public boolean usesRuleCompilationAlgorithm() { + return algorithm.equals(InteGraalKeywords.Algorithms.RULE_COMPILATION) || usesQueryRewritingAlgorithm(); + } + + @Override + public boolean usesOMQASaturationAlgorithm() { + return algorithm.equals(InteGraalKeywords.Algorithms.OMQA_CHASE); + } + + @Override + public boolean usesOMQARewritingAlgorithm() { + return algorithm.equals(InteGraalKeywords.Algorithms.OMQA_REW); + } + + @Override + public boolean usesOMQAHybridAlgorithm() { + return algorithm.equals(InteGraalKeywords.Algorithms.QUERY_ANSWERING_VIA_HYBRID_STRATEGY); + } + + @Override + public boolean usesStorage() { + return usesSaturationAlgorithm() || usesQueryAnsweringAlgorithm() || usesOMQASaturationAlgorithm() + || usesOMQARewritingAlgorithm() || usesOMQAHybridAlgorithm(); + } + + @Override + public Optional<Applier> getRuleApplier() { + return Optional.ofNullable(applier); + } + + @Override + public Optional<Scheduler> getScheduler() { + return Optional.ofNullable(scheduler); + } + + @Override + public Optional<Checker> getCriterion() { + return Optional.ofNullable(checker); + } + + @Override + public Optional<Computer> getComputer() { + return Optional.ofNullable(computer); + } + + @Override + public Optional<Namer> getSkolemization() { + return Optional.ofNullable(skolem); + } + + @Override + public Optional<Evaluator> getEvaluator() { + return Optional.ofNullable(evaluator); + } + + @Override + public Optional<Transformer> getTransformer() { + return Optional.ofNullable(transformer); + } + + @Override + public Optional<DBType> getStorageType() { + return Optional.ofNullable(dbtype); + } + + @Override + public Optional<DriverType> getDBDriver() { + return Optional.ofNullable(driverType); + } + + @Override + public Optional<StorageLayout> getDBStrategy() { + return Optional.ofNullable(storageLayout); + } + + @Override + public Optional<Compilation> getCompilation() { + return Optional.ofNullable(compilation); + } + + @Override + public Optional<Integer> getRank() { + return Optional.ofNullable(this.rank); + } + + @Override + public Optional<Integer> getMax() { + return Optional.ofNullable(this.max); + } + + @Override + public Optional<Duration> getTimeout() { + return Optional.ofNullable(this.timeout); + } + + @Override + public Answers getResultType() { + return this.answers; + } + + @Override + public Images getImageType() { + return this.images; + } + + @Override + public void setResultType(Answers type) { + this.answers = type; + } + + @Override + public void setImageType(Images type) { + this.images = type; + } + + @Override + public boolean asksLists() { + return this.answers.equals(Answers.LIST); + } + + @Override + public boolean asksSet() { + return this.answers.equals(Answers.SET); + } + + @Override + public boolean asksCountOnly() { + return this.answers.equals(Answers.COUNT_ONLY); + } + + @Override + public ExternalAlgorithmHaltingConditions getExternalHaltingConditions() { + if (this.externalHaltingConditions == null) { + this.externalHaltingConditions = ExternalAlgorithmHaltingConditions.defaultConditions(); + } + return this.externalHaltingConditions; + } + + @Override + public Optional<Map<DBMSDriverParameters, String>> getDBMSDriverParameters() { + Map<DBMSDriverParameters, String> result = new LinkedHashMap<>(); + + if (DBMSDriverParameters_URL != null) { + result.put(DBMSDriverParameters.URL, DBMSDriverParameters_URL); + } + if (DBMSDriverParameters_PORT != null) { + result.put(DBMSDriverParameters.PORT, DBMSDriverParameters_PORT); + } + if (DBMSDriverParameters_DATABASE_NAME != null) { + result.put(DBMSDriverParameters.DATABASE_NAME, DBMSDriverParameters_DATABASE_NAME); + } + if (DBMSDriverParameters_USER_NAME != null) { + result.put(DBMSDriverParameters.USER_NAME, DBMSDriverParameters_USER_NAME); + } + if (DBMSDriverParameters_USER_PASSWORD != null) { + result.put(DBMSDriverParameters.USER_PASSWORD, DBMSDriverParameters_USER_PASSWORD); + } + if (DBMSDriverParameters_CLEAR_DB != null) { + result.put(DBMSDriverParameters.CLEAR_DB, DBMSDriverParameters_CLEAR_DB); + } + + if (result.isEmpty()) { + return Optional.empty(); + } else { + return Optional.of(result); + } + } + + + /// ////////////////////////////////////// + /// / OVERRIDDEN / PUBLIC SETTER METHODS + /// ////////////////////////////////////// + + @Override + public IAlgorithmParameters setExternalHaltingConditions(ExternalAlgorithmHaltingConditions hc) { + if (parametereSetAtConstruction) { + LOG.error("parameters have been already set ; wrong usage of the method"); + } + this.externalHaltingConditions = hc; + this.rank = externalHaltingConditions.rank(); + this.timeout = externalHaltingConditions.timeout(); + return this; + } + + @Override + public IAlgorithmParameters setMax(Integer max) { + this.max = max; + return this; + } + + @Override + public IAlgorithmParameters setRank(Integer rank) { + this.rank = rank; + return this; + } + + @Override + public IAlgorithmParameters setTimeout(Duration timeout) { + this.timeout = timeout; + return this; + } + + /** + * Sets the DB storage type (e.g., PostgreSQL, H2) by matching the input string + * to an enum constant and then calling {@link #setParameter(Enum)}. + * + * @param storageDBTypeName the name of the storage type (e.g., "H2", + * "POSTGRESQL") + * @return this {@link IAlgorithmParameters} instance for method chaining + */ + public IAlgorithmParameters setStorageType(String storageDBTypeName) { + return setParameter(EnumUtils.findEnumFromString(storageDBTypeName, InternalStorageConfiguration.DBType.class)); + } + + @Override + public IAlgorithmParameters setStorageType(DBType storage) { + return setParameter(storage); + } + + /** + * Sets the database driver type (e.g., "JDBC") by matching the input string to + * an enum constant and then calling {@link #setParameter(Enum)}. + * + * @param storageDriverName the name of the driver type + * @return this {@link IAlgorithmParameters} instance for method chaining + */ + public IAlgorithmParameters setDBDriver(String storageDriverName) { + return setParameter( + EnumUtils.findEnumFromString(storageDriverName, InternalStorageConfiguration.DriverType.class)); + } + + @Override + public IAlgorithmParameters setDBDriver(DriverType storageDriver) { + return setParameter(storageDriver); + } + + /** + * Sets the storage layout strategy (e.g., "DEFAULT") by matching the input + * string to an enum constant and then calling {@link #setParameter(Enum)}. + * + * @param storageStrategyName the name of the storage layout + * @return this {@link IAlgorithmParameters} instance for method chaining + */ + public IAlgorithmParameters setDBStrategy(String storageStrategyName) { + return setParameter( + EnumUtils.findEnumFromString(storageStrategyName, InternalStorageConfiguration.StorageLayout.class)); + } + + @Override + public IAlgorithmParameters setDBStrategy(StorageLayout storageStrategy) { + return setParameter(storageStrategy); + } + + + /** + * Sets the chase rule applier by matching the input string to an enum constant + * and then calling {@link #setParameter(Enum)}. + * + * @param applierName the name of the rule applier + * @return this {@link IAlgorithmParameters} instance for method chaining + */ + public IAlgorithmParameters setRuleApplier(String applierName) { + return setParameter( + EnumUtils.findEnumFromString(applierName, InteGraalKeywords.Algorithms.Parameters.Chase.Applier.class)); + } + + @Override + public IAlgorithmParameters setRuleApplier(Applier applier) { + return setParameter(applier); + } + + /** + * Sets the scheduler by matching the input string to an enum constant and then + * calling {@link #setParameter(Enum)}. + * + * @param scheduler the name of the scheduler + * @return this {@link IAlgorithmParameters} instance for method chaining + */ + public IAlgorithmParameters setScheduler(String scheduler) { + return setParameter( + EnumUtils.findEnumFromString(scheduler, InteGraalKeywords.Algorithms.Parameters.Chase.Scheduler.class)); + } + + @Override + public IAlgorithmParameters setScheduler(Scheduler scheduler) { + return setParameter(scheduler); + } + + /** + * Sets the chase criterion (checker) by matching the input string to an enum + * constant and then calling {@link #setParameter(Enum)}. + * + * @param criterionName the name of the chase checker + * @return this {@link IAlgorithmParameters} instance for method chaining + */ + public IAlgorithmParameters setCriterion(String criterionName) { + return setParameter(EnumUtils.findEnumFromString(criterionName, + InteGraalKeywords.Algorithms.Parameters.Chase.Checker.class)); + } + + @Override + public IAlgorithmParameters setCriterion(Checker criterion) { + return setParameter(criterion); + } + + /** + * Sets the chase computer by matching the input string to an enum constant and + * then calling {@link #setParameter(Enum)}. + * + * @param computerName the name of the chase computer + * @return this {@link IAlgorithmParameters} instance for method chaining + */ + public IAlgorithmParameters setComputer(String computerName) { + return setParameter(EnumUtils.findEnumFromString(computerName, + InteGraalKeywords.Algorithms.Parameters.Chase.Computer.class)); + } + + @Override + public IAlgorithmParameters setComputer(Computer computer) { + return setParameter(computer); + } + + /** + * Sets the chase Skolemization approach by matching the input string to an enum + * constant and then calling {@link #setParameter(Enum)}. + * + * @param skolemizationName the name of the Skolemization approach + * @return this {@link IAlgorithmParameters} instance for method chaining + */ + public IAlgorithmParameters setSkolemization(String skolemizationName) { + return setParameter(EnumUtils.findEnumFromString(skolemizationName, + InteGraalKeywords.Algorithms.Parameters.Chase.Namer.class)); + } + + @Override + public IAlgorithmParameters setSkolemization(Namer skolemization) { + return setParameter(skolemization); + } + + /** + * Sets the chase evaluator by matching the input string to an enum + * constant and then calling {@link #setParameter(Enum)}. + * + * @param evaluatorName the name of the evaluator + * @return this {@link IAlgorithmParameters} instance for method chaining + */ + public IAlgorithmParameters setEvaluator(String evaluatorName) { + return setParameter(EnumUtils.findEnumFromString(evaluatorName, + InteGraalKeywords.Algorithms.Parameters.Chase.Evaluator.class)); + } + + @Override + public IAlgorithmParameters setEvaluator(Evaluator evaluator) { + return setParameter(evaluator); + } + + + /** + * Sets the chase transformer by matching the input string to an enum + * constant and then calling {@link #setParameter(Enum)}. + * + * @param transformerName the name of the transformer + * @return this {@link IAlgorithmParameters} instance for method chaining + */ + public IAlgorithmParameters setTransformer(String transformerName) { + return setParameter(EnumUtils.findEnumFromString(transformerName, + InteGraalKeywords.Algorithms.Parameters.Chase.Transformer.class)); + } + + @Override + public IAlgorithmParameters setTransformer(Transformer transformer) { + return setParameter(transformer); + } + + + /** + * Sets the compilation approach (e.g., "DEFAULT") by matching the input string + * to an enum constant and then calling {@link #setParameter(Enum)}. + * + * @param compilationName the name of the compilation type + * @return this {@link IAlgorithmParameters} instance for method chaining + */ + public IAlgorithmParameters setCompilation(String compilationName) { + return setParameter(EnumUtils.findEnumFromString(compilationName, + InteGraalKeywords.Algorithms.Parameters.Compilation.class)); + } + + @Override + public IAlgorithmParameters setCompilation(Compilation compilation) { + return setParameter(compilation); + } + + /** + * Sets a DBMS driver parameter based on the provided parameter name and value. + * The parameter name is mapped to an enum instance of + * {@link DBMSDriverParameters}, and then the appropriate field in this class is + * updated. + * + * @param paramName the name of the DBMS driver parameter, e.g., "URL" or + * "PORT" + * @param paramValue the value to set for the specified parameter + * @throws IllegalArgumentException if {@code paramName} does not match any + * known {@link DBMSDriverParameters} value + * @see #setDBMSDriverParameters(DBMSDriverParameters, String) + */ + public void setDBMSDriverParameters(String paramName, String paramValue) { + setDBMSDriverParameters(EnumUtils.findEnumFromString(paramName, DBMSDriverParameters.class), paramValue); + } + + public void setGSATSolverParameters(String paramName, String paramValue) { + setGSATSolverParameters(EnumUtils.findEnumFromString(paramName, GSATSolverParameters.class), paramValue); + } + + + @Override + public IAlgorithmParameters setDBMSDriverParameters(DBMSDriverParameters paramName, String value) { + switch (paramName) { + case DATABASE_NAME -> this.DBMSDriverParameters_DATABASE_NAME = value; + case PORT -> this.DBMSDriverParameters_PORT = value; + case URL -> this.DBMSDriverParameters_URL = value; + case USER_NAME -> this.DBMSDriverParameters_USER_NAME = value; + case USER_PASSWORD -> this.DBMSDriverParameters_USER_PASSWORD = value; + case CLEAR_DB -> this.DBMSDriverParameters_CLEAR_DB = value; + default -> throw new IllegalArgumentException("Unexpected parameter: " + paramName); + } + return this; + } + + + @Override + public IAlgorithmParameters setGSATSolverParameters(GSATSolverParameters paramName, String value) { + switch (paramName) { + case SMART_SOLVER_TRESHOLD -> this.GSATSolverParameters_SMART_SOLVER_TRESHOLD = Integer.parseInt(value); + case MARCO_PATH_TO_EXECUTABLE -> this.GSATSolverParameters_MARCO_PATH_TO_EXECUTABLE = value; + default -> throw new IllegalArgumentException("Unexpected parameter: " + paramName); + } + return this; + } + + @Override + public Optional<String> getMARCOPathToExecutable() { + return Optional.ofNullable(this.GSATSolverParameters_MARCO_PATH_TO_EXECUTABLE); + } + + @Override + public IAlgorithmParameters setMARCOPathToExecutable(String pathtoExecutable) { + this.GSATSolverParameters_MARCO_PATH_TO_EXECUTABLE = pathtoExecutable; + return this; + } + + ///////////////////////////////////////// + //// PRIVATE / HELPER METHODS + ///////////////////////////////////////// + + /** + * Iterates over the provided {@code params}, handling each based on its + * category (enumeration, open parameter from an enumeration, or open + * parameter). + * + * @param params one or more {@link IGParameter} objects that define parameter + * names and values + * @return {@code true} if all parameters were handled successfully; + * {@code false} if an unrecognized parameter was encountered + */ + @SuppressWarnings("unchecked") + private boolean setParams(IGParameter<InteGraalKeywords, ?>... params) { + for (var param : params) { + switch (param.name()) { + // enumeration with closed set of values + case InteGraalKeywords k when k.isEnumeration() -> setParameter((Enum<?>) param.value()); + + // open set of values, but defined within an enumeration (e.g., + // DBConnectionParams) + case InteGraalKeywords k when !k.isEnumeration() && k.getParentEnum().isPresent() -> + setOpenParameterFromEnumeration(k.getParentEnum().get(), param.name().toString(), + param.value().toString()); + + // open set of values (e.g., Rank, Timeout) + case InteGraalKeywords k when !k.isEnumeration() && !k.getParentEnum().isPresent() -> + setOpenParameter(k, param.value()); + + default -> { + LOG.error("Cannot handle parameter " + param); + return false; + } + } + } + return true; + } + + /** + * Sets the value of a parameter based on the provided enum constant. This + * method uses reflection to dynamically identify and set the field within this + * class that corresponds to the enum type of the given constant. The field name + * is expected to match the simple name of the enum's class, with the first + * letter lowercased (following Java naming conventions) + * + * @param enumValue The enum constant to set as the value of the corresponding + * field. The enum's class simple name (lowercased) should + * match the name of the field in this class. + * @throws RuntimeException If no matching field is found for the enum type, or + * if an error occurs while attempting to set the + * field's value. This includes cases where the field + * is not accessible or if the field name does not + * match the expected naming convention. + * @see Field#setAccessible(boolean) + */ + public IAlgorithmParameters setParameter(Enum<?> enumValue) { + LOG.debug("Setting parameter {} for {}", enumValue, this.name); + validateParameter(enumValue); + String fieldName = enumValue.getClass().getSimpleName(); + try { + Field field = null; + for (Field f : this.getClass().getDeclaredFields()) { + if (fieldName.equalsIgnoreCase(f.getName())) { + field = f; + break; + } + } + if (field == null) { + LOG.error("Cannot set parameter {}", enumValue); + throw new RuntimeException( + String.format("[%s::setParameter] Cannot set parameter: %s.", this.getClass(), enumValue)); + } else { + field.setAccessible(true); + field.set(this, enumValue); + } + } catch (IllegalAccessException e) { + LOG.error("Failed to set parameter: {}\n{}", fieldName, e.getMessage()); + throw new RuntimeException( + String.format("[%s::setParameter] Failed to set parameter: %s.", this.getClass(), fieldName), e); + } + return this; + } + + /** + * Sets an open parameter (defined within a known enumeration) by mapping the + * given {@code propertyName} to the appropriate enum constant in + * {@code className}, and assigning the provided {@code value}. + * <p> + * Currently, this is primarily used for {@code DBMSDriverParameters}. + * </p> + * + * @param className the enum's class, e.g., + * {@code DBMSDriverParameters.class} + * @param propertyName the name of the enum constant, e.g., "URL" or "USER_NAME" + * @param value the string value to assign to this parameter + * @return this {@link IAlgorithmParameters} instance for method chaining + * @throws IllegalArgumentException if {@code propertyName} does not match any + * known constant in {@code className} + */ + public IAlgorithmParameters setOpenParameterFromEnumeration(Class<? extends Enum<?>> className, String propertyName, + String value) { + LOG.debug("Setting parameter {} for {} with value {} for {} ", propertyName, className.getSimpleName(), value, + this.name); + + switch (className.getSimpleName().toUpperCase()) { + case "DBMSDRIVERPARAMETERS" -> setDBMSDriverParameters(propertyName, value); + case "GSATSOLVERPARAMETERS" -> setGSATSolverParameters(propertyName, value); + default -> throw new IllegalArgumentException("Unexpected value: " + className); + } + return this; + } + + /** + * Similar to {@link #setOpenParameterFromEnumeration(Class, String, String)}, + * but takes an {@code enumName} instead of the enum {@code className}. This + * method is used to handle open parameters where the parent enumeration is + * already determined. + * + * @param enumName the enumeration constant representing the parameter + * category + * @param propertyName the name of the specific parameter within that category + * @param value the string value to assign to the parameter + * @return this {@link IAlgorithmParameters} instance for method chaining + * @throws IllegalArgumentException if {@code propertyName} does not match any + * recognized constant for the given + * {@code enumName} + */ + public IAlgorithmParameters setOpenParameterFromEnumeration(Enum<?> enumName, String propertyName, String value) { + LOG.debug("Setting parameter {} for {} with value {} for {} ", propertyName, enumName.name(), value, this.name); + + switch (enumName.name().toUpperCase()) { + case "DBMSDRIVERPARAMETERS" -> setDBMSDriverParameters(propertyName, value); + default -> throw new IllegalArgumentException("Unexpected value: " + enumName); + } + return this; + } + + /** + * Sets an open parameter (one that is not tied to a closed enumeration of + * values) by matching its name to one of the fields declared in this class. If + * found, the field is updated with the provided {@code value}. + * + * @param k the keyword representing the parameter name + * @param value the value to set (type {@code Object} because parameters can + * vary) + * @return this {@link IAlgorithmParameters} instance for method chaining + * @throws RuntimeException if the parameter field cannot be found or set + * @see Field#setAccessible(boolean) + */ + public IAlgorithmParameters setOpenParameter(InteGraalKeywords k, Object value) { + LOG.debug("Setting parameter {} with value {} for {}", k, value, this.name); + String fieldName = k.name(); + try { + Field field = null; + for (Field f : this.getClass().getDeclaredFields()) { + if (fieldName.equalsIgnoreCase(f.getName())) { + field = f; + break; + } + } + if (field == null) { + LOG.error("Cannot set parameter {}", k); + throw new RuntimeException( + String.format("[%s::setParameter] Cannot set parameter: %s.", this.getClass(), value)); + } else { + field.setAccessible(true); + field.set(this, value); + } + } catch (IllegalAccessException e) { + LOG.error("Failed to set parameter: {}\n{}", k, e.getMessage()); + throw new RuntimeException( + String.format("[%s::setParameter] Failed to set parameter: %s.", this.getClass(), k), e); + } + return this; + } + + /** + * Validates whether the specified enum value is allowable based on the current + * algorithm's capabilities. For example, chase parameters cannot be used with + * an algorithm that does not support chase. + * + * @param enumValue the enum constant to validate + * @throws IllegalArgumentException if the enum value is incompatible with the + * current algorithm + */ + private void validateParameter(Enum<?> enumValue) { + if (enumValue.getClass().getEnclosingClass() == InteGraalKeywords.Algorithms.Parameters.Chase.class + && !usesSaturationAlgorithm()) { + throw new IllegalArgumentException( + "Chase parameter " + enumValue + " cannot be set for " + getAlgorithm() + " algorithms."); + } + + if (enumValue.getClass().getEnclosingClass() == InteGraalKeywords.Algorithms.Parameters.Compilation.class + && !usesRuleCompilationAlgorithm()) { + throw new IllegalArgumentException( + "Compilation parameter " + enumValue + " cannot be set for " + getAlgorithm() + " algorithms."); + } + + if (enumValue.getClass().getEnclosingClass() == InteGraalKeywords.InternalStorageConfiguration.class + && !usesStorage()) { + throw new IllegalArgumentException( + "Storage parameter " + enumValue + " cannot be set for " + getAlgorithm() + " algorithms."); + } + } + + private void initDefaultValues() { + + this.answers = Answers.SET; + + this.max = 1_000_000; + this.rank = 1_00_00; + this.timeout = Duration.ofHours(1); + } + + ///////////////////////////////////////// + //// toString() + ///////////////////////////////////////// + + /** + * Returns a string representation of this {@code AlgorithmParameters} object, + * which includes key fields and values. + * + * @return a string describing the fields in this class + */ + public String toString() { + return StringUtils.print(this); + } + + @Override + public Optional<Algorithms.Parameters.Explanation> getExplanation() { + return Optional.ofNullable(explanation); + } + + @Override + public IAlgorithmParameters setExplanationCategory(Algorithms.Parameters.Explanation explanationCategory) { + this.explanation = explanationCategory; + return this; + } + + @Override + public Optional<ExplainerSolver> getExplainerSolver() { + return Optional.ofNullable(explainerSolver); + } + + @Override + public IAlgorithmParameters setExplainerSolver(ExplainerSolver solver) { + this.explainerSolver = solver; + return this; + } + + @Override + public Optional<ExplanationSupportType> getExplanationSupportType() { + return Optional.ofNullable(explanationSupportType); + } + + @Override + public IAlgorithmParameters setExplanationSupportType(ExplanationSupportType explanationSupportType) { + this.explanationSupportType = explanationSupportType; + return this; + } + + @Override + public Optional<ExplainerVerbosity> getExplainerVerbosity() { + return Optional.ofNullable(this.explainerVerbosity); + } + + @Override + public IAlgorithmParameters setExplainerVerbosity(ExplainerVerbosity verbosity) { + this.explainerVerbosity = verbosity; + return this; + } + + @Override + public Optional<GraphOfRuleInstancesType> getGraphOfRuleInstancesType() { + return Optional.ofNullable(this.graphOfRuleInstancesType); + } + + @Override + public IAlgorithmParameters setGraphOfRuleInstancesType(GraphOfRuleInstancesType griType) { + this.graphOfRuleInstancesType = griType; + return this; + } + + @Override + public Optional<GraphOfRuleInstancesComputation> getGraphOfRuleInstancesComputation() { + return Optional.ofNullable(this.graphOfRuleInstancesComputation); + } + + @Override + public IAlgorithmParameters setGraphOfRuleInstancesType(GraphOfRuleInstancesComputation griComputation) { + this.graphOfRuleInstancesComputation = griComputation; + return this; + } + + @Override + public Optional<Integer> getGMUSSolverTreshold() { + return Optional.ofNullable(GSATSolverParameters_SMART_SOLVER_TRESHOLD); + } + + @Override + public IAlgorithmParameters setGMUSSolverTreshold(int treshold) { + this.GSATSolverParameters_SMART_SOLVER_TRESHOLD = treshold; + return this; + } + } diff --git a/integraal/integraal-component/src/main/java/fr/boreal/component_builder/api/algorithm/IExplanationParameters.java b/integraal/integraal-component/src/main/java/fr/boreal/component_builder/api/algorithm/IExplanationParameters.java index a7357725650947025963ec59a0ae4fe1684c7b32..ed2e0e0f99c6805cf69957756656da24fc31d279 100644 --- a/integraal/integraal-component/src/main/java/fr/boreal/component_builder/api/algorithm/IExplanationParameters.java +++ b/integraal/integraal-component/src/main/java/fr/boreal/component_builder/api/algorithm/IExplanationParameters.java @@ -52,4 +52,20 @@ interface IExplanationParameters { IAlgorithmParameters setGraphOfRuleInstancesType(InteGraalKeywords.Algorithms.Parameters.Explanation.GraphOfRuleInstancesComputation griComputation); + /* + * GMUS Smart Solver Treshold + */ + Optional<Integer> getGMUSSolverTreshold(); + + IAlgorithmParameters setGMUSSolverTreshold(int treshold); + + /* + * GMUS MARCO Path to Executable + */ + Optional<String> getMARCOPathToExecutable(); + + IAlgorithmParameters setMARCOPathToExecutable(String pathToExecutable); + + public IAlgorithmParameters setGSATSolverParameters(InteGraalKeywords.Algorithms.Parameters.Explanation.GSATSolverParameters paramName, String value) ; + } \ No newline at end of file diff --git a/integraal/integraal-configuration/src/main/java/fr/boreal/configuration/keywords/InteGraalKeywords.java b/integraal/integraal-configuration/src/main/java/fr/boreal/configuration/keywords/InteGraalKeywords.java index 430866010c1f17a0985168e31c782d328860dd67..7e57edfa643bfb4ee9b2f33e91e964931ede0422 100644 --- a/integraal/integraal-configuration/src/main/java/fr/boreal/configuration/keywords/InteGraalKeywords.java +++ b/integraal/integraal-configuration/src/main/java/fr/boreal/configuration/keywords/InteGraalKeywords.java @@ -94,8 +94,9 @@ public enum InteGraalKeywords { EXPLAINER_SOLVER(Algorithms.Parameters.Explanation.ExplainerSolver.class), EXPLAINER_GRI_COMPUTATION(Algorithms.Parameters.Explanation.GraphOfRuleInstancesComputation.class), EXPLAINER_GRI_TYPE(Algorithms.Parameters.Explanation.GraphOfRuleInstancesType.class), - EXPLANATION_SUPPORT_TYPE(Algorithms.Parameters.Explanation.ExplanationSupportType.class); - + EXPLANATION_SUPPORT_TYPE(Algorithms.Parameters.Explanation.ExplanationSupportType.class), + EXPLANATION_GMUS_SOLVER_TREHSOLD(Integer.class), + EXPLANATION_MARCO_PATH_EXECUTBLE(String.class); // TODO Les paramètres peuvent-ils être partagés par les différents services ? // Comment indiquer les valeurs autorisés d'un paramètre (cf. code ci-après) ? @@ -609,7 +610,19 @@ public enum InteGraalKeywords { */ SMART_GSAT_SOLVER } - + + public enum GSATSolverParameters { + /** + * Threshold. Above use SAT4J. Below use MARCO + */ + SMART_SOLVER_TRESHOLD, + /** + * Path to marco.py in the sysmte + */ + MARCO_PATH_TO_EXECUTABLE + } + + public enum GraphOfRuleInstancesComputation { /** * Uses an explainer that will compute the whole GRI first diff --git a/integraal/integraal-configuration/src/main/java/fr/boreal/configuration/parameters/IGParameterValueExtractor.java b/integraal/integraal-configuration/src/main/java/fr/boreal/configuration/parameters/IGParameterValueExtractor.java index 494542eca00e05c9805708f35eeb7d5144c026ac..c2fcb4fcc0e1765de733c69ae3436bfc6e9ec698 100644 --- a/integraal/integraal-configuration/src/main/java/fr/boreal/configuration/parameters/IGParameterValueExtractor.java +++ b/integraal/integraal-configuration/src/main/java/fr/boreal/configuration/parameters/IGParameterValueExtractor.java @@ -94,4 +94,8 @@ public class IGParameterValueExtractor { return (Algorithms.Parameters.Explanation) search(params, InteGraalKeywords.EXPLANATION); } + public static Algorithms.Parameters.Explanation getGMUSSolverTreshold(IGParameter<InteGraalKeywords, ?>... params) { + return (Algorithms.Parameters.Explanation) search(params, InteGraalKeywords.EXPLANATION_GMUS_SOLVER_TREHSOLD); + } + } diff --git a/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/api/builder/AtomicQueryExplainerBuilder.java b/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/api/builder/AtomicQueryExplainerBuilder.java index 98b2b1c73c1bb6916da3ef7a74c01f49d36eaf64..daedba2603efe05871f9b2e30db47b3a7dc5f638 100644 --- a/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/api/builder/AtomicQueryExplainerBuilder.java +++ b/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/api/builder/AtomicQueryExplainerBuilder.java @@ -49,12 +49,15 @@ public final class AtomicQueryExplainerBuilder { private GraphOfRuleInstancesComputation griComputationParam = INCREMENTAL_GRI; private GraphOfRuleInstancesType griTypeParam = KB_GRI; private ExplanationSupportType supportTypeParam = KB_SUPPORT; + private Integer solverTreshold; + private String pathToMARCOExecutable; // instances private Solver solverInstance; private KnowledgeBase kbInstance; private boolean externallySetSolver = false; + /* -------------------------------------------------------------------------------------- */ public AtomicQueryExplainerBuilder apply(KnowledgeBase kb, Collection<IGParameter<InteGraalKeywords, ?>> params) { @@ -69,17 +72,20 @@ public final class AtomicQueryExplainerBuilder { this.griComputationParam = (GraphOfRuleInstancesComputation) p.value(); case EXPLAINER_GRI_TYPE -> this.griTypeParam = (GraphOfRuleInstancesType) p.value(); case EXPLANATION_SUPPORT_TYPE -> this.supportTypeParam = (ExplanationSupportType) p.value(); + case EXPLANATION_GMUS_SOLVER_TREHSOLD -> this.solverTreshold = (Integer) p.value(); + case EXPLANATION_MARCO_PATH_EXECUTBLE -> this.pathToMARCOExecutable = (String) p.value(); default -> { /* ignored – may belong to another component */} } } return this; } - public void withSolver(Solver solver){ + public void withSolver(Solver solver) { Objects.requireNonNull(solver, "cannot use this method with a null solver"); this.solverInstance = solver; - this.externallySetSolver=true; + this.externallySetSolver = true; } + /** * Convenience one‑shot creation */ @@ -114,14 +120,30 @@ public final class AtomicQueryExplainerBuilder { private void buildSolver() { - if(externallySetSolver){ - return; + if (externallySetSolver) { + return; } this.solverInstance = switch (this.solverParam) { - case MARCO -> new MARCOGMUSSolver(); + case MARCO -> { + if (this.pathToMARCOExecutable != null) { + yield new MARCOGMUSSolver(this.pathToMARCOExecutable); + } else { + yield new MARCOGMUSSolver(); + } + } case SAT4J -> new Sat4JSolver(); - case SMART_GSAT_SOLVER -> new HybridSAT4JMARCOSolver(); + case SMART_GSAT_SOLVER -> { + if (this.solverTreshold != null && this.solverTreshold > 0) { + if (this.pathToMARCOExecutable != null) { + yield new HybridSAT4JMARCOSolver(this.solverTreshold, this.pathToMARCOExecutable); + } else { + yield new HybridSAT4JMARCOSolver(this.solverTreshold); + } + } else { + yield new HybridSAT4JMARCOSolver(); + } + } }; } diff --git a/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/configuration/PathFinder.java b/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/configuration/PathFinder.java index 228732ea7b88d264d610d87b39731c9b2640d238..ed6ba002754967366b3628e2093a1722bd49d4cf 100644 --- a/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/configuration/PathFinder.java +++ b/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/configuration/PathFinder.java @@ -15,4 +15,14 @@ public class PathFinder { } } + + public static String ensureFilePath(String... paths) { + for (String p : paths) { + if (p != null && new File(p).exists()) { + return p; + } + } + throw new IllegalStateException( + "None of the provided paths exists: " + String.join(", ", paths)); + } } diff --git a/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/solving_enumerating/hybrid/HybridSAT4JMARCOSolver.java b/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/solving_enumerating/hybrid/HybridSAT4JMARCOSolver.java index 8bc6c823970a577d060746868409dc6e086f8dd0..cdea4a815575c5d20d753d629cac7668f027e924 100644 --- a/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/solving_enumerating/hybrid/HybridSAT4JMARCOSolver.java +++ b/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/solving_enumerating/hybrid/HybridSAT4JMARCOSolver.java @@ -13,18 +13,28 @@ import java.util.Set; public class HybridSAT4JMARCOSolver implements Solver { - private Sat4JSolver sat4JSolver = new Sat4JSolver(); + private final Sat4JSolver sat4JSolver; - private MARCOGMUSSolver marcoSolver = new MARCOGMUSSolver(); + private final MARCOGMUSSolver marcoSolver; private final int TRESHOLD; public HybridSAT4JMARCOSolver() { this.TRESHOLD = 10; + this.sat4JSolver = new Sat4JSolver(); + this.marcoSolver = new MARCOGMUSSolver(); } public HybridSAT4JMARCOSolver(int treshold) { this.TRESHOLD = treshold; + this.sat4JSolver = new Sat4JSolver(); + this.marcoSolver = new MARCOGMUSSolver(); + } + + public HybridSAT4JMARCOSolver(int treshold, String marcoPathToExecutable) { + this.TRESHOLD = treshold; + this.sat4JSolver = new Sat4JSolver(); + this.marcoSolver = new MARCOGMUSSolver(marcoPathToExecutable); } public HybridSolvingResultDecoded solveAndDecode(GSATEncodingResult_GRI encoding) { @@ -49,7 +59,7 @@ public class HybridSAT4JMARCOSolver implements Solver { public HybridSolvingResult solve(GSATEncodingResult_GRI encoding) { - if (encoding.clauses().size() > TRESHOLD) { + if (encoding.clauses().size() < TRESHOLD) { List<List<List<Integer>>> sat4JGMUSes = sat4JSolver.enumerateGMUSes(encoding.clauses()); return new HybridSolvingResult(sat4JGMUSes, sat4JSolver); diff --git a/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/solving_enumerating/marco/MARCOGMUSSolver.java b/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/solving_enumerating/marco/MARCOGMUSSolver.java index 22cf23784eaff67105089b93fff7d9104d6929b7..5ce9497c9c3705cabcc5eb4db3599168c47c3b84 100644 --- a/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/solving_enumerating/marco/MARCOGMUSSolver.java +++ b/integraal/integraal-explanation/src/main/java/fr/boreal/explanation/solving_enumerating/marco/MARCOGMUSSolver.java @@ -3,8 +3,6 @@ package fr.boreal.explanation.solving_enumerating.marco; import com.google.common.collect.BiMap; import fr.boreal.explanation.api.solver.Solver; import fr.boreal.model.logicalElements.api.Atom; -import fr.boreal.model.logicalElements.api.Term; -import no.hasmac.jsonld.uri.Path; import java.io.*; import java.util.HashSet; @@ -16,17 +14,32 @@ import static fr.boreal.explanation.configuration.PathFinder.ensureFilePath; public class MARCOGMUSSolver implements Solver { - private static final MARCOGMUSSolver INSTANCE = new MARCOGMUSSolver(); - - public static MARCOGMUSSolver instance() { - return INSTANCE; - } + private final String pathToMARCOExecutable; String tmpFileName = "gsat.gcnf"; File gcnfFile = new File(tmpFileName); int timeout = 0; + public MARCOGMUSSolver(String pathToMARCOExecutableSetByUser) { + this.pathToMARCOExecutable = + ensureFilePath( + pathToMARCOExecutableSetByUser, + "integraal-explanation/MARCO-MUS/marco.py", + "MARCO-MUS/marco.py"); + } + + public MARCOGMUSSolver() { + this.pathToMARCOExecutable = + ensureFilePath( + "integraal-explanation/MARCO-MUS/marco.py", + "MARCO-MUS/marco.py"); + } + + public String getPathToMARCOExecutable() { + return pathToMARCOExecutable; + } + /** * This main methods call two methods: * 1. writeGCNF: Writing the clauses to temporary gsat.gcnf file @@ -116,9 +129,9 @@ public class MARCOGMUSSolver implements Solver { ProcessBuilder build = new ProcessBuilder().redirectErrorStream(true); String command; if (timeout == 0) - build.command(ensureFilePath("integraal-explanation/MARCO-MUS/marco.py", "MARCO-MUS/marco.py"), "-s", "-v", "-b", "MUSes", gcnfFile.getAbsolutePath()); + build.command(this.pathToMARCOExecutable, "-s", "-v", "-b", "MUSes", gcnfFile.getAbsolutePath()); else - build.command(ensureFilePath("integraal-explanation/MARCO-MUS/marco.py", "MARCO-MUS/marco.py"), "-a", "-v", "-b", "MUSes", "-T", Long.toString(timeout), gcnfFile.getAbsolutePath()); + build.command(this.pathToMARCOExecutable, "-a", "-v", "-b", "MUSes", "-T", Long.toString(timeout), gcnfFile.getAbsolutePath()); Process proc; try { proc = build.start();