コード例 #1
0
{ 'individual': 'temporalFleetWithoutSwitches', 'evolver': 'temporalUnrollingVer0', 'communicator': 'parallelUnixPipe',
    'fleetSize': 6, 'numSensorNeurons': 6, 'numMotorNeurons': 6, 'numHiddenNeurons': 12,
    'mutModifyNeuron': 0.4, 'mutModifyConnection': 0.4, 'mutAddRemRatio': 1.,
    'weightScale': 1.,
    'populationSize': 50,
    'genStopAfter': 4000,
    'initialPopulationType': 'sparse', 'secondObjectiveProbability': 1.0, 'newIndividualsPerGeneration': 1,
    'backup': 'yes', 'backupPeriod': 100, 'trackAncestry': 'no',
    'logBestIndividual': 'yes', 'logPopulation': 'no',
    'printGeneration': 'yes', 'printPopulation': 'no', 'printParetoFront': 'yes',
    'logParetoFront': 'yes', 'logParetoFrontKeepAllGenerations': 'yes', 'logParetoFrontPeriod': 10,
    'randomSeed': 42}

### Required pbsGridWalker definitions
computationName = 'temporal_pool'
nonRSGrid = gr.Grid1d(
    'initialPopulationType', ['random', 'sparse']) * gr.Grid1d(
        'newIndividualsPerGeneration', [0, 5]) * gr.Grid1d(
            'evolver', ['temporalUnrolling', 'temporalUnrollingVer0'])
parametricGrid = nonRSGrid * numTrials + gr.Grid1dFromFile(
    'randomSeed', cr.randSeedFile, size=len(nonRSGrid) * numTrials)

for par in parametricGrid.paramNames():
    evsDefaults.pop(par)


def prepareEnvironment(experiment):
    ce.prepareEnvironment(experiment)


def runComputationAtPoint(worker, params):
    return ce.runComputationAtPoint(worker,
コード例 #2
0
    'writeTrajectories': 'false'
}
arrowbotInitialConditions = [[0] * segments
                             ] * segments  # segmentsXsegments null matrix
arrowbotTargetOrientations = [[1 if i == j else 0 for i in range(segments)]
                              for j in range(segments)
                              ]  # segmentsXsegments identity matrix
# Optional definitions for pbsGridWalker that are constant
involvedGitRepositories = mmr.involvedGitRepositories
# dryRun = False

### Required pbsGridWalker definitions
computationName = 'simpleTimeSeries_N' + str(segments)

gcvsrandGrid = gr.Grid1d('compositeClass0', [
    'integerVectorSymmetricRangeMutations', 'integerVectorRandomJumps'
]) * gr.Grid1d('probabilityOfMutatingClass0', [0.2])
constmorphGrid = gr.Grid1d(
    'compositeClass0', ['integerVectorSymmetricRangeMutations']) * gr.Grid1d(
        'probabilityOfMutatingClass0', [0.0])
nonRSGrid = gcvsrandGrid.concatenate(constmorphGrid)
# parametricGrid = nonRSGrid*numTrials + gr.Grid1dFromFile('randomSeed', mmr.randSeedFile, size=len(nonRSGrid)*numTrials)

# Since the order of iteration is not guaranteed in Python, different random seed sets get assigned to different non-RS points on different machines.
# To circumvent that, I pickle the grid (produced by the commented line above) on the machine that does the calculations and unpickle it on the data processing machine.
import pickle
with open(join(mmr.morphModPath, 'rawgrid'), 'r') as rgf:
    parametricGrid = pickle.load(rgf)

for par in parametricGrid.paramNames():
    evsDefaults.pop(par)
コード例 #3
0
    'writeTrajectories': 'false'
}
arrowbotInitialConditions = [[0] * segments
                             ] * segments  # segmentsXsegments null matrix
arrowbotTargetOrientations = [[1 if i == j else 0 for i in range(segments)]
                              for j in range(segments)
                              ]  # segmentsXsegments identity matrix
# Optional definitions for pbsGridWalker that are constant
involvedGitRepositories = mmr.involvedGitRepositories
# dryRun = False

### Required pbsGridWalker definitions
computationName = 'ccSwipe_N' + str(segments)

nonRSGrid = gr.LinGrid('secondObjectiveProbability', 0.0, 0.05, 0, 20) * \
            gr.Grid1d('initialPopulationType', ['sparse', 'random'])
parametricGrid = nonRSGrid * numTrials + gr.Grid1dFromFile(
    'randomSeed', mmr.randSeedFile, size=len(nonRSGrid) * numTrials)

for par in parametricGrid.paramNames():
    evsDefaults.pop(par)


def prepareEnvironment(experiment):
    gccommons.prepareEnvironment(experiment)


def runComputationAtPoint(worker, params):
    return gccommons.runComputationAtPoint(worker, params, evsDefaults,
                                           arrowbotsDefaults,
                                           arrowbotInitialConditions,
コード例 #4
0
'fleetSize': 6, 'numSensorNeurons': 6, 'numMotorNeurons': 6, 'numHiddenNeurons': 12,
'mutModifyNeuron': 0.4, 'mutModifyConnection': 0.4, 'mutAddRemRatio': 1.,
'weightScale': 1.,
'populationSize': 100,
'genStopAfter': 1800,
'initialPopulationType': 'sparse', 'secondObjectiveProbability': 1.0, 'newIndividualsPerGeneration': 1,
'backup': 'yes', 'backupPeriod': 100, 'trackAncestry': 'no',
'logBestIndividual': 'yes', 'logPopulation': 'no',
'printGeneration': 'yes', 'printPopulation': 'no', 'printParetoFront': 'yes',
'logParetoFront': 'yes', 'logParetoFrontKeepAllGenerations': 'yes', 'logParetoFrontPeriod': 10,
'randomSeed': 42}

### Required pbsGridWalker definitions
computationName = 'temporal_simple_v2'

nonRSGrid = gr.Grid1d('initialPopulationType', ['sparse', 'random'])*gr.Grid1d('newIndividualsPerGeneration', [1])
parametricGrid = nonRSGrid*numTrials + gr.Grid1dFromFile('randomSeed', cr.randSeedFile, size=len(nonRSGrid)*numTrials)

for par in parametricGrid.paramNames():
	evsDefaults.pop(par)

def prepareEnvironment(experiment):
	ce.prepareEnvironment(experiment)

def runComputationAtPoint(worker, params):
	return ce.runComputationAtPoint(worker, params, evsDefaults, parallelClients=cores)

def processResults(experiment):
	import os
	import shutil
	import numpy as np
コード例 #5
0
               'backup': 'no', 'trackAncestry': 'no',
               'randomSeed': 0}
arrowbotsDefaults = {'segments': segments, 'sensorAttachmentType': 'variable',
                     'simulationTime': 10., 'timeStep': 0.1,
                     'integrateError': 'false', 'writeTrajectories': 'false'}
arrowbotInitialConditions = [[0]*segments]*segments # segmentsXsegments null matrix
arrowbotTargetOrientations = [ [1 if i==j else 0 for i in range(segments)] for j in range(segments) ] # segmentsXsegments identity matrix
# Optional definitions for pbsGridWalker that are constant
involvedGitRepositories = mmr.involvedGitRepositories
# dryRun = False

### Required pbsGridWalker definitions
computationName = 'rateSizeSwipe_N' + str(segments)

nonRSGrid = gr.LinGrid('probabilityOfMutatingClass0', 0.0, 0.2, 0, 5) * \
            gr.Grid1d('initialPopulationType', ['sparse', 'random']) * \
            gr.Grid1d('populationSize', [15, 25, 40, 60])
parametricGrid = nonRSGrid*numTrials + gr.Grid1dFromFile('randomSeed', mmr.randSeedFile, size=len(nonRSGrid)*numTrials)

for par in parametricGrid.paramNames():
	evsDefaults.pop(par)

def prepareEnvironment(experiment):
	gccommons.prepareEnvironment(experiment)

def runComputationAtPoint(worker, params):
	return gccommons.runComputationAtPoint(worker, params,
		evsDefaults, arrowbotsDefaults,
		arrowbotInitialConditions,
		arrowbotTargetOrientations)
コード例 #6
0
    'fleetSize': 6, 'numSensorNeurons': 10, 'numMotorNeurons': 6, 'initNumBehavioralControllers': 1,
    'numHiddenNeurons': 6, 'mutModifyNeuron': 0.3, 'mutModifyConnection': 0.4, 'mutAddRemRatio': 1.,
    'weightScale': 1.,
    'populationSize': 50,
    'genStopAfter': 5000,
    'initialPopulationType': 'sparse',
    'backup': 'yes', 'backupPeriod': 100, 'trackAncestry': 'no',
    'logBestIndividual': 'yes', 'logPopulation': 'no',
    'printGeneration': 'yes', 'printPopulation': 'no', 'printParetoFront': 'yes',
    'logParetoFront': 'yes', 'logParetoFrontKeepAllGenerations': 'yes', 'logParetoFrontPeriod': 10,
    'randomSeed': 42}

### Required pbsGridWalker definitions
computationName = 'afpo-continuous'

nonRSGrid = gr.Grid1d('numHiddenNeurons', [6, 12, 18]) * gr.Grid1d(
    'initialPopulationType', ['sparse', 'random'])
parametricGrid = nonRSGrid * numTrials + gr.Grid1dFromFile(
    'randomSeed', cr.randSeedFile, size=len(nonRSGrid) * numTrials)

for par in parametricGrid.paramNames():
    evsDefaults.pop(par)


def prepareEnvironment(experiment):
    ce.prepareEnvironment(experiment)


def runComputationAtPoint(worker, params):
    return ce.runComputationAtPoint(worker,
                                    params,
{ 'individual': 'temporalFleetWithoutSwitches', 'evolver': 'cluneSimplified', 'communicator': 'parallelUnixPipe',
'fleetSize': 6, 'numSensorNeurons': 6, 'numMotorNeurons': 6, 'numHiddenNeurons': 12,
'mutModifyNeuron': 0.4, 'mutModifyConnection': 0.4, 'mutAddRemRatio': 1.,
'weightScale': 1.,
'populationSize': 100,
'genStopAfter': 1800,
'initialPopulationType': 'sparse', 'secondObjectiveProbability': 1.0, 'newIndividualsPerGeneration': 1,
'backup': 'yes', 'backupPeriod': 100, 'trackAncestry': 'no',
'logBestIndividual': 'yes', 'logPopulation': 'no',
'printGeneration': 'yes', 'printPopulation': 'no', 'printParetoFront': 'yes',
'logParetoFront': 'yes', 'logParetoFrontKeepAllGenerations': 'yes', 'logParetoFrontPeriod': 10,
'randomSeed': 42}

### Required pbsGridWalker definitions
computationName = 'clune_pool_sparse'
nonRSGrid = gr.Grid1d('initialPopulationType', ['sparse'])*gr.Grid1d('newIndividualsPerGeneration', [0, 5])*gr.Grid1d('evolver', ['cluneSimplified', 'cluneSimplifiedWithPool']);
parametricGrid = nonRSGrid*numTrials + gr.Grid1dFromFile('randomSeed', cr.randSeedFile, size=len(nonRSGrid)*numTrials)

for par in parametricGrid.paramNames():
	evsDefaults.pop(par)

def prepareEnvironment(experiment):
	ce.prepareEnvironment(experiment)

def runComputationAtPoint(worker, params):
	return ce.runComputationAtPoint(worker, params, evsDefaults, parallelClients=cores)

def processResults(experiment):
	import os
	import shutil
	import numpy as np
コード例 #8
0
    'fleetSize': 6, 'numSensorNeurons': 6, 'numMotorNeurons': 6, 'numHiddenNeurons': 12,
    'mutModifyNeuron': 0.4, 'mutModifyConnection': 0.4, 'mutAddRemRatio': 1.,
    'weightScale': 1.,
    'populationSize': 100,
    'genStopAfter': 5000,
    'initialPopulationType': 'sparse', 'secondObjectiveProbability': 1.0, 'newIndividualsPerGeneration': 1,
    'backup': 'yes', 'backupPeriod': 100, 'trackAncestry': 'no',
    'logBestIndividual': 'yes', 'logPopulation': 'no',
    'printGeneration': 'yes', 'printPopulation': 'no', 'printParetoFront': 'yes',
    'logParetoFront': 'yes', 'logParetoFrontKeepAllGenerations': 'yes', 'logParetoFrontPeriod': 10,
    'randomSeed': 42}

### Required pbsGridWalker definitions
computationName = 'pcc_simple'

