All Downloads are FREE. Search and download functionalities are using the official Maven repository.

au.csiro.pathling.terminology.Relation Maven / Gradle / Ivy

There is a newer version: 7.0.1
Show newest version
/*
 * Copyright 2022 Commonwealth Scientific and Industrial Research
 * Organisation (CSIRO) ABN 41 687 119 230.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package au.csiro.pathling.terminology;

import au.csiro.pathling.fhirpath.encoding.SimpleCoding;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
import lombok.ToString;

/**
 * Represents relation between codings with implicit coding equality.
 * 

* Implicitly two codings that are equal are related. It may be a transitive or non-transitive * relation depending on the construction, i.e: the creator is responsible for explicitly defining * all related pairs for transitive closure (except of the equality). * * @author Piotr Szul */ @ToString @EqualsAndHashCode public class Relation implements Serializable { private static final long serialVersionUID = -8124924480216379884L; /** * An entry representing the existence of relation between {@code form} and {@code to}. */ @Data @AllArgsConstructor(staticName = "of") public static class Entry implements Serializable { private static final long serialVersionUID = 1L; @NonNull private final SimpleCoding from; @NonNull private final SimpleCoding to; } /** * Set of codings with contains() following the coding's equivalence semantics. * * @author Piotr Szul */ static class CodingSet { @Nonnull private final Set allCodings; @Nonnull private final Set unversionedCodings; CodingSet(@Nonnull final Set allCodings) { this.allCodings = allCodings; this.unversionedCodings = allCodings.stream().map(SimpleCoding::toNonVersioned).collect(Collectors.toSet()); } /** * Belongs to set operation with the coding's equivalence semantics, i.e. if the set includes an * unversioned coding, it contains any versioned coding with the same system code, and; if a set * contains a versioned coding, it contains its corresponding unversioned coding as well. * * @param c coding */ boolean contains(@Nonnull final SimpleCoding c) { return allCodings.contains(c) || (c.isVersioned() ? allCodings.contains(c.toNonVersioned()) : unversionedCodings.contains(c)); } } @Nonnull private final Map> mappings; /** * Private constructor. Use {@link #equality()} or {@link #fromMappings} to create instances. */ private Relation(@Nonnull final Map> mappings) { this.mappings = mappings; } /** * Expands given set of Codings using with the closure, that is produces a set of Codings that are * in the relation with the given set. */ @Nonnull private Set expand(@Nonnull final Set codings) { final Relation.CodingSet baseSet = new Relation.CodingSet(codings); return Stream .concat(codings.stream(), mappings.entrySet().stream() .filter(kv -> baseSet.contains(kv.getKey())).flatMap(kv -> kv.getValue().stream())) .collect(Collectors.toSet()); } /** * Checks if any of the Codings in the right set is in the relation with any of the Codings in the * left set. * * @param left a collections of codings. * @param right a collection of codings. * @return true if any left coding is related to any right coding. */ public boolean anyRelates(@Nonnull final Collection left, @Nonnull final Collection right) { // filter out null SystemAndCodes final Set leftSet = left.stream().filter(SimpleCoding::isDefined).collect(Collectors.toSet()); final Relation.CodingSet expansion = new Relation.CodingSet(expand(leftSet)); return right.stream().anyMatch(expansion::contains); } /** * Constructs relation from given list of related pairs of codings. *

* The relation is assumed to include coding equality so {@code (A,A)} is assumed. All other the * related pairs need to be explicitly listed. If the relation is meant to represent a transitive * closure with implicit equality such that: {@code A -> B -> C} then the entry list must include * the all pairs of: {@code [(A,B), (B,C), (A, C)]}. * * @param entries the list of pair of codings that are related. * @return the relation instance. */ @Nonnull public static Relation fromMappings(@Nonnull final Collection entries) { final Map> groupedMappings = entries.stream().collect(Collectors.groupingBy(Entry::getFrom)); final Map> groupedCodings = groupedMappings.entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().stream() .map(Entry::getTo) .collect(Collectors.toList()))); return new Relation(groupedCodings); } /** * Constructs a relation that only includes coding equality. * * @return the equality relation instance. */ @Nonnull public static Relation equality() { return new Relation(Collections.emptyMap()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy