Skip to content

Commit

Permalink
Merge pull request #68 from EMMC-ASBL/proper-cost-function
Browse files Browse the repository at this point in the history
Proper cost function
  • Loading branch information
jesper-friis committed Jan 27, 2023
2 parents edfe936 + b1a1d3a commit a676c26
Showing 1 changed file with 35 additions and 13 deletions.
48 changes: 35 additions & 13 deletions tripper/mappings/mappings.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from pint import Quantity # remove

from tripper import DM, EMMO, FNO, MAP, RDF, RDFS
from tripper.utils import parse_literal

if TYPE_CHECKING: # pragma: no cover
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union
Expand Down Expand Up @@ -91,7 +92,7 @@ def __init__(
):
self.value = value
self.unit = unit
self.iri = iri
self.output_iri = iri
self.property_iri = property_iri
self.cost = cost

Expand All @@ -117,7 +118,7 @@ def show(
strings = []
ind = " " * indent
strings.append(ind + f'{name if name else "Value"}:')
strings.append(ind + f" iri: {self.iri}")
strings.append(ind + f" iri: {self.output_iri}")
strings.append(ind + f" property_iri: {self.property_iri}")
strings.append(ind + f" unit: {self.unit}")
strings.append(ind + f" cost: {self.cost}")
Expand All @@ -138,9 +139,11 @@ class MappingStep:
steptype: One of the step types from the StepType enum.
function: Callable that evaluates the output from the input.
cost: The cost related to this mapping step. Should be either a
float or a callable taking the same arguments as `function` as
input returning the cost as a float.
float or a callable taking three arguments (`triplestore`,
`input_iris` and `output_iri`) and return the cost as a float.
output_unit: Output unit.
triplestore: Triplestore instance containing the knowledge base
that this mapping step was created from.
The arguments can also be assigned as attributes.
"""
Expand All @@ -154,11 +157,13 @@ def __init__(
function: "Optional[Callable]" = None,
cost: "Union[float, Callable]" = 1.0,
output_unit: "Optional[str]" = None,
triplestore: "Optional[Triplestore]" = None,
) -> None:
self.output_iri = output_iri
self.steptype = steptype
self.function = function
self.cost = cost
self.triplestore = triplestore
self.output_unit = output_unit
self.input_routes: "List[dict]" = [] # list of inputs dicts
self.join_mode = False # whether to join upcoming input
Expand Down Expand Up @@ -265,7 +270,7 @@ def get_input_iris(self, routeno: int) -> "Dict[str, Optional[str]]":
"""
inputs, _ = self.get_inputs(routeno)
return {
k: v.output_iri if isinstance(v, MappingStep) else v.iri
k: v.output_iri if isinstance(v, MappingStep) else v.output_iri
for k, v in inputs.items()
}

Expand Down Expand Up @@ -350,8 +355,9 @@ def lowest_costs(self, nresults: int = 5) -> "List[Tuple[float, int]]":
# mapping step.
if callable(self.cost):
for i, rno in enumerate(base.routeno):
values = get_values(inputs, rno, magnitudes=True)
owncost = self.cost(**values)
inputs, _ = self.get_inputs(rno)
input_iris = [input.output_iri for input in inputs.values()]
owncost = self.cost(self.triplestore, input_iris, self.output_iri)
base.cost[i] += owncost
else:
owncost = self.cost
Expand Down Expand Up @@ -654,7 +660,9 @@ def getcost(target, stepname):
cost = soCost.get(target, default_costs[stepname])
if cost is None:
return None
return function_repo[cost] if cost in function_repo else float(cost)
return (
function_repo[cost] if cost in function_repo else float(parse_literal(cost))
)

def walk(target, visited, step):
"""Walk backward in rdf graph from `node` to sources."""
Expand All @@ -677,7 +685,11 @@ def addnode(node, steptype, stepname):
)
step.add_input(value, name=soName.get(node))
else:
prevstep = MappingStep(output_iri=node, output_unit=soUnit.get(node))
prevstep = MappingStep(
output_iri=node,
output_unit=soUnit.get(node),
triplestore=triplestore,
)
step.add_input(prevstep, name=soName.get(node))
walk(node, visited, prevstep)

Expand All @@ -697,18 +709,24 @@ def addnode(node, steptype, stepname):
for func, input_iris in fmap(triplestore)[target]:
step.steptype = StepType.FUNCTION
step.cost = getcost(func, "function")
step.function = function_repo[func]
step.function = function_repo.get(func)
step.join_mode = True
for input_iri in input_iris:
step0 = MappingStep(
output_iri=input_iri, output_unit=soUnit.get(input_iri)
output_iri=input_iri,
output_unit=soUnit.get(input_iri),
triplestore=triplestore,
)
step.add_input(step0, name=soName.get(input_iri))
walk(input_iri, visited, step0)
step.join_input()

visited = set()
step = MappingStep(output_iri=target, output_unit=soUnit.get(target))
step = MappingStep(
output_iri=target,
output_unit=soUnit.get(target),
triplestore=triplestore,
)
if target in soInst:
# It is only initially we want to follow instanceOf in forward
# direction. Later on we will only follow mapsTo and instanceOf in
Expand All @@ -717,7 +735,11 @@ def addnode(node, steptype, stepname):
source = soInst[target]
step.steptype = StepType.INSTANCEOF
step.cost = getcost(source, "instanceOf")
step0 = MappingStep(output_iri=source, output_unit=soUnit.get(source))
step0 = MappingStep(
output_iri=source,
output_unit=soUnit.get(source),
triplestore=triplestore,
)
step.add_input(step0, name=soName.get(target))
step = step0
target = source
Expand Down

0 comments on commit a676c26

Please sign in to comment.