Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proper cost function #68

Merged
merged 5 commits into from
Jan 27, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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