Skip to content
Snippets Groups Projects
Commit 48d2168e authored by Bernhard Johannes Berger's avatar Bernhard Johannes Berger Committed by Christina Sophie Viola Plump
Browse files

Fixed several issues with data generation

parent ef7adb17
No related branches found
No related tags found
2 merge requests!26Merge current develop into release,!23Fixed several issues with data generation
Pipeline #348753 passed
Showing
with 179 additions and 34 deletions
......@@ -3,8 +3,6 @@ package de.evoal.core.api.cdi;
import de.evoal.core.api.utils.InitializationException;
import de.evoal.core.api.utils.LanguageHelper;
import de.evoal.core.api.utils.Requirements;
import de.evoal.languages.model.base.Attribute;
import de.evoal.languages.model.base.FunctionDefinition;
import de.evoal.languages.model.base.Instance;
import de.evoal.languages.model.dl.util.FQNProvider;
import lombok.NonNull;
......@@ -101,6 +99,14 @@ public final class BeanFactory {
return createComponent(type, name, configuration);
}
public static <T extends EvoalComponent<T>> T createComponent(final Class<T> type, final Instance configuration, final String nameSuffix) {
Requirements.requireNotNull(configuration);
final String name = new FQNProvider().get(configuration) + nameSuffix;
return createComponent(type, name, configuration);
}
public static <S extends EvoalComponent<S>, T extends EvoalComponentProvider<S>> S createComponent(final Class<S> type, final Class<T> provider, final Instance configuration) {
Requirements.requireNotNull(type);
Requirements.requireNotNull(configuration);
......
......@@ -4,10 +4,9 @@ import de.evoal.core.api.properties.Properties;
import de.evoal.core.api.properties.PropertiesSpecification;
import de.evoal.core.api.properties.PropertySpecification;
import de.evoal.core.api.utils.InitializationException;
import de.evoal.languages.model.base.Instance;
import de.evoal.languages.model.ddl.DataDescription;
import de.evoal.languages.model.generator.Step;
import de.evoal.languages.model.instance.DataReference;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
......@@ -20,12 +19,12 @@ public abstract class AbstractGeneratorFunction implements GeneratorFunction {
/**
* The properties the generator function writes.
*/
protected PropertiesSpecification writeSpecification;
protected @Getter PropertiesSpecification writeSpecification;
/**
* The properties the generator function reads.
*/
protected PropertiesSpecification readSpecification;
protected @Getter PropertiesSpecification readSpecification;
@Override
public GeneratorFunction init(final Step configuration) throws InitializationException {
......
package de.evoal.generator.api;
import de.evoal.core.api.cdi.EvoalComponent;
import de.evoal.core.api.properties.Properties;
import de.evoal.core.api.properties.PropertiesSpecification;
import de.evoal.core.api.utils.InitializationException;
import de.evoal.languages.model.generator.Step;
......@@ -16,4 +15,14 @@ public interface GeneratorFunction {
default GeneratorFunction init(final Step configuration) throws InitializationException {
return this;
}
/**
* Returns the specification properties read by the generator function.
*/
PropertiesSpecification getReadSpecification();
/**
* Returns the specification properties written by the generator function.
*/
PropertiesSpecification getWriteSpecification();
}
......@@ -8,30 +8,26 @@ import de.evoal.core.api.properties.PropertySpecification;
import de.evoal.core.api.utils.InitializationException;
import de.evoal.generator.api.AbstractGeneratorFunction;
import de.evoal.generator.api.GeneratorFunction;
import de.evoal.generator.main.utils.ConfigurationHelper;
import de.evoal.generator.main.functions.distributions.Distribution;
import de.evoal.generator.main.functions.distributions.DistributionsFactory;
import de.evoal.languages.model.generator.Step;
import org.apache.commons.math3.distribution.NormalDistribution;
import org.apache.commons.math3.distribution.RealDistribution;
import javax.enterprise.context.Dependent;
import javax.inject.Named;
@Dependent
@Named("de.evoal.generator.generator.normally-distributed-noise")
public class NormalNoiseFunction extends AbstractGeneratorFunction {
@Named("de.evoal.generator.generator.noise-data")
public class NoiseDataFunction extends AbstractGeneratorFunction {
/**
* The different distributions to apply.
*/
private final List<RealDistribution> distributions = new ArrayList<>();
private final List<Distribution> distributions = new ArrayList<>();
public GeneratorFunction init(final Step configuration) throws InitializationException {
super.init(configuration);
ConfigurationHelper.readDistributions(configuration.getInstance(), "distributions")
.stream()
.map(d -> new NormalDistribution(d.μ(), d.σ()))
.forEach(distributions::add);
distributions.addAll(DistributionsFactory.readDistributions(configuration.getInstance(), "distributions"));
return this;
}
......
package de.evoal.generator.main.functions.distributions;
import de.evoal.core.api.cdi.EvoalComponent;
public interface Distribution extends EvoalComponent<Distribution> {
double sample();
}
package de.evoal.generator.main.utils;
package de.evoal.generator.main.functions.distributions;
import de.evoal.core.api.cdi.BeanFactory;
import de.evoal.core.api.utils.LanguageHelper;
import de.evoal.languages.model.base.Array;
import de.evoal.languages.model.base.Instance;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public final class ConfigurationHelper {
private ConfigurationHelper() {}
public record Distribution(double μ, double σ) {}
public final class DistributionsFactory {
private DistributionsFactory() {}
public static List<Distribution> readDistributions(final Instance instance, final String name) {
final Array array = (Array)instance.findAttribute(name).getValue();
return array.getValues()
.stream()
.map(Instance.class::cast)
.map(ConfigurationHelper::readDistribution)
.collect(Collectors.toUnmodifiableList());
}
private static Distribution readDistribution(final Instance instance) {
final LanguageHelper helper = BeanFactory.create(LanguageHelper.class);
final double μ = helper.lookup(instance, "μ");
final double σ = helper.lookup(instance, "σ");
final Object [] array = helper.lookup(instance, name);
return new Distribution(μ, σ);
return Arrays.stream(array)
.map(Instance.class::cast)
.map(i -> BeanFactory.createComponent(Distribution.class, i, "-noise"))
.toList();
}
}
package de.evoal.generator.main.functions.distributions;
import de.evoal.core.api.utils.LanguageHelper;
import de.evoal.languages.model.base.Instance;
import lombok.Data;
import org.apache.commons.math3.distribution.RealDistribution;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.inject.Named;
@Data
@Named("de.evoal.generator.generator.normal-distribution-noise")
@Dependent
public class NormalDistribution implements Distribution {
private RealDistribution distribution;
@Inject
private LanguageHelper helper;
@Override
public NormalDistribution init(final Instance configuration) {
double μ = helper.lookup(configuration, "μ");
double σ = helper.lookup(configuration, "σ");
distribution = new org.apache.commons.math3.distribution.NormalDistribution(μ, σ);
return this;
}
@Override
public double sample() {
return distribution.sample();
}
}
package de.evoal.generator.main.functions.distributions;
import de.evoal.core.api.utils.LanguageHelper;
import de.evoal.languages.model.base.Instance;
import lombok.Data;
import org.apache.commons.math3.distribution.RealDistribution;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.inject.Named;
@Data
@Named("de.evoal.generator.generator.uniform-distribution-noise")
@Dependent
public class UniformDistribution implements Distribution {
private double l;
private double u;
private RealDistribution distribution;
@Inject
private LanguageHelper helper;
@Override
public UniformDistribution init(final Instance configuration) {
double lower = helper.lookup(configuration, "lower");
double upper = helper.lookup(configuration, "upper");
distribution = new org.apache.commons.math3.distribution.UniformRealDistribution(lower, upper);
return this;
}
@Override
public double sample() {
return distribution.sample();
}
}
package de.evoal.generator.main.generators;
import de.evoal.core.api.languages.ExpressionEvaluator;
import de.evoal.core.api.utils.InitializationException;
import de.evoal.generator.api.GeneratorFunction;
import de.evoal.languages.model.base.RealLiteral;
import de.evoal.languages.model.base.Instance;
import de.evoal.languages.model.generator.Step;
import org.apache.commons.math3.distribution.UniformRealDistribution;
import lombok.extern.slf4j.Slf4j;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.inject.Named;
@Dependent
@Named("de.evoal.generator.generator.uniform-distribution")
@Slf4j
public class UniformDistribution extends RealDistributionBase {
@Inject
private ExpressionEvaluator evaluator;
public GeneratorFunction init(final Step configuration) throws InitializationException {
super.init(configuration);
Object ranges = ((RealLiteral)configuration.getInstance().findAttribute("μ").getValue()).getLiteral();
if(true) throw new IllegalStateException("Not yet implemented.");
final Instance instance = configuration.getInstance();
double lowerBound = evaluator.attributeToDouble(instance, "lower");
double upperBound = evaluator.attributeToDouble(instance, "upper");
//Object ranges = ((RealLiteral)configuration.getInstance().findAttribute("μ").getValue()).getLiteral();
//if(true) throw new IllegalStateException("Not yet implemented.");
log.info("Using uniform distribution with lower={} and upper={}", lowerBound, upperBound);
for(int i = 0; i < writeSpecification.getProperties().size(); ++i) {
getDistributions().add(new UniformRealDistribution(-1.0, 1.0));
getDistributions().add(new UniformRealDistribution(lowerBound, upperBound));
}
return this;
......
......@@ -114,7 +114,7 @@ public class StatementExecutor extends GeneratorSwitch<Object> {
.filter(Objects::nonNull)
.filter(Pipeline.class::isInstance)
.map(Pipeline.class::cast)
.collect(Collectors.toUnmodifiableList());
.toList();
String filename = stmt.getFile();
......@@ -146,21 +146,27 @@ public class StatementExecutor extends GeneratorSwitch<Object> {
log.info("Writing {} with {} data points.", filename, count);
new File(filename).getAbsoluteFile().getParentFile().mkdirs();
final PropertiesSpecification specification = PropertiesSpecification.builder().build();
final Properties emptyProperties = new Properties(specification);
// we start with an empty specification (and empty properties)
final PropertiesSpecification emptySpecification = PropertiesSpecification.builder()
.build();
final Properties emptyProperties = new Properties(emptySpecification);
Stream<Properties> stream = Stream.generate(() -> emptyProperties);
PropertiesSpecification specification = emptySpecification;
for(final Pipeline pipe : pipelines) {
for(final GeneratorFunction function : pipe.getSteps()) {
stream = stream.map(function::apply);
specification = PropertiesSpecification.builder()
.add(specification)
.add(function.getWriteSpecification())
.build();
}
}
PropertiesSpecification.Builder resultSpec = PropertiesSpecification.builder();
stream = stream.peek(p -> resultSpec.add(p.getSpecification()));
try(final PropertiesWriter writer = PropertiesIOFactory.writer(new File(filename), resultSpec.build())) {
log.info("Writing properties stream with specification {} to {}.", specification, filename);
try(final PropertiesWriter writer = PropertiesIOFactory.writer(new File(filename), specification)) {
stream.limit(count)
.forEach(p -> {
try {
......
module de.evoal.generator.main {
requires java.base;
requires jakarta.inject.api;
requires jakarta.enterprise.cdi.api;
......@@ -42,4 +40,5 @@ module de.evoal.generator.main {
exports de.evoal.generator.api;
opens de.evoal.generator.api to weld.core.impl;
opens de.evoal.generator.main.functions.distributions;
}
......@@ -225,10 +225,10 @@ module de.evoal.generator.generator {
}
/**
* Adds normally distributed noise to data. For each data to noise, you can
* specify a separate distribution.
* Adds noise to data. For each data to noise, you can specify a
* separate distribution.
*/
type 'normally-distributed-noise' {
type 'noise-data' {
/**
* The different distributions to use. Make sure it matches the size of
* the data the function writes.
......@@ -250,6 +250,20 @@ module de.evoal.generator.generator {
*/
'σ' : real;
}
/**
* Specification for uniform distribution.
*/
type 'uniform-distribution' extends distribution {
/**
* parameter for lower bound
*/
'lower' :real;
/**
* parameter for upper bound
*/
'upper' : real;
}
type 'constraint-validation' {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment