19package denoptim.fitness;
21import java.util.ArrayList;
22import java.util.HashMap;
25import java.util.logging.Level;
26import java.util.logging.Logger;
28import org.openscience.cdk.IImplementationSpecification;
29import org.openscience.cdk.exception.CDKException;
30import org.openscience.cdk.interfaces.IAtom;
31import org.openscience.cdk.interfaces.IAtomContainer;
32import org.openscience.cdk.interfaces.IBond;
33import org.openscience.cdk.isomorphism.Mappings;
34import org.openscience.cdk.qsar.DescriptorEngine;
35import org.openscience.cdk.qsar.DescriptorValue;
36import org.openscience.cdk.qsar.IAtomPairDescriptor;
37import org.openscience.cdk.qsar.IAtomicDescriptor;
38import org.openscience.cdk.qsar.IBondDescriptor;
39import org.openscience.cdk.qsar.IDescriptor;
40import org.openscience.cdk.qsar.IMolecularDescriptor;
41import org.openscience.cdk.qsar.result.DoubleArrayResult;
42import org.openscience.cdk.qsar.result.DoubleResult;
43import org.openscience.cdk.qsar.result.IDescriptorResult;
44import org.openscience.cdk.qsar.result.IntegerArrayResult;
45import org.openscience.cdk.qsar.result.IntegerResult;
47import denoptim.constants.DENOPTIMConstants;
48import denoptim.exception.DENOPTIMException;
49import denoptim.utils.DummyAtomHandler;
50import denoptim.utils.ManySMARTSQuery;
51import denoptim.utils.MathUtils;
52import jakarta.el.ELContext;
53import jakarta.el.ELException;
54import jakarta.el.ELResolver;
55import jakarta.el.ExpressionFactory;
56import jakarta.el.FunctionMapper;
57import jakarta.el.ValueExpression;
58import jakarta.el.VariableMapper;
119 this.descriptors =
new ArrayList<DescriptorForFitness>();
122 ArrayList<String> classnames =
new ArrayList<String>();
130 engine =
new DescriptorEngine(classnames,
null);
131 List<IDescriptor> newInstances =
engine.getDescriptorInstances();
133 for (
int i=0; i<this.descriptors.size(); i++)
135 this.descriptors.get(i).implementation = newInstances.get(i);
138 this.descriptors.get(i).implementation.setParameters(
139 descriptors.get(i).implementation.getParameters());
140 }
catch (CDKException e)
147 engine.setDescriptorInstances(newInstances);
148 engine.setDescriptorSpecifications(
engine.initializeSpecifications(
164 public double getFitness(IAtomContainer iac)
throws Exception
190 logger.log(Level.FINE,
"Descriptor instances: "
191 +
engine.getDescriptorInstances().size());
196 HashMap<String, Double> valuesMap =
new HashMap<String,Double>();
202 valuesMap.put(v.getName(),
null);
205 for (
int i=0; i<
engine.getDescriptorInstances().size(); i++)
208 IDescriptor desc =
engine.getDescriptorInstances().get(i);
211 logger.log(Level.FINE,
"Working on descriptor '"
214 IImplementationSpecification descSpec =
215 engine.getDescriptorSpecifications().get(i);
218 Map<String, String> smarts =
new HashMap<String, String>();
221 logger.log(Level.FINE,
"-Processing varName = '"
222 + variable.getName() +
"'");
223 if (variable.smarts !=
null)
225 if (variable.smarts.size()!=1)
228 +
"SMARTS identifiers is not implemented yet. "
229 +
"Please, let the DENOPTIM developers know "
230 +
"about your interest in this "
233 smarts.put(variable.getName(), variable.smarts.get(0));
237 Map<String, Mappings> allMatches =
new HashMap<String, Mappings>();
238 if (smarts.size() != 0)
243 String msg =
"WARNING! Problems while searching for "
244 +
"specific atoms/bonds using SMARTS: "
251 logger.log(Level.FINE,
"Collecting value of variables "
252 +
"derived from descriptor #" + i +
": " + descName);
255 DescriptorValue value =
null;
256 if (desc instanceof IMolecularDescriptor)
260 String varName = variable.getName();
261 value = (DescriptorValue) iac.getProperty(descSpec);
263 descSpec, value, varName, iac);
264 valuesMap.put(varName, val);
265 iac.setProperty(varName,val);
267 }
else if (desc instanceof IAtomicDescriptor) {
270 String varName = variable.getName();
271 Mappings hits = allMatches.get(varName);
274 String msg =
"No hits for SMARTS of " + varName +
": "
275 +
"setting variable value to 0.0";
276 logger.log(Level.WARNING ,msg);
277 valuesMap.put(varName, 0.0);
280 logger.log(Level.FINE,
"-AtomIDs contributing to "
281 + varName +
":" + hits);
282 if (hits.count() > 1)
284 String msg =
"Multiple hits with SMARTS identifier for "
285 + varName +
". Taking average of all values.";
286 logger.log(Level.WARNING ,msg);
289 List<Double> vals =
new ArrayList<Double>();
290 for (
int[] singleMatch : hits)
292 if (singleMatch.length != 1)
294 String msg =
"Multiple entries in a single hit "
295 +
"with SMARTS identifier for "
296 + varName +
". Taking average of values.";
297 logger.log(Level.WARNING ,msg);
299 for (Integer atmId : singleMatch)
301 IAtom atm = iac.getAtom(atmId);
302 value = (DescriptorValue) atm.getProperty(descSpec);
304 desc, descSpec, value, varName, iac);
307 iac.setProperty(varName+
"_"+valCounter,val);
310 logger.log(Level.FINE,
"-Values contributing to "
311 + varName +
": " + vals);
313 valuesMap.put(varName, overallValue);
314 iac.setProperty(varName,overallValue);
316 }
else if (desc instanceof IBondDescriptor) {
319 String varName = variable.getName();
320 Mappings hits = allMatches.get(varName);
323 String msg =
"No hits for SMARTS of " + varName +
": "
324 +
"setting variable value to 0.0";
325 logger.log(Level.WARNING, msg);
326 valuesMap.put(varName, 0.0);
329 logger.log(Level.FINE,
"-AtomIDs contributing to "
330 + varName +
":" + hits);
331 if (hits.count() > 1)
333 String msg =
"Multiple hits with SMARTS identifier for "
334 + varName +
". Taking average of all values.";
335 logger.log(Level.WARNING, msg);
338 List<Double> vals =
new ArrayList<Double>();
339 for (
int[] singleMatch : hits)
341 if (singleMatch.length != 2)
343 String msg =
"Number of entries is != 2 for a "
344 +
"single hit with SMARTS identifier for "
345 + varName +
". I do not know how to deal "
349 IBond bnd = iac.getBond(iac.getAtom(singleMatch[0]),
350 iac.getAtom(singleMatch[1]));
351 value = (DescriptorValue) bnd.getProperty(descSpec);
353 desc, descSpec, value, varName, iac);
356 iac.setProperty(varName+
"_"+valCounter,val);
358 logger.log(Level.FINE,
"-Values contributing to "
359 + varName +
": "+vals);
361 valuesMap.put(varName, overallValue);
362 iac.setProperty(varName,overallValue);
364 }
else if (desc instanceof IAtomPairDescriptor) {
365 throw new Exception(
"AtomPair-kind of descriptors are not yet "
366 +
" usable. Upgrade the code. ");
369 throw new Exception(
"Type of descriptor "+ descName +
" is "
370 +
"unknown. Cannot understand if it should be threated "
371 +
"as molecular, atomic, or bond descriptor.");
374 logger.log(Level.FINE,
"VARIABLES: "+valuesMap);
377 ExpressionFactory expFactory = ExpressionFactory.newInstance();
378 ELContext ncc =
new ELContext() {
380 VariableMapper vm =
new VariableMapper() {
382 @SuppressWarnings(
"serial")
384 public ValueExpression resolveVariable(String varName)
386 ValueExpression ve =
new ValueExpression() {
389 public Object getValue(ELContext context)
392 if (!valuesMap.containsKey(varName))
394 throw new ELException(
"Variable '" + varName
395 +
"' cannot be resolved");
397 value = valuesMap.get(varName);
403 public void setValue(ELContext context, Object value)
407 public boolean isReadOnly(ELContext context)
413 public Class<?> getType(ELContext context)
419 public Class<?> getExpectedType()
425 public String getExpressionString()
431 public boolean equals(Object obj)
437 public int hashCode()
443 public boolean isLiteralText()
452 public ValueExpression setVariable(String variable,
459 public ELResolver getELResolver()
465 public FunctionMapper getFunctionMapper()
471 public VariableMapper getVariableMapper()
476 double fitness = Double.NaN;
479 ValueExpression ve = expFactory.createValueExpression(ncc,
expression,
481 fitness = (double) ve.getValue(ncc);
499 IDescriptor implementation,
500 IImplementationSpecification descSpec, DescriptorValue value,
501 String varName, IAtomContainer iac)
throws Exception
505 throw new Exception(
"Null value from calculation of descriptor"
506 +
" " + descName +
" (for variable '" + varName +
"'");
509 Exception expFromDescriptor = value.getException();
510 if (expFromDescriptor !=
null)
513 throw new Exception(expFromDescriptor);
516 IDescriptorResult result = value.getValue();
519 throw new Exception(
"Null result from calculation of "
520 +
"descriptor " + descName +
"(for variable '"
524 double valueToFitness = Double.NaN;
526 if (result instanceof DoubleResult)
528 valueToFitness = ((DoubleResult) result).doubleValue();
529 }
else if (result instanceof IntegerResult)
531 valueToFitness = ((IntegerResult)result).intValue();
532 }
else if (result instanceof DoubleArrayResult)
534 DoubleArrayResult a = (DoubleArrayResult) result;
535 int id = descriptor.resultId;
536 if (
id >= a.length())
538 throw new Exception(
"Value ID out of range for descriptor "
541 valueToFitness = a.get(
id);
544 List<String> list =
new ArrayList<String>();
545 for (
int j=0; j<a.length(); j++)
547 list.add(String.valueOf(a.get(j)));
549 iac.setProperty(implementation.getClass().getName() +
"#" + varName,
551 }
else if (result instanceof IntegerArrayResult)
553 IntegerArrayResult array = (IntegerArrayResult) result;
554 int id = descriptor.resultId;
555 if (
id >= array.length())
557 throw new Exception(
"Value ID out of range for descriptor "
560 valueToFitness = array.get(
id);
563 List<String> list =
new ArrayList<String>();
564 for (
int j=0; j<array.length(); j++)
566 list.add(String.valueOf(array.get(j)));
568 iac.setProperty(implementation.getClass().getName()+
"#" + varName,
572 return valueToFitness;
General set of constants used in DENOPTIM.
static final String MOLERRORTAG
SDF tag containing errors during execution of molecule specific tasks.
static final String DUMMYATMSYMBOL
Symbol of dummy atom.
static final String FITNESSTAG
SDF tag containing the fitness of a candidate.
This is a reference to a specific descriptor value.
List< Variable > getVariables()
Get the variables that make use of values produced by this descriptor.
DescriptorForFitness cloneAllButImpl()
This is a sort of cloning that returns a new DescriptorForFitness with the same field content of this...
String shortName
Descriptor short name.
DENOPTIM's (internal) fitness provider calculates the value of Variables that are used in an expressi...
DescriptorEngine engine
The engine that collects and calculates descriptors.
double processValue(String descName, DescriptorForFitness descriptor, IDescriptor implementation, IImplementationSpecification descSpec, DescriptorValue value, String varName, IAtomContainer iac)
Takes the value and checks that it is all good, then processes the value to extract the result define...
List< DescriptorForFitness > descriptors
The collection of descriptors to consider.
double getFitness(IAtomContainer iac)
Calculated the fitness according to the current configuration.
FitnessProvider(List< DescriptorForFitness > descriptors, String expression, Logger logger)
Constructs an instance that will calculate the fitness according to the given parameters.
Logger logger
Program-specific logger.
String expression
The equation used to calculate the fitness value.
A variable in the expression defining the fitness.
Toll to add/remove dummy atoms from linearities or multi-hapto sites.
IAtomContainer removeDummy(IAtomContainer mol)
Removes all dummy atoms and the bonds connecting them to other atoms.
IAtomContainer removeDummyInHapto(IAtomContainer mol)
Container of lists of atoms matching a list of SMARTS.
Map< String, Mappings > getAllMatches()
Some useful math operations.
static double mean(double[] a)
Calculate mean value.