$darkmode
DENOPTIM
FitnessProviderTest.java
Go to the documentation of this file.
1package denoptim.fitness;
2
3/*
4 * DENOPTIM
5 * Copyright (C) 2019 Vishwesh Venkatraman <vishwesh.venkatraman@ntnu.no>
6 * and Marco Foscato <marco.foscato@uib.no>
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published
10 * by the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22import static org.junit.jupiter.api.Assertions.assertEquals;
23import static org.junit.jupiter.api.Assertions.assertTrue;
24
25import java.io.File;
26import java.util.ArrayList;
27import java.util.List;
28import java.util.Map;
29import java.util.logging.Level;
30import java.util.logging.Logger;
31
32import org.junit.jupiter.api.BeforeEach;
33import org.junit.jupiter.api.Test;
34import org.junit.jupiter.api.io.TempDir;
35import org.openscience.cdk.DefaultChemObjectBuilder;
36import org.openscience.cdk.exception.InvalidSmilesException;
37import org.openscience.cdk.fingerprint.IBitFingerprint;
38import org.openscience.cdk.fingerprint.PubchemFingerprinter;
39import org.openscience.cdk.interfaces.IAtomContainer;
40import org.openscience.cdk.qsar.DescriptorEngine;
41import org.openscience.cdk.qsar.IDescriptor;
42import org.openscience.cdk.silent.SilentChemObjectBuilder;
43import org.openscience.cdk.smiles.SmilesParser;
44
45import denoptim.constants.DENOPTIMConstants;
46import denoptim.fitness.descriptors.TanimotoMolSimilarity;
47import denoptim.io.DenoptimIO;
48
56{
57 private SmilesParser sp;
58 private static final String SEP = System.getProperty("file.separator");
59
60 @TempDir
61 static File tempDir;
62
63 private Logger logger;
64
65 @BeforeEach
66 void setUp()
67 {
68 assertTrue(tempDir.isDirectory(),"Should be a directory ");
69 sp = new SmilesParser(SilentChemObjectBuilder.getInstance());
70 logger = Logger.getLogger("DummyLogger");
71 logger.setLevel(Level.SEVERE);
72 }
73
74//------------------------------------------------------------------------------
75
76 @Test
77 public void testConfigureDescriptorsList() throws Exception
78 {
79 List<String> classNames = new ArrayList<String>();
80 classNames.add("org.openscience.cdk.qsar.descriptors.molecular."
81 + "ZagrebIndexDescriptor");
82 classNames.add("org.openscience.cdk.qsar.descriptors.molecular."
83 + "AtomCountDescriptor");
84 DescriptorEngine engine = new DescriptorEngine(classNames,null);
85 List<IDescriptor> iDescs = engine.instantiateDescriptors(classNames);
86
87 List<DescriptorForFitness> descriptors =
88 new ArrayList<DescriptorForFitness>();
89 for (int i=0; i<iDescs.size(); i++)
90 {
91 IDescriptor iDesc = iDescs.get(i);
93 iDesc.getDescriptorNames()[0],
94 classNames.get(i), iDesc, 0);
95 descriptors.add(dv);
96 }
97
98 FitnessProvider fp = new FitnessProvider(descriptors, "no eq needed",
99 logger);
100
101 assertEquals(2, fp.engine.getDescriptorInstances().size(),
102 "Number of descriptors from custom list");
103 }
104
105//------------------------------------------------------------------------------
106
107 @Test
108 public void testGetFitness() throws Exception
109 {
110 IAtomContainer mol = null;
111 try {
112 mol = sp.parseSmiles("C(C)CO");
113 } catch (InvalidSmilesException e) {
114 // This cannot happen
115 }
116
117 List<String> classNames = new ArrayList<String>();
118 classNames.add("org.openscience.cdk.qsar.descriptors.molecular."
119 + "ZagrebIndexDescriptor");
120 classNames.add("org.openscience.cdk.qsar.descriptors.molecular."
121 + "AtomCountDescriptor");
122 DescriptorEngine engine = new DescriptorEngine(classNames,null);
123 List<IDescriptor> iDescs = engine.instantiateDescriptors(classNames);
124
125 List<DescriptorForFitness> descriptors =
126 new ArrayList<DescriptorForFitness>();
127 String[] varNames = new String[] {"desc0", "desc1"};
128 for (int i=0; i<iDescs.size(); i++)
129 {
130 IDescriptor iDesc = iDescs.get(i);
132 iDesc.getDescriptorNames()[0],
133 classNames.get(i), iDesc, 0);
134 dff.addDependentVariable(new Variable(varNames[i]));
135 descriptors.add(dff);
136 }
137
138 String expression = "${" + varNames[0] + " + " + varNames[1] + "}";
139
140 FitnessProvider fp = new FitnessProvider(descriptors, expression,
141 logger);
142 double fitness = fp.getFitness(mol);
143
144 // The descriptors values must be already in the mol properties map
145 Map<Object, Object> props = mol.getProperties();
146 // 6 properties: title, descpSpec, descSpec, Zagreb val, nAtom val, fitness
147 assertEquals(6,props.size(),"Number of properties in processed mol");
148 List<Object> keys = new ArrayList<Object>();
149 for (Object k : props.keySet())
150 {
151 keys.add(k);
152 }
153 if (props.get(varNames[0]).toString().equals("10.0"))
154 {
155 assertEquals("12.0",props.get(varNames[1]).toString(),
156 "Unexpected descriptor value (A)");
157 } else if (props.get(varNames[1]).toString().equals("10.0"))
158 {
159 assertEquals("10.0",props.get(varNames[0]).toString(),
160 "Unexpected descriptor value (B)");
161 } else {
162 assertTrue(false, "Unexpected descriptor value (C)");
163 }
164
165 double trsh = 0.001;
166 assertTrue(Math.abs(22.0 - fitness) < trsh,
167 "Fitness value should be 22.0 but is " + fitness);
168 }
169
170//------------------------------------------------------------------------------
171
172 @Test
173 public void testGetFitnessWithCustomDescriptors() throws Exception
174 {
175 // Construct a descriptor implementation
176 List<String> classNames = new ArrayList<String>();
177 classNames.add("denoptim.fitness.descriptors.TanimotoMolSimilarity");
178 DescriptorEngine engine = new DescriptorEngine(classNames,null);
179 engine.instantiateDescriptors(classNames);
180 IDescriptor iDesc = new TanimotoMolSimilarity();
181
182 //Customise parameters used to calculate descriptors
183 IAtomContainer ref = sp.parseSmiles("CNC(=O)c1cc(OC)ccc1");
184 PubchemFingerprinter fpMaker = new PubchemFingerprinter(
185 DefaultChemObjectBuilder.getInstance());
186 IBitFingerprint fpRef = fpMaker.getBitFingerprint(ref);
187 Object[] params = {"PubchemFingerprinter", fpRef};
188 iDesc.setParameters(params);
189
190 String myVarName = "myVar";
191
192 //Configure fitness provider
194 iDesc.getDescriptorNames()[0],
195 iDesc.getClass().getName(), iDesc, 0);
196 dff.addDependentVariable(new Variable (myVarName));
197 List<DescriptorForFitness> descriptors =
198 new ArrayList<DescriptorForFitness>();
199 descriptors.add(dff);
200 String expression = "${" + myVarName + "}";
201 FitnessProvider fp = new FitnessProvider(descriptors, expression,
202 logger);
203
204 //Construct a molecule to be evaluated by the fitness provider
205 IAtomContainer mol = sp.parseSmiles("COc1ccccc1");
206
207 //Calculate fitness
208 double fitness = fp.getFitness(mol);
209
210 //Get the result and check it
211 Object propObj = mol.getProperty(DENOPTIMConstants.FITNESSTAG);
212 assertTrue(propObj!=null,"Fitness is not null.");
213 double trsh = 0.001;
214 assertTrue(Math.abs(((double) propObj) - fitness) < trsh,
215 "Fitness value should be 0.6 but is " + fitness);
216 assertTrue(Math.abs(0.6 - fitness) < trsh,
217 "Fitness value should be 0.6 but is " + fitness);
218 }
219
220//------------------------------------------------------------------------------
221
227 @Test
228 public void testGetFitnessWithParametrizedDescriptors() throws Exception
229 {
230 String fileName = tempDir.getAbsolutePath() + SEP + "ref.sdf";
231 IAtomContainer ref = sp.parseSmiles("CNC(=O)c1cc(OC)ccc1");
232 DenoptimIO.writeSDFFile(fileName, ref, false);
233
235
236 String[] lines = new String[] {
237 "FP-Equation=${taniSym + taniBis + 0.02 * Zagreb - aHyb_1 +"
238 + " aHyb_2}",
239 "FP-DescriptorSpecs=${Variable.atomSpecific('aHyb_1','aHyb','[$([C])]')}",
240 "FP-DescriptorSpecs=${Variable.atomSpecific('aHyb_2','aHyb','[$([O])]')}",
241 "FP-DescriptorSpecs=${Variable.parametrized('taniSym',"
242 + "'TanimotoSimilarity','PubchemFingerprinter, "
243 + "FILE:" + fileName + "')}",
244 "FP-DescriptorSpecs=${Variable.parametrized('taniBis',"
245 + "'TanimotoSimilarity','GraphOnlyFingerprinter, "
246 + "FILE:" + fileName + "')}"};
247 for (int i=0; i<lines.length; i++)
248 {
249 String line = lines[i];
250 fitPar.interpretKeyword(line);
251 }
252 fitPar.processParameters();
253
255 fitPar.getDescriptors(),
256 fitPar.getFitnessExpression(),
257 logger);
258
259 IAtomContainer mol = sp.parseSmiles("COc1ccccc1");
260
261 fp.getFitness(mol);
262
263 String[] expectedProps = new String[] {DENOPTIMConstants.FITNESSTAG,"Zagreb","taniBis",
264 "taniSym","aHyb_1","aHyb_2"};
265 double[] expectedValue = new double[] {
266 2.5689610, // fitness
267 34.000000, // Zagreb
268 0.4318000, // taniBis
269 0.6000000, // taniSym
270 2.1428571, // aHyb_1
271 3.0000000 // aHyb_2
272 };
273 for (int i=0; i<expectedProps.length; i++)
274 {
275 Object p = mol.getProperty(expectedProps[i]);
276 double value = Double.parseDouble(p.toString());
277 assertTrue(closeEnough(expectedValue[i], value),
278 "Value of property '" + expectedProps[i] + "' should be "
279 + expectedValue[i] + " but is " + value);
280 }
281 }
282
283//------------------------------------------------------------------------------
284
285 @Test
286 public void testGetConstantFitness() throws Exception
287 {
289 fitPar.interpretKeyword("FP-Equation=${1.23456}");
290 fitPar.processParameters();
291
293 fitPar.getDescriptors(),
294 fitPar.getFitnessExpression(),
295 logger);
296
297 IAtomContainer mol = sp.parseSmiles("COc1ccccc1");
298
299 fp.getFitness(mol);
300
301 Object prop = mol.getProperty(DENOPTIMConstants.FITNESSTAG);
302 assertTrue(prop != null, "Fitness property found in molecule");
303 assertTrue(closeEnough(1.23456, Double.parseDouble(prop.toString())),
304 "Numerical result (" + Double.parseDouble(prop.toString())
305 + ") is correct");
306 }
307
308//------------------------------------------------------------------------------
309
310 private boolean closeEnough(double expected, double actual)
311 {
312 double threshold = 0.0001;
313 double delta = Math.abs(expected-actual);
314 return delta < threshold;
315 }
316
317//------------------------------------------------------------------------------
318
319}
General set of constants used in DENOPTIM.
static final String FITNESSTAG
SDF tag containing the fitness of a candidate.
This is a reference to a specific descriptor value.
void addDependentVariable(Variable v)
Append the reference to a variable that used data produced by the calculation of this descriptor.
Settings defining the calculation of fitness.
void processParameters()
Processes all parameters and initialize related objects.
List< DescriptorForFitness > getDescriptors()
void interpretKeyword(String key, String value)
Processes a keyword/value pair and assign the related parameters.
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 getFitness(IAtomContainer iac)
Calculated the fitness according to the current configuration.
Unit test for internal fitness provider.
boolean closeEnough(double expected, double actual)
void testGetFitnessWithParametrizedDescriptors()
This test is reproducing most of what done in FitnessParametersTest#testProcessExpressions() so if bo...
A variable in the expression defining the fitness.
Definition: Variable.java:42
Calculates the molecular similarity against a target compound the fingerprint of which is given as pa...
Utility methods for input/output.
static void writeSDFFile(String fileName, IAtomContainer mol)
Writes IAtomContainer to SDF file.