nonRSGrid = gr.Grid1d('secondObjectiveProbability',
                      [0.7, 0.9, 1.0]) * gr.Grid1d(
                          'newIndividualsPerGeneration', [0, 1, 4])
parametricGrid = nonRSGrid * numTrials + gr.Grid1dFromFile(
    'randomSeed', cr.randSeedFile, size=len(nonRSGrid) * numTrials)

for par in parametricGrid.paramNames():
    evsDefaults.pop(par)


def prepareEnvironment(experiment):
    ce.prepareEnvironment(experiment)


def runComputationAtPoint(worker, params):
    return ce.runComputationAtPoint(worker,
                                    params,
コード例 #9
0
ファイル: experiment_EFA3.py プロジェクト: abernatskiy/walter
'lineageInjectionPeriod': 50, 'mutatedLineagesRatio': 0., 'lineageMutationType': 'individualClassDefault',
'genStopAfter': 6000,
'numFitnessParams': 5,
'initialPopulationType': 'random',
'backup': 'yes', 'backupPeriod': 100, 'trackAncestry': 'yes',
'logBestIndividual': 'yes', 'logPopulation': 'yes', 'logPopulationPeriod': 100,
'printGeneration': 'yes', 'printPopulation': 'no', 'printParetoFront': 'yes',
'logParetoFront': 'yes', 'logParetoFrontKeepAllGenerations': 'yes', 'logParetoFrontPeriod': 10,
'randomSeed': 42}

### Required pbsGridWalker definitions
computationName = 'ageFunction3'

nonRSGrid = (
             (
              gr.Grid1d('individual', ['ctrnnDiscreteWeightsFleetOfIdenticalsEvolvableFitness'])*
              gr.Grid1d('lineageInjectionPeriod', [50])*
              gr.Grid1d('mutatedLineagesRatio', [0.0])*
              gr.Grid1d('initialPopulationType', ['random'])*
              gr.Grid1d('evolver', ['ageFunction'])*
              gr.Grid1d('lineageMutationType', ['individualClassDefault'])
             ).concatenate(
              gr.Grid1d('individual', ['ctrnnDiscreteWeightsFleetOfIdenticalsEvolvableFitness'])*
              gr.Grid1d('lineageInjectionPeriod', [50])*
              gr.Grid1d('mutatedLineagesRatio', [1.0])*
              gr.Grid1d('initialPopulationType', ['random'])*
              gr.Grid1d('evolver', ['ageFunction'])*
              gr.Grid1d('lineageMutationType', ['individualClassDefault', 'randomJump'])
            )
            )
コード例 #10
0
{ 'individual': 'ctrnnFleetOfIdenticals', 'evolver': 'cluneSimplified', 'communicator': 'parallelUnixPipe',
    'fleetSize': 6, 'numSensorNeurons': 6, 'numMotorNeurons': 6, 'numHiddenNeurons': 12,
    'mutModifyNeuron': 0.4, 'mutModifyConnection': 0.4, 'mutAddRemRatio': 1.,
    'weightScale': 1.,
    'populationSize': 50,
    'genStopAfter': 4000,
    'initialPopulationType': 'sparse', 'secondObjectiveProbability': 1.0, 'newIndividualsPerGeneration': 1,
    'backup': 'yes', 'backupPeriod': 100, 'trackAncestry': 'no',
    'logBestIndividual': 'yes', 'logPopulation': 'no',
    'printGeneration': 'yes', 'printPopulation': 'no', 'printParetoFront': 'yes',
    'logParetoFront': 'yes', 'logParetoFrontKeepAllGenerations': 'yes', 'logParetoFrontPeriod': 10,
    'randomSeed': 42}

### Required pbsGridWalker definitions
computationName = 'clune_pool_sop0.9'
nonRSGrid = gr.Grid1d('initialPopulationType',
                      ['sparse', 'random']) * gr.Grid1d(
                          'secondObjectiveProbability', [0.9])
#computationName = 'clune_pool_sparse'
#nonRSGrid = gr.Grid1d('initialPopulationType', ['sparse', 'random'])*gr.Grid1d('newIndividualsPerGeneration', [0, 5])*gr.Grid1d('evolver', ['cluneSimplified', 'cluneSimplifiedWithPool']);
parametricGrid = nonRSGrid * numTrials + gr.Grid1dFromFile(
    'randomSeed', cr.randSeedFile, size=len(nonRSGrid) * numTrials)

