% Register RDF namespaces, for use in the convenience methods at the end :- rdf_db:rdf_register_ns(nmr, 'http://www.nmrshiftdb.org/onto#'). :- rdf_db:rdf_register_ns(xsd, 'http://www.w3.org/2001/XMLSchema#'). findMolWithPeakValsNear( SearchShiftVals, Mols ) :- % Pick the Moleculess in 'Mol', that match the pattern: %% listPeakShiftsOfMol( Mol, MolShiftVals ), %% containsListElemsNear( SearchShiftVals, MolShiftVals ) % and collect them in 'Mols'. % % A Mol(ecule)'s shift values are collected and compared against the given % SearchShiftVals. Then, in 'Mols', all 'Mol's, for which their shift values % match the SearchShiftVals, are collected. setof( Mol, ( listPeakShiftsOfMol( Mol, MolShiftVals ), containsListElemsNear( SearchShiftVals, MolShiftVals )), [Mols|MolTail] ). % Given a 'Mol', give it's shiftvalues in list form, in 'ListOfPeaks' listPeakShiftsOfMol( Mol, ListOfPeaks ) :- hasSpectrum( Mol, Spectrum ), findall( ShiftVal, ( hasPeak( Spectrum, Peak ), hasShiftVal( Peak, ShiftVal ) ), ListOfPeaks ). % Compare two lists to see if list2 has near-matches for each value in list1 containsListElemsNear( [ElemHead|ElemTail], List ) :- memberCloseTo( ElemHead, List ), ( containsListElemsNear( ElemTail, List ); ElemTail == [] ). %%%%%%%%%%%%%%%%%%%%%%%% % Recursive construct: % %%%%%%%%%%%%%%%%%%%%%%%% % Test first the end criterion: memberCloseTo( X, [ Y | Tail ] ) :- closeTo( X, Y ). % but if the above doesn't validate, do recursively continue with the tail of List2: memberCloseTo( X, [ Y | Tail ] ) :- memberCloseTo( X, Tail ). % Numerical near-match closeTo( Val1, Val2 ) :- abs(Val1 - Val2) =< 0.3. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Convenience accessory methods % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% hasShiftVal( Peak, ShiftVal ) :- rdf_db:rdf( Peak, nmr:hasShift, literal(type(xsd:decimal, ShiftValLiteral))), atom_number_create( ShiftValLiteral, ShiftVal ). hasSpectrum( Subject, Predicate ) :- rdf_db:rdf( Subject, nmr:hasSpectrum, Predicate). hasPeak( Subject, Predicate ) :- rdf_db:rdf( Subject, nmr:hasPeak, Predicate). % Wrapper method for the atom_number/2 method which converts atoms (string % constants) to number. The wrapper methods avoids exceptions on empty atoms, % instead converting into a zero. atom_number_create( Atom, Number ) :- % IF atom is not empty atom_length( Atom, AtomLength ), AtomLength > 0 -> % THEN Convert the atom to a numerical value atom_number( Atom, Number ); % ELSE Convert to a zero atom_number( '0', Number ).