Skip to content
Merged
Show file tree
Hide file tree
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
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased] - 2022-02-15
## [Unreleased] - 2022-02-17

### Added

Expand All @@ -21,6 +21,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Other


## [3.1.1] - 2022-02-17

### Fixed
* Fixed inefficient memory usage in KendallTauDistance (issue #183)
* Fixed inefficient memory usage in KendallTauSequenceDistance (issue #184)
* Fixed inefficient memory usage in WeightedKendallTauDistance (issue #185)
* Fixed inefficiency in WeightedKendallTauDistance related to redundant computation (issue #182)


## [3.1.0] - 2022-02-15

### Added
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright 2014, 2015, 2017-2022 Vincent A. Cicirello, <https://www.cicirello.org/>.
* JavaPermutationTools: A Java library for computation on permutations and sequences.
* Copyright (C) 2014, 2015, 2017-2022 Vincent A. Cicirello, <https://www.cicirello.org/>.
*
* This file is part of JavaPermutationTools (https://jpt.cicirello.org/).
*
Expand Down Expand Up @@ -74,7 +75,7 @@ public int distance(Permutation p1, Permutation p2) {
for (int i = 0; i < arrayP2.length; i++) {
arrayP2[i] = invP1[p2.get(i)];
}
return countInversions(arrayP2);
return countInversions(arrayP2, 0, arrayP2.length-1);
}

@Override
Expand All @@ -83,15 +84,21 @@ public int max(int length) {
return (length*(length - 1))>>1;
}

private int countInversions(int[] array) {
if (array.length <= 1) return 0;
int m = array.length >> 1;
int[] left = Arrays.copyOfRange(array, 0, m);
int[] right = Arrays.copyOfRange(array, m, array.length);
int count = countInversions(left) + countInversions(right);
private int countInversions(int[] array, int first, int last) {
if (last <= first) {
return 0;
}
int m = (first + last) >> 1;
return countInversions(array, first, m) + countInversions(array, m+1, last) + merge(array, first, m+1, last+1);
}

private int merge(int[] array, int first, int midPlus, int lastPlus) {
int[] left = Arrays.copyOfRange(array, first, midPlus);
int[] right = Arrays.copyOfRange(array, midPlus, lastPlus);
int i = 0;
int j = 0;
int k = 0;
int k = first;
int count = 0;
while (i < left.length && j < right.length) {
if (left[i] < right[j]) {
array[k] = left[i];
Expand All @@ -117,5 +124,4 @@ private int countInversions(int[] array) {
}
return count;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public double distancef(Permutation p1, Permutation p2) {
w[arrayP2[i]] = weights[p2.get(i)];
}

return countWeightedInversions(arrayP2, w);
return countWeightedInversions(arrayP2, w, 0, arrayP2.length-1);
}

/**
Expand All @@ -115,26 +115,33 @@ public double maxf(int length) {
return maxDistance;
}

private double countWeightedInversions(int[] array, double[] w) {
if (array.length <= 1) return 0;
int m = array.length >> 1;
int[] left = Arrays.copyOfRange(array, 0, m);
int[] right = Arrays.copyOfRange(array, m, array.length);
double weightedCount = countWeightedInversions(left, w) + countWeightedInversions(right, w);
private double countWeightedInversions(int[] array, double[] w, int first, int last) {
if (last <= first) {
return 0;
}
int m = (first + last) >> 1;
return countWeightedInversions(array, w, first, m) + countWeightedInversions(array, w, m+1, last) + merge(array, w, first, m+1, last+1);
}

private double merge(int[] array, double[] w, int first, int midPlus, int lastPlus) {
int[] left = Arrays.copyOfRange(array, first, midPlus);
int[] right = Arrays.copyOfRange(array, midPlus, lastPlus);
int i = 0;
int j = 0;
int k = 0;
int k = first;
double weightedCount = 0;
double leftWeights = 0;
for (int x = 0; x < left.length; x++) {
leftWeights += w[left[x]];
}
while (i < left.length && j < right.length) {
if (left[i] < right[j]) {
leftWeights -= w[left[i]];
array[k] = left[i];
i++;
k++;
} else {
// inversions
double leftWeights = 0;
for (int x = i; x < left.length; x++) {
leftWeights += w[left[x]];
}
weightedCount += w[right[j]] * leftWeights;
array[k] = right[j];
j++;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright 2018-2021 Vincent A. Cicirello, <https://www.cicirello.org/>.
* JavaPermutationTools: A Java library for computation on permutations and sequences.
* Copyright (C) 2018-2021 Vincent A. Cicirello, <https://www.cicirello.org/>.
*
* This file is part of JavaPermutationTools (https://jpt.cicirello.org/).
*
Expand Down Expand Up @@ -76,7 +77,6 @@
* Industrial Networks and Intelligent Systems, 7(23), Article e1, April 2020.</p>
*
* @author <a href=https://www.cicirello.org/ target=_top>Vincent A. Cicirello</a>, <a href=https://www.cicirello.org/ target=_top>https://www.cicirello.org/</a>
* @version 5.13.2021
*/
public final class KendallTauSequenceDistance implements SequenceDistanceMeasurer {

Expand Down Expand Up @@ -128,7 +128,7 @@ public int distance(int[] s1, int[] s2) {
int numLabels = USE_HASHMAP ? relabelElementsWithHash(s1,s2,relabeling) : relabelElements(s1,s2,relabeling);
Bucket[][] buckets = bucketSortElements(relabeling, numLabels);
int[] mapping = mapElements(buckets, relabeling.length);
return countInversions(mapping);
return countInversions(mapping, 0, mapping.length-1);
}

/**
Expand All @@ -144,7 +144,7 @@ public int distance(long[] s1, long[] s2) {
int numLabels = USE_HASHMAP ? relabelElementsWithHash(s1,s2,relabeling) : relabelElements(s1,s2,relabeling);
Bucket[][] buckets = bucketSortElements(relabeling, numLabels);
int[] mapping = mapElements(buckets, relabeling.length);
return countInversions(mapping);
return countInversions(mapping, 0, mapping.length-1);
}

/**
Expand All @@ -160,7 +160,7 @@ public int distance(short[] s1, short[] s2) {
int numLabels = USE_HASHMAP ? relabelElementsWithHash(s1,s2,relabeling) : relabelElements(s1,s2,relabeling);
Bucket[][] buckets = bucketSortElements(relabeling, numLabels);
int[] mapping = mapElements(buckets, relabeling.length);
return countInversions(mapping);
return countInversions(mapping, 0, mapping.length-1);
}

/**
Expand All @@ -176,7 +176,7 @@ public int distance(byte[] s1, byte[] s2) {
int numLabels = USE_HASHMAP ? relabelElementsWithHash(s1,s2,relabeling) : relabelElements(s1,s2,relabeling);
Bucket[][] buckets = bucketSortElements(relabeling, numLabels);
int[] mapping = mapElements(buckets, relabeling.length);
return countInversions(mapping);
return countInversions(mapping, 0, mapping.length-1);
}

/**
Expand All @@ -192,7 +192,7 @@ public int distance(char[] s1, char[] s2) {
int numLabels = USE_HASHMAP ? relabelElementsWithHash(s1,s2,relabeling) : relabelElements(s1,s2,relabeling);
Bucket[][] buckets = bucketSortElements(relabeling, numLabels);
int[] mapping = mapElements(buckets, relabeling.length);
return countInversions(mapping);
return countInversions(mapping, 0, mapping.length-1);
}

/**
Expand All @@ -208,7 +208,7 @@ public int distance(String s1, String s2) {
int numLabels = USE_HASHMAP ? relabelElementsWithHash(s1,s2,relabeling) : relabelElements(s1,s2,relabeling);
Bucket[][] buckets = bucketSortElements(relabeling, numLabels);
int[] mapping = mapElements(buckets, relabeling.length);
return countInversions(mapping);
return countInversions(mapping, 0, mapping.length-1);
}

/**
Expand All @@ -224,7 +224,7 @@ public int distance(float[] s1, float[] s2) {
int numLabels = USE_HASHMAP ? relabelElementsWithHash(s1,s2,relabeling) : relabelElements(s1,s2,relabeling);
Bucket[][] buckets = bucketSortElements(relabeling, numLabels);
int[] mapping = mapElements(buckets, relabeling.length);
return countInversions(mapping);
return countInversions(mapping, 0, mapping.length-1);
}

/**
Expand All @@ -240,7 +240,7 @@ public int distance(double[] s1, double[] s2) {
int numLabels = USE_HASHMAP ? relabelElementsWithHash(s1,s2,relabeling) : relabelElements(s1,s2,relabeling);
Bucket[][] buckets = bucketSortElements(relabeling, numLabels);
int[] mapping = mapElements(buckets, relabeling.length);
return countInversions(mapping);
return countInversions(mapping, 0, mapping.length-1);
}

/**
Expand All @@ -256,7 +256,7 @@ public int distance(boolean[] s1, boolean[] s2) {
int numLabels = relabelElements(s1,s2,relabeling);
Bucket[][] buckets = bucketSortElements(relabeling, numLabels);
int[] mapping = mapElements(buckets, relabeling.length);
return countInversions(mapping);
return countInversions(mapping, 0, mapping.length-1);
}

/**
Expand All @@ -277,7 +277,7 @@ public int distance(Object[] s1, Object[] s2) {

Bucket[][] buckets = bucketSortElements(relabeling, numLabels);
int[] mapping = mapElements(buckets, relabeling.length);
return countInversions(mapping);
return countInversions(mapping, 0, mapping.length-1);
}

/**
Expand All @@ -296,7 +296,7 @@ public <T> int distance(List<T> s1, List<T> s2) {

Bucket[][] buckets = bucketSortElements(relabeling, numLabels);
int[] mapping = mapElements(buckets, relabeling.length);
return countInversions(mapping);
return countInversions(mapping, 0, mapping.length-1);
}

private int[] mapElements(Bucket[][] buckets, int seqLength) {
Expand Down Expand Up @@ -752,15 +752,21 @@ private int relabelElements(List<Comparable> s1, List<Comparable> s2, int[][] re
}

// assumes all unique elements
private int countInversions(int[] array) {
if (array.length <= 1) return 0;
int m = array.length / 2;
int[] left = Arrays.copyOfRange(array, 0, m);
int[] right = Arrays.copyOfRange(array, m, array.length);
int count = countInversions(left) + countInversions(right);
private int countInversions(int[] array, int first, int last) {
if (last <= first) {
return 0;
}
int m = (first + last) >> 1;
return countInversions(array, first, m) + countInversions(array, m+1, last) + merge(array, first, m+1, last+1);
}

private int merge(int[] array, int first, int midPlus, int lastPlus) {
int[] left = Arrays.copyOfRange(array, first, midPlus);
int[] right = Arrays.copyOfRange(array, midPlus, lastPlus);
int i = 0;
int j = 0;
int k = 0;
int k = first;
int count = 0;
while (i < left.length && j < right.length) {
if (left[i] <= right[j]) {
array[k] = left[i];
Expand All @@ -787,6 +793,7 @@ private int countInversions(int[] array) {
return count;
}


// internal data structures below

private static final class Bucket {
Expand Down