for par in parametricGrid.paramNames():
    evsDefaults.pop(par)


def prepareEnvironment(experiment):
    ce.prepareEnvironment(experiment)


def runComputationAtPoint(worker, params):
コード例 #11
0
               'backup': 'no', 'trackAncestry': 'no',
               'randomSeed': 0}
arrowbotsDefaults = {'segments': segments, 'sensorAttachmentType': 'variable',
                     'simulationTime': 10.0, 'timeStep': 0.1,
                     'integrateError': 'false', 'writeTrajectories': 'false'}
arrowbotInitialConditions = [[0]*segments]*segments # segmentsXsegments null matrix
arrowbotTargetOrientations = [ [1 if i==j else 0 for i in range(segments)] for j in range(segments) ] # segmentsXsegments identity matrix
# Optional definitions for pbsGridWalker that are constant
involvedGitRepositories = mmr.involvedGitRepositories
# dryRun = False

### Required pbsGridWalker definitions
computationName = 'rateSwipe_N' + str(segments)

nonRSGrid = gr.LinGrid('probabilityOfMutatingClass0', 0.0, 0.05, 0, 20) * \
            gr.Grid1d('compositeClass0', ['integerVectorSymmetricRangeMutations', 'integerVectorRandomJumps'])
parametricGrid = nonRSGrid*numTrials + gr.Grid1dFromFile('randomSeed', mmr.randSeedFile, size=len(nonRSGrid)*numTrials)

for par in parametricGrid.paramNames():
	evsDefaults.pop(par)

def prepareEnvironment(experiment):
	gccommons.prepareEnvironment(experiment)

def runComputationAtPoint(worker, params):
	return gccommons.runComputationAtPoint(worker, params,
		evsDefaults, arrowbotsDefaults,
		arrowbotInitialConditions,
		arrowbotTargetOrientations)

def processResults(experiment):
コード例 #12
0
                             ] * segments  # segmentsXsegments null matrix
arrowbotTargetOrientations = [[1 if i == j else 0 for i in range(segments)]
                              for j in range(segments)
                              ]  # segmentsXsegments identity matrix

# Optional definitions for pbsGridWalker that depend on the number of segments
pointsPerJob = 10
queue = 'workq'
expectedWallClockTime = '30:00:00'

# Optional definitions for pbsGridWalker that are constant
maxJobs = 25
involvedGitRepositories = mmr.involvedGitRepositories

# Required pbsGridWalker definitions
parametricGrid = gr.Grid1d(
    'sensorAttachmentType', attachments.keys()) * gr.Grid1d(
        'initialPopulationType', initialPopulationTypes) * gr.Grid1dFromFile(
            'randomSeed', mmr.randSeedFile, size=numTrials)


def prepareEnvironment(experiment):
    if not exists(mmr.arrowbotsExecutable):
        raise RuntimeError('Arrowbots executable not found at ' +
                           mmr.arrowbotsExecutable)
    if not exists(mmr.evsExecutable):
        raise RuntimeError('EVS executable not found at ' + mmr.evsExecutable)


def runComputationAtPoint(worker, params):
    print('Running evs-arrowbots pair with the following parameters: ' +
          str(params))
コード例 #13
0
    'populationSize': 500,
    'genStopAfter': 3000,
    'numFitnessParams': 5,
    'fitnessParamsUpdatePeriod': 50,
    'fitnessGroupsNumber': 10,
    'initialPopulationType': 'random',
    'backup': 'yes', 'backupPeriod': 100, 'trackAncestry': 'yes',
    'logBestIndividual': 'yes', 'logPopulation': 'yes', 'logPopulationPeriod': 100,
    'printGeneration': 'yes', 'printPopulation': 'no', 'printParetoFront': 'yes',
    'logParetoFront': 'yes', 'logParetoFrontKeepAllGenerations': 'yes', 'logParetoFrontPeriod': 10,
    'randomSeed': 42}

### Required pbsGridWalker definitions
computationName = 'evolvableFitness'

nonRSGrid = gr.Grid1d('fitnessParamsUpdatePeriod', [25, 50, 100]) * gr.Grid1d(
    'evolver',
    ['evolvableFitnessFunction', 'evolvableFitnessFunctionSparsityBiased'])
parametricGrid = nonRSGrid * numTrials + gr.Grid1dFromFile(
    'randomSeed', cr.randSeedFile, size=len(nonRSGrid) * numTrials)

for par in parametricGrid.paramNames():
    evsDefaults.pop(par)


def prepareEnvironment(experiment):
    ce.prepareEnvironment(experiment)


def runComputationAtPoint(worker, params):
    return ce.runComputationAtPoint(worker,
コード例 #14
0
arrowbotsAdditionalParams = {'segments': segments,
                             'simulationTime': 10., 'timeStep': 0.1, 'integrateError': 'no', 'writeTrajectories': 'no'}
arrowbotInitialConditions = [[0]*segments]*segments # segmentsXsegments null matrix
arrowbotTargetOrientations = [ [1 if i==j else 0 for i in range(segments)] for j in range(segments) ] # segmentsXsegments identity matrix

# Optional definitions for pbsGridWalker that depend on the number of segments
pointsPerJob = 25
maxJobs = 8
queue = 'shortq'
expectedWallClockTime = '01:00:00'

# Optional definitions for pbsGridWalker that are constant
involvedGitRepositories = mmr.involvedGitRepositories

# Required pbsGridWalker definitions
parametricGrid = gr.Grid1d('sensorAttachmentType', attachments.keys())*gr.Grid1d('initialPopulationType', initialPopulationTypes)*gr.Grid1dFromFile('randomSeed', mmr.randSeedFile, size=numTrials)

def prepareEnvironment(experiment):
	if not exists(mmr.arrowbotsExecutable):
		raise RuntimeError('Arrowbots executable not found at ' + mmr.arrowbotsExecutable)
	if not exists(mmr.evsExecutable):
		raise RuntimeError('EVS executable not found at ' + mmr.evsExecutable)

def runComputationAtPoint(worker, params):
	print('Running evs-arrowbots pair with the following parameters: ' + str(params))
	parsedParams = tal.classifyDict(params, classifiers.serverClientClassifier)
	serverParams = tal.sumOfDicts(parsedParams['server'], evsAdditionalParams)
	clientParams = tal.sumOfDicts(parsedParams['client'], arrowbotsAdditionalParams)
	tiniw.write(serverParams, classifiers.evsClassifier, 'evs.ini')
	tiniw.write(clientParams, classifiers.arrowbotsClassifier, 'arrowbot.ini')
	tfio.writeColumns(arrowbotInitialConditions, 'initialConditions.dat')
コード例 #15
0
ファイル: experiment_TU.py プロジェクト: abernatskiy/walter
{ 'individual': 'temporalFleetDiscreteWeightsWithoutSwitches', 'evolver': 'temporalUnrollingAFPO', 'communicator': 'parallelUnixPipe',
    'fleetSize': 6, 'numSensorNeurons': 10, 'numMotorNeurons': 6, 'numHiddenNeurons': 12,
    'mutModifyNeuron': 0.4, 'mutModifyConnection': 0.4, 'mutAddRemRatio': 1.,
    'weightScale': 1.,
    'populationSize': 50,
    'genStopAfter': 5000,
    'initialPopulationType': 'random', 'secondObjectiveProbability': 1.0, 'newIndividualsPerGeneration': 1,
    'backup': 'yes', 'backupPeriod': 100, 'trackAncestry': 'no',
    'logBestIndividual': 'yes', 'logPopulation': 'no',
    'printGeneration': 'yes', 'printPopulation': 'no', 'printParetoFront': 'yes',
    'logParetoFront': 'yes', 'logParetoFrontKeepAllGenerations': 'yes', 'logParetoFrontPeriod': 100,
    'randomSeed': 42}

### Required pbsGridWalker definitions
computationName = 'temporal_unrolling'
nonRSGrid = gr.Grid1d(
    'initialPopulationType', ['random', 'sparse']) * gr.Grid1d(
        'evolver', [
            'temporalUnrollingAFPO', 'temporalUnrollingSimplest',
            'temporalUnrollingWithPool'
        ])
parametricGrid = nonRSGrid * numTrials + gr.Grid1dFromFile(
    'randomSeed',
    cr.randSeedFile,
    startAt=200,
    size=len(nonRSGrid) * numTrials)

for par in parametricGrid.paramNames():
    evsDefaults.pop(par)


def prepareEnvironment(experiment):