pax_global_header 0000666 0000000 0000000 00000000064 15101666221 0014512 g ustar 00root root 0000000 0000000 52 comment=0c1dacc8cef350ddc18bf0029bf16bcbf7287a39
euclid-euclid-2.13/ 0000775 0000000 0000000 00000000000 15101666221 0014147 5 ustar 00root root 0000000 0000000 euclid-euclid-2.13/.github/ 0000775 0000000 0000000 00000000000 15101666221 0015507 5 ustar 00root root 0000000 0000000 euclid-euclid-2.13/.github/workflows/ 0000775 0000000 0000000 00000000000 15101666221 0017544 5 ustar 00root root 0000000 0000000 euclid-euclid-2.13/.github/workflows/maven.yml 0000664 0000000 0000000 00000001713 15101666221 0021377 0 ustar 00root root 0000000 0000000 name: Java CI with Maven
on:
push:
pull_request:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
java: [ 8, 11, 17, 21, 25 ]
name: Java ${{ matrix.java }}
steps:
- uses: actions/checkout@v4
- name: Set up Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: ${{ matrix.java }}
- name: Build with Maven
run: mvn clean install -Dgpg.skip -Dmaven.javadoc.skip=true
coverage:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- name: Set up Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 8
- name: Build with Maven
run: mvn clean install -Dgpg.skip -Dmaven.javadoc.skip=true -Dmaven.test.failure.ignore=true
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
euclid-euclid-2.13/.gitignore 0000664 0000000 0000000 00000000172 15101666221 0016137 0 ustar 00root root 0000000 0000000 foo
.project
.settings/
.classpath
^.hgignore~$
^.gitignore~$
^target/.*
target/
# IntelliJ Idear files
/.idea/*
**/*.iml
euclid-euclid-2.13/CITATION.cff 0000664 0000000 0000000 00000001044 15101666221 0016040 0 ustar 00root root 0000000 0000000 cff-version: 1.2.0
message: "If you use this software, please cite it as below."
title: Euclid
version: 2.13
date-released: 2025-11-02
url: "https://github.com/BlueObelisk/euclid"
preferred-citation:
type: article
authors:
- family-names: Murray-Rust
given-names: Peter
- family-names: Rzepa
given-names: Henry S.
title: "CML: Evolution and design"
year: 2011
month: 10
day: 14
journal: Journal of Cheminformatics
volume: 3
issue: 44
doi: 10.1186/1758-2946-3-44
url: https://doi.org/10.1186/1758-2946-3-44
euclid-euclid-2.13/LICENSE.txt 0000664 0000000 0000000 00000026135 15101666221 0016001 0 ustar 00root root 0000000 0000000 Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
euclid-euclid-2.13/README.md 0000664 0000000 0000000 00000002327 15101666221 0015432 0 ustar 00root root 0000000 0000000 # CML Euclid
[](https://maven-badges.herokuapp.com/maven-central/org.blueobelisk/euclid)
[](https://github.com/BlueObelisk/euclid/actions/workflows/maven.yml)
[](https://doi.org/10.5281/zenodo.5815148)
[](https://codecov.io/gh/BlueObelisk/euclid)
A library of numeric, geometric and XML routines
Euclid was written ca. 1994 as Java had no useful libraries then. Much of the
functionality is now present in Apache and other libraries and in an ideal world
Euclid maths and geometry could be replaced. However, there are additions that are valuable.
It's used a lot in CML tools (JUMBO, JUMBO-converters) and also AMI (for extracting semantics from PDFs).
## Releases
Instructions to increase the version:
```shell
mvn versions:set -DnewVersion=2.14-SNAPSHOT
```
Deploy to Sonatype with the following commands, for snapshots and releases respectively:
```shell
mvn clean deploy
```
euclid-euclid-2.13/pom.xml 0000664 0000000 0000000 00000027240 15101666221 0015471 0 ustar 00root root 0000000 0000000 4.0.0org.blueobeliskeuclid2.13jarUTF-8UTF-8CML EuclidA Java library for 2D and 3D geometric calculationshttps://github.com/BlueObelisk/euclidApache License, Version 2.0http://www.apache.org/licenses/LICENSE-2.0.txtrepohttps://github.com/BlueObelisk/euclidscm:git:git://github.com/blueobelisk/euclid.gitscm:git:ssh://git@github.com/blueobelisk/euclid.gitHEADpm286Peter Murray-Rust1994cml-discusshttps://lists.sourceforge.net/lists/listinfo/cml-discuss
https://lists.sourceforge.net/lists/listinfo/cml-discuss
http://sourceforge.net/mailarchive/forum.php?forum_name=cml-discuss
centralhttps://central.sonatype.com/repository/maven-snapshots/centralhttps://central.sonatype.comPeter Murray-Rusthttp://wwmm.ch.cam.ac.uk/blogs/murrayrust/ org.apache.maven.pluginsmaven-enforcer-plugin3.6.1enforce-mavenenforce3.6.31.8org.apache.maven.pluginsmaven-compiler-plugin3.14.01.81.8org.apache.maven.pluginsmaven-javadoc-plugin3.11.3attach-javadocsjaraggregateaggregatesitemaven-source-plugin3.3.1attach-sourcesjar-no-forkorg.codehaus.mojocobertura-maven-plugin2.7falseorg.xmlcml.*8080org/xmlcml/**/*.classcleanpre-sitecleaninstrumentsiteinstrumentcoberturacheckcom.mycila.maven-license-pluginmaven-license-plugin1.10.b1src/main/resources/header.txt.travis.yml.gitignoreREADME.mdLICENSE.***/READMEsrc/test/resources/org/xmlcml/files/**src/*/java/blogspot/software_and_algorithms/stern_library/****/*.java-old**/junk.idea/**org.sonatype.centralcentral-publishing-maven-plugin0.8.0truecentraltruepublishedorg.apache.maven.pluginsmaven-gpg-plugin3.2.8sign-artifactsverifysignorg.jacocojacoco-maven-plugin0.8.13start-agentprepare-agentgenerate-reportreportjunitjunit4.13.2commons-iocommons-io2.20.0org.apache.logging.log4jlog4j2.25.2pomorg.apache.logging.log4jlog4j-1.2-api2.25.2org.apache.logging.log4jlog4j-core2.25.2org.apache.commonscommons-lang33.19.0org.apache.commonscommons-math2.2joda-timejoda-time2.14.0xomxom1.3.9xercesxercesImplreleasemaven-assembly-plugin3.7.1srcorg.apache.maven.pluginsmaven-project-info-reports-plugin3.9.0indexsummarydependenciesproject-teamlicensecimscmorg.apache.maven.pluginsmaven-javadoc-pluginorg.apache.maven.pluginsmaven-surefire-report-plugin3.5.3org.apache.maven.pluginsmaven-jxr-plugin3.6.0org.apache.maven.pluginsmaven-pmd-plugin3.27.01.8trueorg.apache.maven.pluginsmaven-checkstyle-plugin3.6.0src/test/resources/checkstyle.xml
org.codehaus.mojocobertura-maven-pluginorg.codehaus.mojoapt-maven-plugin1.0-alpha-5
euclid-euclid-2.13/src/ 0000775 0000000 0000000 00000000000 15101666221 0014736 5 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/ 0000775 0000000 0000000 00000000000 15101666221 0015662 5 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/java/ 0000775 0000000 0000000 00000000000 15101666221 0016603 5 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/java/blogspot/ 0000775 0000000 0000000 00000000000 15101666221 0020434 5 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/java/blogspot/software_and_algorithms/ 0000775 0000000 0000000 00000000000 15101666221 0025341 5 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/java/blogspot/software_and_algorithms/stern_library/ 0000775 0000000 0000000 00000000000 15101666221 0030220 5 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/java/blogspot/software_and_algorithms/stern_library/data_structure/ 0000775 0000000 0000000 00000000000 15101666221 0033251 5 ustar 00root root 0000000 0000000 DynamicIntervalTree.java 0000664 0000000 0000000 00000024116 15101666221 0037752 0 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/java/blogspot/software_and_algorithms/stern_library/data_structure package blogspot.software_and_algorithms.stern_library.data_structure;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import blogspot.software_and_algorithms.stern_library.data_structure.RedBlackTree.Node.NodeColor;
/* Copyright (c) 2012 Kevin L. Stern
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* A dynamic interval tree is a balanced binary search tree which
* stores intervals so that both point queries (queries that return intervals
* from the set which contain a query point) and overlapping interval queries
* (queries that return intervals from the set which overlap a query interval)
* can be completed in time O(k*log(n)), where n is the number of intervals
* stored in the tree and k is the size of the result set from the query.
*
* Insertion and deletion of intervals to and from this tree completes in time
* O(log(n)) where n is the number of intervals stored in the tree.
*
* This tree consumes linear space in the number of intervals stored in the
* tree.
*
* Note that this implementation supports all three closed, open and half-open
* intervals.
*
* @author Kevin L. Stern
*/
public class DynamicIntervalTree, T extends Interval> {
public RedBlackTree binarySearchTree = new RedBlackTree(
new Comparator() {
@Override
public int compare(T o1, T o2) {
int result = o1.getLow().compareTo(o2.getLow());
if (result == 0) {
if (o1.isClosedOnLow() != o2.isClosedOnLow()) {
result = o1.isClosedOnLow() ? -1 : 1;
} else {
result = o1.compareTo(o2);
}
}
return result;
}
}) {
@Override
protected RedBlackTree.Node createNewNode(T value) {
return new DynamicIntervalTree.Node(value);
}
@Override
public RedBlackTree.Node delete(T value) {
RedBlackTree.Node node = super.delete(value);
if (node != null && node.getColor() != NodeColor.BLACK) {
DynamicIntervalTree.Node temp = (DynamicIntervalTree.Node) node
.getParent();
while (temp != null) {
temp.computeMaximumHighEndpoint();
temp = temp.getParent();
}
}
return node;
}
@Override
protected void fixAfterDeletion(RedBlackTree.Node node) {
DynamicIntervalTree.Node temp = (DynamicIntervalTree.Node) node
.getParent();
while (temp != null) {
temp.computeMaximumHighEndpoint();
temp = temp.getParent();
}
super.fixAfterDeletion(node);
}
@Override
protected void fixAfterInsertion(RedBlackTree.Node node) {
DynamicIntervalTree.Node temp = (DynamicIntervalTree.Node) node
.getParent();
while (temp != null) {
temp.computeMaximumHighEndpoint();
temp = temp.getParent();
}
super.fixAfterInsertion(node);
}
@Override
protected void leftRotate(RedBlackTree.Node node) {
super.leftRotate(node);
DynamicIntervalTree.Node temp = (DynamicIntervalTree.Node) node;
temp.computeMaximumHighEndpoint();
temp.getParent().computeMaximumHighEndpoint();
}
@Override
protected void rightRotate(RedBlackTree.Node node) {
super.rightRotate(node);
DynamicIntervalTree.Node temp = (DynamicIntervalTree.Node) node;
temp.computeMaximumHighEndpoint();
temp.getParent().computeMaximumHighEndpoint();
}
};
/**
* Clear the contents of the tree.
*/
public void clear() {
binarySearchTree.clear();
}
/**
* Delete the specified interval from this tree.
*
* @param interval
* the interval to delete.
* @return true if an element was deleted as a result of this call, false
* otherwise.
*/
public boolean delete(T interval) {
return binarySearchTree.delete(interval) != null;
}
/**
* Fetch an interval containing the specified point.
*
* @param queryPoint
* the query point.
* @return an interval containing the specified point, null if none.
*/
protected T fetchContainingInterval(U queryPoint) {
Node node = (Node) binarySearchTree.getRoot();
while (node != null) {
if (node.getValue().contains(queryPoint)) {
return node.getValue();
}
Node leftChild = node.getLeft();
node = node.getRight();
if (leftChild != null) {
int cmp = leftChild.getMaximumHighEndpoint().compareTo(
queryPoint);
if (cmp > 0 || cmp == 0 && leftChild.isClosedOnEndpoint()) {
node = leftChild;
}
}
}
return null;
}
/**
* Fetch intervals containing the specified point.
*
* @param queryPoint
* the query point.
* @return a Collection of all intervals containing the specified point.
*/
public Collection fetchContainingIntervals(U queryPoint) {
if (queryPoint == null) {
throw new NullPointerException("queryPoint is null");
}
List result = new ArrayList();
T interval;
while ((interval = fetchContainingInterval(queryPoint)) != null) {
result.add(interval);
delete(interval);
}
for (T next : result) {
insert(next);
}
return result;
}
/**
* Fetch an interval overlapping the specified interval.
*
* @param queryInterval
* the query interval.
* @return an interval overlapping the specified interval, null if none.
*/
protected T fetchOverlappingInterval(T queryInterval) {
Node node = (Node) binarySearchTree.getRoot();
while (node != null) {
if (node.getValue().overlaps(queryInterval)) {
return node.getValue();
}
Node leftChild = node.getLeft();
node = node.getRight();
if (leftChild != null) {
int cmp = leftChild.getMaximumHighEndpoint().compareTo(
queryInterval.getLow());
if (cmp > 0 || cmp == 0 && leftChild.isClosedOnEndpoint()
&& queryInterval.isClosedOnLow()) {
node = leftChild;
}
}
}
return null;
}
/**
* Fetch intervals overlapping the specified interval.
*
* @param queryInterval
* the query interval.
* @return a Collection of all intervals overlapping the specified point.
*/
public Collection fetchOverlappingIntervals(T queryInterval) {
if (queryInterval == null) {
throw new NullPointerException("queryInterval is null");
}
List result = new ArrayList();
T interval;
while ((interval = fetchOverlappingInterval(queryInterval)) != null) {
result.add(interval);
delete(interval);
}
for (T next : result) {
insert(next);
}
return result;
}
/**
* Get the number of intervals being stored in the tree.
*
* @return the number of intervals being stored in the tree.
*/
public int getSize() {
return binarySearchTree.getSize();
}
/**
* Insert the specified interval into this tree.
*
* @param interval
* the interval to insert.
* @return true if an element was inserted as a result of this call, false
* otherwise.
*/
public boolean insert(T interval) {
return binarySearchTree.insert(interval) != null;
}
/**
* A node for a dynamic interval tree is a red-black tree node
* augmented to store the maximum high endpoint among intervals stored
* within the subtree rooted at the node.
*/
protected static class Node, T extends Interval>
extends RedBlackTree.Node {
private U maximumHighEndpoint;
private boolean isClosedOnEndpoint;
/**
* Construct a new node associated with the specified interval.
*
* @param interval
* the interval with which this node is associated.
*/
public Node(T interval) {
super(interval);
maximumHighEndpoint = interval.getHigh();
isClosedOnEndpoint = interval.isClosedOnHigh();
}
/**
* Compute the maximum high endpoint among intervals stored within the
* subtree rooted at this node and correct values up the tree.
*/
protected void computeMaximumHighEndpoint() {
U maximumHighEndpoint = getValue().getHigh();
boolean isClosedOnEndpoint = getValue().isClosedOnHigh();
Node child;
child = getLeft();
if (child != null) {
int cmp = child.maximumHighEndpoint
.compareTo(maximumHighEndpoint);
if (cmp > 0 || cmp == 0 && child.isClosedOnEndpoint) {
maximumHighEndpoint = child.maximumHighEndpoint;
isClosedOnEndpoint = child.isClosedOnEndpoint;
}
}
child = getRight();
if (child != null) {
int cmp = child.maximumHighEndpoint
.compareTo(maximumHighEndpoint);
if (cmp > 0 || cmp == 0 && child.isClosedOnEndpoint) {
maximumHighEndpoint = child.maximumHighEndpoint;
isClosedOnEndpoint = child.isClosedOnEndpoint;
}
}
this.maximumHighEndpoint = maximumHighEndpoint;
this.isClosedOnEndpoint = isClosedOnEndpoint;
}
/**
* {@inheritDoc}
*/
@Override
public Node getLeft() {
return (Node) super.getLeft();
}
public U getMaximumHighEndpoint() {
return maximumHighEndpoint;
}
/**
* {@inheritDoc}
*/
@Override
public Node getParent() {
return (Node) super.getParent();
}
/**
* {@inheritDoc}
*/
@Override
public Node getRight() {
return (Node) super.getRight();
}
public boolean isClosedOnEndpoint() {
return isClosedOnEndpoint;
}
}
}
Interval.java 0000664 0000000 0000000 00000015532 15101666221 0035627 0 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/java/blogspot/software_and_algorithms/stern_library/data_structure package blogspot.software_and_algorithms.stern_library.data_structure;
/* Copyright (c) 2012 Kevin L. Stern
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* An interval is the subset of elements which fall between (with
* respect to a total order) two endpoint elements of a set. An interval that
* contains its endpoints is closed, an interval that contains one of
* its endpoints but not the other is half open and an interval that
* does not contain either of its endpoints is open. This class
* encapsulates the concept of an interval and uses a class's natural order.
*
* @author Kevin L. Stern
*/
public class Interval> implements
Comparable> {
private T low, high;
private boolean isClosedOnLow, isClosedOnHigh;
private int hashCode = 0;
/**
* Construct a new instance with the specified low and high endpoints.
*
* @param low
* the low endpoint.
* @param isClosedOnLow
* true if this interval contains its low endpoint, false
* otherwise.
* @param high
* the high endpoint.
* @param isClosedOnHigh
* true if this interval contains its high endpoint, false
* otherwise.
*/
public Interval(T low, boolean isClosedOnLow, T high, boolean isClosedOnHigh) {
if (low == null) {
throw new NullPointerException("low endpoint is null");
} else if (high == null) {
throw new NullPointerException("high endpoint is null");
}
this.low = low;
this.isClosedOnLow = isClosedOnLow;
this.high = high;
this.isClosedOnHigh = isClosedOnHigh;
}
/**
* {@inheritDoc}
*/
@Override
public int compareTo(Interval o) {
int result = low.compareTo(o.low);
if (result == 0) {
if (isClosedOnLow != o.isClosedOnLow) {
result = isClosedOnLow ? -1 : 1;
} else {
result = high.compareTo(o.high);
if (result == 0) {
if (isClosedOnHigh != o.isClosedOnHigh) {
result = isClosedOnHigh ? -1 : 1;
}
}
}
}
return result;
}
/**
* Test whether or not this interval contains the specified interval. An
* interval is contained by another precisely when all of its values are
* contained by the other.
*
* @param interval
* the query interval, non-null.
* @return true if this interval contains the specified interval, false
* otherwise.
*/
public boolean contains(Interval interval) {
boolean lowIsLowerBound = low.equals(interval.low)
&& (isClosedOnLow || !interval.isClosedOnLow)
|| low.compareTo(interval.low) < 0;
boolean highIsUpperBound = high.equals(interval.high)
&& (isClosedOnHigh || !interval.isClosedOnHigh)
|| high.compareTo(interval.high) > 0;
return lowIsLowerBound && highIsUpperBound;
}
/**
* Test whether or not this interval contains the specified value.
*
* @param value
* the query value, non-null.
* @return true if this interval contains the specified value, false
* otherwise.
*/
public boolean contains(T value) {
return value.equals(low) && isClosedOnLow || value.equals(high)
&& isClosedOnHigh || low.compareTo(value) < 0
&& value.compareTo(high) < 0;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Interval other = (Interval) obj;
if (high == null) {
if (other.high != null)
return false;
} else if (!high.equals(other.high))
return false;
if (isClosedOnHigh != other.isClosedOnHigh)
return false;
if (low == null) {
if (other.low != null)
return false;
} else if (!low.equals(other.low))
return false;
if (isClosedOnLow != other.isClosedOnLow)
return false;
return true;
}
/**
* Get the high endpoint.
*
* @return the high endpoint.
*/
public T getHigh() {
return high;
}
/**
* Get the low endpoint.
*
* @return the low endpoint.
*/
public T getLow() {
return low;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
if (hashCode == 0) {
final int prime = 31;
int result = 1;
result = prime * result + ((high == null) ? 0 : high.hashCode());
result = prime * result + (isClosedOnHigh ? 1231 : 1237);
result = prime * result + ((low == null) ? 0 : low.hashCode());
result = prime * result + (isClosedOnLow ? 1231 : 1237);
hashCode = result;
}
return hashCode;
}
/**
*
* @return true if this interval is closed at its high endpoint, false
* otherwise.
*/
public boolean isClosedOnHigh() {
return isClosedOnHigh;
}
/**
*
* @return true if the interval is closed at its low endpoint, false
* otherwise.
*/
public boolean isClosedOnLow() {
return isClosedOnLow;
}
/**
* Test whether or not this interval and the specified interval overlap. Two
* intervals overlap precisely when their intersection is non-empty.
*
* @param interval
* the query interval.
* @return true if this interval and the specified interval overlap, false
* otherwise.
*/
public boolean overlaps(Interval interval) {
if (interval.isClosedOnLow && contains(interval.low) || isClosedOnLow
&& interval.contains(low)) {
return true;
}
if (!interval.isClosedOnLow && low.compareTo(interval.low) <= 0
&& interval.low.compareTo(high) < 0 || !isClosedOnLow
&& interval.low.compareTo(low) <= 0
&& low.compareTo(interval.high) < 0) {
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
String format;
if (isClosedOnLow) {
if (isClosedOnHigh) {
format = "[%s, %s]";
} else {
format = "[%s, %s)";
}
} else {
if (isClosedOnHigh) {
format = "(%s, %s]";
} else {
format = "(%s, %s)";
}
}
return String.format(format, low.toString(), high.toString());
}
} OrderLinkedRedBlackTree.java 0000664 0000000 0000000 00000012506 15101666221 0040453 0 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/java/blogspot/software_and_algorithms/stern_library/data_structure package blogspot.software_and_algorithms.stern_library.data_structure;
import java.util.Comparator;
/* Copyright (c) 2012 Kevin L. Stern
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* A red black tree that has been augmented to support linear time partial
* iteration by storing pointers to a node's predecessor and successor within
* the node itself.
*
* @author Kevin L. Stern
*/
public class OrderLinkedRedBlackTree extends RedBlackTree {
private RedBlackTree.Node head;
/**
* Default constructor.
*/
public OrderLinkedRedBlackTree() {
this(null);
}
/**
* Construct a new instance which uses the specified comparator.
*
* @param comparator
* the comparator to use when ordering elements.
*/
public OrderLinkedRedBlackTree(Comparator comparator) {
super(comparator);
}
/**
* {@inheritDoc}
*/
@Override
public void clear() {
super.clear();
head = null;
}
/**
* {@inheritDoc}
*/
@Override
protected RedBlackTree.Node createNewNode(T value) {
return new Node(value);
}
/**
* {@inheritDoc}
*/
@Override
public RedBlackTree.Node delete(T value) {
if (head != null && head.getValue().equals(value)) {
head = getSuccessor(head);
}
RedBlackTree.Node result = super.delete(value);
if (result != null) {
Node linkedNode = (Node) result;
if (linkedNode.getPredecessor() != null)
linkedNode.getPredecessor().setSuccessor(
linkedNode.getSuccessor());
if (linkedNode.getSuccessor() != null)
linkedNode.getSuccessor().setPredecessor(
linkedNode.getPredecessor());
}
return result;
}
/**
* {@inheritDoc}
*/
@Override
protected void exchangeValues(RedBlackTree.Node node,
RedBlackTree.Node successor) {
super.exchangeValues(node, successor);
Node linkedNode = (Node) node;
Node linkedSuccessor = (Node) successor;
linkedNode.setSuccessor(linkedSuccessor.getSuccessor());
if (linkedNode.getSuccessor() != null)
linkedNode.getSuccessor().setPredecessor(linkedNode);
linkedSuccessor.setPredecessor(null);
linkedSuccessor.setSuccessor(null);
}
/**
* {@inheritDoc}
*/
@Override
public RedBlackTree.Node getFirstNode() {
return head;
}
/**
* {@inheritDoc}
*/
@Override
public RedBlackTree.Node getPredecessor(RedBlackTree.Node node) {
return ((Node) node).getPredecessor();
}
/**
* {@inheritDoc}
*/
@Override
public RedBlackTree.Node getSuccessor(RedBlackTree.Node node) {
return ((Node) node).getSuccessor();
}
/**
* {@inheritDoc}
*/
@Override
public RedBlackTree.Node insert(T value) {
RedBlackTree.Node result = super.insert(value);
if (result != null) {
Node linkedNode = (Node) result;
Node pred = (Node) super.getPredecessor(result);
linkedNode.setPredecessor(pred);
if (pred != null) {
pred.setSuccessor(linkedNode);
}
Node succ = (Node) super.getSuccessor(result);
linkedNode.setSuccessor(succ);
if (succ != null) {
succ.setPredecessor(linkedNode);
}
if (head == null) {
head = getRoot();
} else {
RedBlackTree.Node node = getPredecessor(head);
if (node != null) {
head = node;
}
}
}
return result;
}
/**
* A red-black tree node augmented to store pointers to its predecessor and
* successor.
*
* @author Kevin L. Stern
*/
public static class Node extends RedBlackTree.Node {
private Node predecessor, successor;
/**
* Construct a node with the specified value.
*
* @param value
* the value to associate with this node.
*/
public Node(T value) {
super(value);
}
/**
* Get the predecessor node.
*
* @return the predecessor of this node in the tree.
*/
public Node getPredecessor() {
return predecessor;
}
/**
* Get the successor node.
*
* @return the successor of this node in the tree.
*/
public Node getSuccessor() {
return successor;
}
/**
* Set the predecessor node.
*
* @param node
* the predecessor of this node in the tree.
*/
protected void setPredecessor(Node node) {
predecessor = node;
}
/**
* Set the successor node.
*
* @param node
* the successor of this node in the tree.
*/
protected void setSuccessor(Node node) {
successor = node;
}
}
} RedBlackTree.java 0000664 0000000 0000000 00000046070 15101666221 0036333 0 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/java/blogspot/software_and_algorithms/stern_library/data_structure package blogspot.software_and_algorithms.stern_library.data_structure;
import java.util.Comparator;
import java.util.Iterator;
import java.util.NoSuchElementException;
import blogspot.software_and_algorithms.stern_library.data_structure.RedBlackTree.Node.NodeColor;
/* Copyright (c) 2012 Kevin L. Stern
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* A red-black tree is a binary search tree guaranteeing that no path
* from root to leaf is more than twice as long as any other such path. This
* property provides an assurance that the height of a red-black tree is
* logarithmic in the number of nodes in the tree.
*
* This implementation is based upon Cormen, Leiserson, Rivest, Stein's
* Introduction to Algorithms book.
*
* @see "Introduction to Algorithms Cormen, Leiserson, Rivest, and Stein.
* Introduction to Algorithms. 2nd ed. Cambridge, MA: MIT Press, 2001.
* ISBN: 0262032937."
*/
public class RedBlackTree implements Iterable {
private Comparator super T> comparator;
private Node root;
private int size;
/**
* Default constructor. Tree uses the natural ordering of elements defined
* by {@link Comparable#compareTo(Object)}; for custom ordering see
* {@link RedBlackTree#RedBlackTree(Comparator)}.
*/
public RedBlackTree() {
this(null);
}
/**
* Construct a new tree which uses the specified custom comparator.
*
* @param comparator
* the comparator to use when ordering elements.
*/
public RedBlackTree(Comparator super T> comparator) {
this.comparator = comparator;
this.root = null;
this.size = 0;
}
/**
* Clear all entries from this tree.
*/
public void clear() {
root = null;
size = 0;
}
/**
* Convenience method to compare two values either by use of the Comparator,
* if not null, or by casting to Comparable otherwise. This method may
* result in a ClassCastException if the tree holds non-Comparable values
* and no Comparator was specified upon construction.
*
* @param val1
* the lhs of the compare operation.
* @param val2
* the rhs of the compare operation.
* @return a negative integer, zero, or a positive integer depending upon
* whether val1 is less than, equal to, or greater than val2,
* respectively.
*/
private int compare(T val1, T val2) {
return comparator == null ? ((Comparable) val1).compareTo(val2)
: comparator.compare(val1, val2);
}
/**
* Test whether or not the specified value is an element of this tree.
*
* @param value
* the query value.
* @return true if the specified value is an element of this tree, false
* otherwise.
*/
public boolean contains(T value) {
return getNode(value) != null;
}
/**
* Create a new node with the specified value. This method allows a subclass
* to assert control over the type of the nodes held by this tree.
*
* @param value
* the value to apply to the new node.
* @return a new node holding the specified value.
*/
protected Node createNewNode(T value) {
return new Node(value);
}
/**
* Delete the specified value from this tree.
*
* @param value
* the value to delete.
* @return the node which contained the value before it was removed from
* this tree, null if the value is not an element of this tree.
*/
public Node delete(T value) {
if (value == null) {
return null;
}
Node node = getNode(value);
if (node == null)
return null;
Node swap;
if (!(node.getLeft() == null || node.getRight() == null)) {
Node successor = getSuccessor(node);
exchangeValues(node, successor);
node = successor;
}
if (node.getLeft() != null) {
swap = node.getLeft();
} else {
swap = node.getRight();
}
if (swap != null)
swap.setParent(node.getParent());
if (node.getParent() == null)
root = swap;
else if (node == node.getParent().getLeft())
node.getParent().setLeft(swap);
else
node.getParent().setRight(swap);
if (node.getColor() == NodeColor.BLACK) {
if (root != null)
fixAfterDeletion(swap == null ? node : swap);
}
size--;
return node;
}
/**
* Called by {@link #delete} when the node to be removed is a leaf. In
* this case, the node's value is exchanged with its successor as per the
* typical binary tree node removal operation. This method allows a subclass
* to influence value exchange behavior (e.g. if additional node information
* needs to be exchanged).
*
* @param node
* the node whose value is to be removed.
* @param successor
* the node to actually be removed.
*/
protected void exchangeValues(Node node, Node successor) {
T tempValue = successor.getValue();
successor.setValue(node.getValue());
node.setValue(tempValue);
}
/**
* Re-balance the tree after a delete operation.
*
* @param node
* the deleted node or the swap node.
*
* @see "CLRS Introduction to Algorithms"
*/
protected void fixAfterDeletion(Node node) {
while (node != root && getColor(node) == NodeColor.BLACK) {
if (node == node.getParent().getLeft()
|| (node.getParent().getRight() != null && node != node
.getParent().getRight())) {
Node temp = node.getParent().getRight();
if (getColor(temp) == NodeColor.RED) {
setColor(temp, NodeColor.BLACK);
setColor(node.getParent(), NodeColor.RED);
leftRotate(node.getParent());
temp = node.getParent().getRight();
}
if (getColor(temp.getLeft()) == NodeColor.BLACK
&& getColor(temp.getRight()) == NodeColor.BLACK) {
setColor(temp, NodeColor.RED);
node = node.getParent();
} else {
if (getColor(temp.getRight()) == NodeColor.BLACK) {
setColor(temp.getLeft(), NodeColor.BLACK);
setColor(temp, NodeColor.RED);
rightRotate(temp);
temp = node.getParent().getRight();
}
setColor(temp, getColor(node.getParent()));
setColor(node.getParent(), NodeColor.BLACK);
setColor(temp.getRight(), NodeColor.BLACK);
leftRotate(node.getParent());
node = root;
}
} else {
Node temp = node.getParent().getLeft();
if (getColor(temp) == NodeColor.RED) {
setColor(temp, NodeColor.BLACK);
setColor(node.getParent(), NodeColor.RED);
rightRotate(node.getParent());
temp = node.getParent().getLeft();
}
if (getColor(temp.getRight()) == NodeColor.BLACK
&& getColor(temp.getLeft()) == NodeColor.BLACK) {
setColor(temp, NodeColor.RED);
node = node.getParent();
} else {
if (getColor(temp.getLeft()) == NodeColor.BLACK) {
setColor(temp.getRight(), NodeColor.BLACK);
setColor(temp, NodeColor.RED);
leftRotate(temp);
temp = node.getParent().getLeft();
}
setColor(temp, getColor(node.getParent()));
setColor(node.getParent(), NodeColor.BLACK);
setColor(temp.getLeft(), NodeColor.BLACK);
rightRotate(node.getParent());
node = root;
}
}
}
setColor(node, NodeColor.BLACK);
}
/**
* Re-balance the tree after an insert operation.
*
* @param node
* the inserted node.
*
* @see "CLRS Introduction to Algorithms"
*/
protected void fixAfterInsertion(Node node) {
while (getColor(node.getParent()) == NodeColor.RED) {
if (node.getParent() == node.getParent().getParent().getLeft()) {
Node temp = node.getParent().getParent().getRight();
if (getColor(temp) == NodeColor.RED) {
setColor(node.getParent(), (NodeColor.BLACK));
setColor(temp, NodeColor.BLACK);
setColor(node.getParent().getParent(), NodeColor.RED);
node = node.getParent().getParent();
} else {
if (node == node.getParent().getRight()) {
node = node.getParent();
leftRotate(node);
}
setColor(node.getParent(), NodeColor.BLACK);
setColor(node.getParent().getParent(), NodeColor.RED);
rightRotate(node.getParent().getParent());
}
} else {
Node temp = node.getParent().getParent().getLeft();
if (getColor(temp) == NodeColor.RED) {
setColor(node.getParent(), NodeColor.BLACK);
setColor(temp, NodeColor.BLACK);
setColor(node.getParent().getParent(), NodeColor.RED);
node = node.getParent().getParent();
} else {
if (node == node.getParent().getLeft()) {
node = node.getParent();
rightRotate(node);
}
setColor(node.getParent(), NodeColor.BLACK);
setColor(node.getParent().getParent(), NodeColor.RED);
leftRotate(node.getParent().getParent());
}
}
}
setColor(root, NodeColor.BLACK);
}
/**
* Convenience method implementing the concept of a null-node leaf being
* black.
*
* @param node
* the node whose color is to be determined, null is interpreted
* as a null leaf and is assigned the color black.
* @return the color of the specified node.
*/
private NodeColor getColor(Node node) {
return (node == null) ? NodeColor.BLACK : node.getColor();
}
/**
* Get the node containing the smallest value held by this tree.
*
* @return the node containing the smallest value held by this tree.
*/
public Node getFirstNode() {
Node result = root;
if (result != null) {
while (result.getLeft() != null) {
result = result.getLeft();
}
}
return result;
}
/**
* Get the node that holds the specified value.
*
* @param value
* the query value.
* @return the node that holds the specified value, null if none.
*/
public Node getNode(T value) {
if (value == null) {
return null;
}
Node node = root;
while (node != null) {
int delta = compare(node.getValue(), value);
if (delta < 0) {
node = node.getRight();
} else if (delta > 0) {
node = node.getLeft();
} else {
break;
}
}
return node;
}
/**
* Get the predecessor of the specified node. The predecessor of a node n is
* the node with the largest value in the tree smaller than the value held
* by n.
*
* @param node the node compared to which predecessor node will be found
* @return the predecessor of the specified node
* @see "CLRS"
*/
public Node getPredecessor(Node node) {
if (node.getLeft() != null) {
node = node.getLeft();
while (node.getRight() != null)
node = node.getRight();
return node;
}
Node temp = node.getParent();
while (temp != null && node == temp.getLeft()) {
node = temp;
temp = temp.getParent();
}
return temp;
}
/**
* Get the root of this tree.
*
* @return the root of this tree.
*/
public Node getRoot() {
return root;
}
/**
* Get the number of elements contained within this tree.
*
* @return the number of elements contained within this tree.
*/
public int getSize() {
return size;
}
/**
* Get the successor of the specified node. The successor of a node n is the
* node with the smallest value in the tree larger than the value held by n.
*
* @param node the node compared to which successor node will be found
* @return the successor of the specified node
* @see "CLRS"
*/
public Node getSuccessor(Node node) {
if (node.getRight() != null) {
node = node.getRight();
while (node.getLeft() != null)
node = node.getLeft();
return node;
}
Node temp = node.getParent();
while (temp != null && node == temp.getRight()) {
node = temp;
temp = temp.getParent();
}
return temp;
}
/**
* Insert the specified value into this tree.
*
* @param value
* the value to insert.
* @return the new node containing the specified value if the value was not
* already present in the tree, null otherwise.
*/
public Node insert(T value) {
Node node = null;
Node parent = root;
while (parent != null) {
int delta = compare(parent.getValue(), value);
if (delta < 0) {
if (parent.getRight() == null) {
node = createNewNode(value);
parent.setRight(node);
node.setParent(parent);
parent = null;
} else {
parent = parent.getRight();
}
} else if (delta > 0) {
if (parent.getLeft() == null) {
node = createNewNode(value);
parent.setLeft(node);
node.setParent(parent);
parent = null;
} else {
parent = parent.getLeft();
}
} else {
return null;
}
}
if (node == null) {
node = createNewNode(value);
root = node;
}
setColor(node, NodeColor.RED);
fixAfterInsertion(node);
size++;
return node;
}
/**
* @return true if there are no items in this tree, false otherwise.
*/
public boolean isEmpty() {
return size == 0;
}
/**
* Returns an Iterator over the elements of this tree.
*
* @return an Iterator over the elements of this tree.
*/
@Override
public Iterator iterator() {
return new Iterator() {
private Node cursor = getFirstNode();
private T lastReturn;
@Override
public boolean hasNext() {
return cursor != null;
}
@Override
public T next() {
if (cursor == null) {
throw new NoSuchElementException();
}
lastReturn = cursor.getValue();
cursor = getSuccessor(cursor);
return lastReturn;
}
@Override
public void remove() {
if (lastReturn == null) {
throw new NoSuchElementException();
}
T currentValue = cursor == null ? null : cursor.getValue();
delete(lastReturn);
cursor = currentValue == null ? null : getNode(currentValue);
lastReturn = null;
}
};
}
/**
* Perform a left rotate operation on the specified node.
*
* @param node
* the node on which the left rotate operation will be performed.
*
* @see "CLRS Introduction to Algorithms"
*/
protected void leftRotate(Node node) {
Node temp = node.getRight();
node.setRight(temp.getLeft());
if (temp.getLeft() != null)
temp.getLeft().setParent(node);
temp.setParent(node.getParent());
if (node.getParent() == null)
root = temp;
else if (node == node.getParent().getLeft())
node.getParent().setLeft(temp);
else
node.getParent().setRight(temp);
temp.setLeft(node);
node.setParent(temp);
}
/**
* Perform a right rotate operation on the specified node.
*
* @param node
* the node on which a right rotate operation is to be performed.
*
* @see "CLRS Introduction to Algorithms"
*/
protected void rightRotate(Node node) {
Node temp = node.getLeft();
node.setLeft(temp.getRight());
if (temp.getRight() != null)
temp.getRight().setParent(node);
temp.setParent(node.getParent());
if (node.getParent() == null)
root = temp;
else if (node == node.getParent().getRight())
node.getParent().setRight(temp);
else
node.getParent().setLeft(temp);
temp.setRight(node);
node.setParent(temp);
}
/**
* Convenience method to set the color of the specified node to the
* specified color if the node is non-null.
*
* @param node
* the target node, possibly null.
* @param color
* the target color, non-null.
*/
private void setColor(Node node, NodeColor color) {
if (node != null)
node.setColor(color);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder("{");
if (!isEmpty()) {
for (Iterator i = iterator();;) {
builder.append(i.next());
if (i.hasNext()) {
builder.append(", ");
} else {
break;
}
}
}
builder.append("}");
return builder.toString();
}
/**
* A red-black tree node is a binary tree node augmented to hold an
* additional piece of information called the node's color. The
* domain of values from which a red-black tree node's color is assigned
* comprises red and black. A red-black tree requires that
* its nodes provide the ability to set the parent and children and to set
* the value stored by the node. This class encapsulates the concept of a
* red-black tree node.
*/
public static class Node {
private NodeColor color;
private Node left, right, parent;
private T value;
/**
* Construct a new node with the specified value.
*
* @param value
* the value to store in this node.
*/
public Node(T value) {
if (value == null) {
throw new NullPointerException("value is null");
}
this.value = value;
}
/**
* Get the color.
*
* @return the color, never null.
*/
public NodeColor getColor() {
return color;
}
/**
* Get the left child.
*
* @return the left child, possibly null.
*/
public Node getLeft() {
return left;
}
/**
* Get the parent.
*
* @return the parent, possibly null.
*/
public Node getParent() {
return parent;
}
/**
* Get the right child.
*
* @return the right child, possibly null.
*/
public Node getRight() {
return right;
}
/**
* Get the value.
*
* @return the value.
*/
public T getValue() {
return value;
}
/**
* Test whether or not this node is a leaf node.
*
* @return true if this node is a leaf node, false otherwise.
*/
public boolean isLeaf() {
return left == null && right == null;
}
/**
* Set the color.
*
* @param color
* the color to set to this node.
*/
protected void setColor(NodeColor color) {
this.color = color;
}
/**
* Set the left child.
*
* @param node
* the node to set as the left child of this node.
*/
protected void setLeft(Node node) {
this.left = node;
}
/**
* Set the parent.
*
* @param node
* the node to set as the parent of this node.
*/
protected void setParent(Node node) {
this.parent = node;
}
/**
* Set the right child.
*
* @param node
* the node to set as the right child of this node.
*/
protected void setRight(Node node) {
this.right = node;
}
/**
* Set the value.
*
* @param value
* the value to store in this node, must be non-null.
*/
protected void setValue(T value) {
if (value == null) {
throw new IllegalArgumentException("value is null");
}
this.value = value;
}
/**
* The domain of values from which a node's color is assigned.
*/
public static enum NodeColor {
BLACK, RED
}
}
} StaticIntervalTree.java 0000664 0000000 0000000 00000046033 15101666221 0037617 0 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/java/blogspot/software_and_algorithms/stern_library/data_structure package blogspot.software_and_algorithms.stern_library.data_structure;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/* Copyright (c) 2012 Kevin L. Stern
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* A static interval tree is a balanced binary search tree which is
* built to store a pre-specified set of intervals so that both point queries
* (queries that return intervals from the set which contain a query point) and
* overlapping interval queries (queries that return intervals from the set
* which overlap a query interval) can be completed in time O(log(n)+k), where n
* is the size of the pre-specified set of intervals and k is the size of the
* result set from the query.
*
* While this implementation of a static interval tree is built to support a
* pre-specified set of intervals, intervals from this set may be added to and
* removed from the tree at will, giving a semi-static nature to the tree. The
* construction process completes in time O(n*log(n)) where n is the size of the
* set of intervals with which the tree is built.
*
* Insertion and deletion of intervals to and from a constructed tree completes
* in time O(log(n)) where n is the size of the set of intervals with which the
* tree was built.
*
* A constructed tree consumes linear space in the size of the set of intervals
* with which the tree was built.
*
* Note that this implementation supports all three closed, open and half-open
* intervals.
*
* @author Kevin L. Stern
*/
public class StaticIntervalTree, T extends Interval> {
private Node root;
private int size;
/**
* Default constructor.
*/
public StaticIntervalTree() {
size = 0;
}
/**
* Internal helper method to construct a subtree structure capable of
* holding the elements of the specified portion of the specified list of
* intervals.
*
* @param intervalList
* the list of intervals with which to build the subtree; must be
* ordered by low endpoint.
* @param low
* the low index of the portion of intervalList to consider,
* inclusive.
* @param high
* the high index of the portion of intervalList to consider,
* exclusive.
*/
private Node buildSubtree(List intervalList, int low, int high) {
U point = intervalList.get((low + high) >>> 1).getLow();
Node result = new Node(point);
int lowPointer = low;
int highPointer = high;
for (int j = low; j < highPointer; j++) {
T next = intervalList.get(j);
if (next.getHigh().compareTo(point) < 0) {
Collections.swap(intervalList, lowPointer++, j);
} else if (next.getLow().compareTo(point) > 0) {
highPointer = j;
}
}
if (low < lowPointer) {
result.setLeft(buildSubtree(intervalList, low, lowPointer));
}
if (highPointer < high) {
result.setRight(buildSubtree(intervalList, highPointer, high));
}
return result;
}
/**
* Build the interval tree to support the elements of the specified set of
* intervals. Note that this method does not insert intervals into the tree
* (this must be done via {@link #insert(Interval)} after the tree is
* built).
*
* @param intervals
* the set of intervals for which the tree is to be built.
*/
public void buildTree(Set intervals) {
List intervalList = new ArrayList(intervals);
Collections.sort(intervalList, new Comparator() {
@Override
public int compare(T o1, T o2) {
return o1.getLow().compareTo(o2.getLow());
}
});
root = buildSubtree(intervalList, 0, intervals.size());
size = 0;
}
/**
* Clear the contents of the tree, leaving the tree structure intact.
*/
public void clear() {
if (root != null) {
List> stack = new ArrayList>();
stack.add(root);
while (!stack.isEmpty()) {
Node next = stack.remove(stack.size() - 1);
next.clear();
Node temp;
if ((temp = next.getLeft()) != null) {
stack.add(temp);
}
if ((temp = next.getRight()) != null) {
stack.add(temp);
}
}
}
size = 0;
}
/**
* Delete the specified interval from this tree.
*
* @param interval
* the interval to delete.
* @return true if an element was deleted as a result of this call, false
* otherwise.
*/
public boolean delete(T interval) {
if (interval == null) {
return false;
}
Node node = root;
while (node != null) {
U temp = node.getPoint();
if (interval.getLow().compareTo(temp) <= 0
&& temp.compareTo(interval.getHigh()) <= 0) {
if (node.delete(interval)) {
size -= 1;
return true;
}
} else if (interval.getHigh().compareTo(temp) < 0) {
node = node.getLeft();
} else {
node = node.getRight();
}
}
return false;
}
/**
* Fetch intervals containing the specified point.
*
* @param target
* the target Collection into which to place the desired
* intervals.
* @param queryPoint
* the query point.
* @return the target Collection.
*/
public > V fetchContainingIntervals(V target,
U queryPoint) {
if (target == null) {
throw new NullPointerException("target is null");
}
if (queryPoint == null) {
throw new NullPointerException("queryPoint is null");
}
Node node = root;
while (node != null) {
U temp = node.getPoint();
if (queryPoint.equals(temp)) {
node.fetchIntervalsContainingNodePoint(target);
node = null;
} else if (queryPoint.compareTo(temp) < 0) {
node.fetchIntervalsContainingPointLow(target, queryPoint, true);
node = node.getLeft();
} else {
node.fetchIntervalsContainingPointHigh(target, queryPoint, true);
node = node.getRight();
}
}
return target;
}
/**
* Fetch intervals overlapping the specified interval.
*
* @param target
* the target Collection into which to place the desired
* intervals.
* @param queryInterval
* the query interval.
* @return the target Collection.
*/
public > V fetchOverlappingIntervals(V target,
T queryInterval) {
if (target == null) {
throw new NullPointerException("target is null");
}
if (queryInterval == null) {
throw new NullPointerException("queryInterval is null");
}
List> stack = new ArrayList>();
if (root != null) {
stack.add(root);
}
while (!stack.isEmpty()) {
Node node = stack.remove(stack.size() - 1);
U temp = node.getPoint();
if (queryInterval.getLow().compareTo(temp) <= 0
&& temp.compareTo(queryInterval.getHigh()) <= 0) {
node.fetchOverlappingIntervals(target, queryInterval);
if (node.getLeft() != null) {
stack.add(node.getLeft());
}
if (node.getRight() != null) {
stack.add(node.getRight());
}
} else if (queryInterval.getHigh().compareTo(temp) < 0) {
node.fetchIntervalsContainingPointLow(target,
queryInterval.getHigh(), queryInterval.isClosedOnHigh());
if (node.getLeft() != null) {
stack.add(node.getLeft());
}
} else {
node.fetchIntervalsContainingPointHigh(target,
queryInterval.getLow(), queryInterval.isClosedOnLow());
if (node.getRight() != null) {
stack.add(node.getRight());
}
}
}
return target;
}
/**
* Get the number of intervals being stored in the tree.
*
* @return the number of intervals being stored in the tree.
*/
public int getSize() {
return size;
}
/**
* Insert the specified interval into this tree. Behavior is undefined when
* the interval was not included in the set of intervals presented at the
* most recent call to {@link #buildTree(Set)}.
*
* @param interval
* the interval to insert.
* @return true if an element was inserted as a result of this call, false
* otherwise.
*/
public boolean insert(T interval) {
Node node = root;
while (node != null) {
U temp = node.getPoint();
if (interval.getLow().compareTo(temp) <= 0
&& temp.compareTo(interval.getHigh()) <= 0) {
if (node.insert(interval)) {
size++;
return true;
}
} else if (interval.getHigh().compareTo(temp) < 0) {
node = node.getLeft();
} else {
node = node.getRight();
}
}
return false;
}
/**
* A node for a static interval tree is a binary tree node
* augmented with an associated point value and the ability to store
* intervals.
*
* Intervals that are stored within this node either contain the node's
* point value or are open at an endpoint that equals the node's point
* value. Intervals are stored so that these two cases are easily
* distinguished from one another: Each such class of interval is stored in
* two structures, one is a tree sorted by low endpoint and the other is a
* tree sorted by high endpoint. This enables efficient point queries as
* well as insertions and deletions from the node.
*/
protected static class Node, T extends Interval> {
private RedBlackTree highOrderedContainingIntervals = new OrderLinkedRedBlackTree(
new Comparator() {
@Override
public int compare(T o1, T o2) {
int result = o1.getHigh().compareTo(o2.getHigh());
if (result == 0) {
if (o1.isClosedOnHigh() != o2.isClosedOnHigh()) {
result = o1.isClosedOnHigh() ? 1 : -1;
} else {
result = o1.compareTo(o2);
}
}
return result > 0 ? -1 : result < 0 ? 1 : 0;
}
});
private RedBlackTree lowOrderedContainingIntervals = new OrderLinkedRedBlackTree(
new Comparator() {
@Override
public int compare(T o1, T o2) {
int result = o1.getLow().compareTo(o2.getLow());
if (result == 0) {
result = o1.compareTo(o2);
}
return result > 0 ? 1 : result < 0 ? -1 : 0;
}
});
private RedBlackTree highOrderedExcludingIntervals = new OrderLinkedRedBlackTree(
new Comparator() {
@Override
public int compare(T o1, T o2) {
int result = o1.getHigh().compareTo(o2.getHigh());
if (result == 0) {
if (o1.isClosedOnHigh() != o2.isClosedOnHigh()) {
result = o1.isClosedOnHigh() ? 1 : -1;
} else {
result = o1.compareTo(o2);
}
}
return result > 0 ? -1 : result < 0 ? 1 : 0;
}
});
private RedBlackTree lowOrderedExcludingIntervals = new OrderLinkedRedBlackTree(
new Comparator() {
@Override
public int compare(T o1, T o2) {
int result = o1.getLow().compareTo(o2.getLow());
if (result == 0) {
result = o1.compareTo(o2);
}
return result > 0 ? 1 : result < 0 ? -1 : 0;
}
});
private Node left, right;
private U point;
/**
* Construct a new node associated with the specified point.
*
* @param point
* the point with which this node is associated.
*/
public Node(U point) {
if (point == null) {
throw new NullPointerException("point is null");
}
this.point = point;
}
/**
* Clear the elements of this node.
*/
public void clear() {
lowOrderedContainingIntervals.clear();
highOrderedContainingIntervals.clear();
lowOrderedExcludingIntervals.clear();
highOrderedExcludingIntervals.clear();
}
/**
* Delete the specified interval from this node.
*
* @param interval
* the interval to delete.
* @return true if an element was deleted as a result of this call,
* false otherwise.
*/
public boolean delete(T interval) {
if (interval.contains(point)) {
if (lowOrderedContainingIntervals.delete(interval) == null) {
return false;
}
highOrderedContainingIntervals.delete(interval);
} else {
if (lowOrderedExcludingIntervals.delete(interval) == null) {
return false;
}
highOrderedExcludingIntervals.delete(interval);
}
return true;
}
/**
* Fetch all intervals from this node that contain the node's point.
*
* @param target
* the target Collection into which to place the desired
* intervals.
*/
public void fetchIntervalsContainingNodePoint(Collection target) {
if (highOrderedContainingIntervals.getSize() > 0) {
RedBlackTree.Node temp = highOrderedContainingIntervals
.getFirstNode();
while (temp != null) {
target.add(temp.getValue());
temp = highOrderedContainingIntervals.getSuccessor(temp);
}
}
}
/**
* Fetch intervals containing the specified value. This method is called
* when the specified value is greater than this node's point.
*
* @param target
* the target Collection into which to place the desired
* intervals.
* @param queryPoint
* the query value.
* @param isClosedOnValue
* true if the search is inclusive of the specified value,
* false otherwise.
*/
public void fetchIntervalsContainingPointHigh(Collection target,
U queryPoint, boolean isClosedOnValue) {
for (Iterator i = highOrderedContainingIntervals.iterator(); i
.hasNext();) {
T next = i.next();
int cmp = next.getHigh().compareTo(queryPoint);
if (cmp < 0 || cmp == 0
&& (!isClosedOnValue || !next.isClosedOnHigh())) {
break;
}
target.add(next);
}
for (Iterator i = highOrderedExcludingIntervals.iterator(); i
.hasNext();) {
T next = i.next();
int cmp = next.getHigh().compareTo(queryPoint);
if (cmp < 0 || cmp == 0
&& (!isClosedOnValue || !next.isClosedOnHigh())) {
break;
}
target.add(next);
}
}
/**
* Fetch intervals containing the specified value. This method is called
* when the specified value is less than this node's point.
*
* @param target
* the target Collection into which to place the desired
* intervals.
* @param queryPoint
* the query value.
* @param isClosedOnValue
* true if the search is inclusive of the specified value,
* false otherwise.
*/
public void fetchIntervalsContainingPointLow(Collection target,
U queryPoint, boolean isClosedOnValue) {
for (Iterator i = lowOrderedContainingIntervals.iterator(); i
.hasNext();) {
T next = i.next();
int cmp = next.getLow().compareTo(queryPoint);
if (cmp > 0 || cmp == 0
&& (!isClosedOnValue || !next.isClosedOnLow()))
break;
target.add(next);
}
for (Iterator i = lowOrderedExcludingIntervals.iterator(); i
.hasNext();) {
T next = i.next();
int cmp = next.getLow().compareTo(queryPoint);
if (cmp > 0 || cmp == 0
&& (!isClosedOnValue || !next.isClosedOnLow()))
break;
target.add(next);
}
}
/**
* Fetch all intervals from this node which overlap the specified
* interval. By contract, the interval must be such that
* {@link Interval#getLow()} {@literal <}= {@link Node#getPoint()}
* {@literal <}= {@link Interval#getHigh()}.
*
* @param target
* the target Collection into which to place the desired
* intervals.
* @param queryInterval
* the query interval.
*/
public void fetchOverlappingIntervals(Collection target,
Interval queryInterval) {
if (queryInterval.getLow().compareTo(point) == 0) {
fetchIntervalsContainingPointHigh(target,
queryInterval.getLow(), queryInterval.isClosedOnLow());
} else if (queryInterval.getHigh().compareTo(point) == 0) {
fetchIntervalsContainingPointLow(target,
queryInterval.getHigh(), queryInterval.isClosedOnHigh());
} else {
fetchIntervalsContainingNodePoint(target);
if (highOrderedExcludingIntervals.getSize() > 0) {
RedBlackTree.Node temp = highOrderedExcludingIntervals
.getFirstNode();
while (temp != null) {
target.add(temp.getValue());
temp = highOrderedExcludingIntervals.getSuccessor(temp);
}
}
}
}
/**
* Get the left child.
*
* @return the left child, null if none exists.
*/
public Node getLeft() {
return left;
}
/**
* Get the point associated with this node.
*
* @return the point associated with this node.
*/
public U getPoint() {
return point;
}
/**
* Get the right child.
*
* @return the right child, null if none exists.
*/
public Node getRight() {
return right;
}
/**
* Insert the specified interval into this node. By contract, the
* interval must be such that {@link Interval#getLow()} <=
* {@link Node#getPoint()} <= {@link Interval#getHigh()}.
*
* @param interval
* the interval to insert.
* @return true if an element was inserted as a result of this call,
* false otherwise.
*/
private boolean insert(T interval) {
if (interval.contains(point)) {
if (lowOrderedContainingIntervals.insert(interval) == null) {
return false;
}
highOrderedContainingIntervals.insert(interval);
} else {
if (lowOrderedExcludingIntervals.insert(interval) == null) {
return false;
}
highOrderedExcludingIntervals.insert(interval);
}
return true;
}
/**
* Set the left child to the specified node.
*
* @param node
* the left child.
*/
private void setLeft(Node node) {
left = node;
}
/**
* Set the right child to the specified node.
*
* @param node
* the right child.
*/
private void setRight(Node node) {
right = node;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder("{");
for (Iterator i = lowOrderedContainingIntervals.iterator();;) {
builder.append(i.next().toString());
if (i.hasNext()) {
builder.append(", ");
} else {
break;
}
}
for (Iterator i = lowOrderedExcludingIntervals.iterator(); i
.hasNext();) {
builder.append(", ").append(i.next().toString());
}
builder.append("}");
return builder.toString();
}
}
} euclid-euclid-2.13/src/main/java/blogspot/software_and_algorithms/stern_library/geometry/ 0000775 0000000 0000000 00000000000 15101666221 0032053 5 ustar 00root root 0000000 0000000 ClosestPointPairAlgorithm.java 0000664 0000000 0000000 00000020257 15101666221 0037756 0 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/java/blogspot/software_and_algorithms/stern_library/geometry package blogspot.software_and_algorithms.stern_library.geometry;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/* Copyright (c) 2012 Kevin L. Stern
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* An implementation of the divide-and-conquer algorithm for computing the
* closest pair among elements of a set of points. The algorithm consists of
* constructing a list of points, then recursively dividing the list into a left
* and right sublist and inspecting each sublist individually for closest point
* pairs. The two sub-results are merged by searching for closer point pairs
* that cross the boundary of separation. Happily, only a linear amount of work
* is required to merge the two results into a final closest pair of points,
* giving a total runtime of O(n*log(n)) for the algorithm.
*
* @author Kevin L. Stern
*/
public class ClosestPointPairAlgorithm {
private List pointsOrderedByXCoordinate,
pointsOrderedByYCoordinate;
/**
* Construct an instance of the algorithm for the specified point
* Collection.
*
* @param points
* the Collection of points through which to search for the
* closest pair.
*/
public ClosestPointPairAlgorithm(Collection points) {
if (points == null) {
throw new NullPointerException("points is null");
}
if (points.size() < 2) {
throw new IllegalArgumentException("points is too small");
}
pointsOrderedByXCoordinate = new ArrayList(points);
Collections.sort(pointsOrderedByXCoordinate, new Comparator() {
@Override
public int compare(Point2D o1, Point2D o2) {
double delta = o1.getX() - o2.getX();
if (delta == 0.0) {
delta = o1.getY() - o2.getY();
}
return delta < 0 ? -1 : delta > 0 ? 1 : 0;
}
});
pointsOrderedByYCoordinate = new ArrayList(points);
Collections.sort(pointsOrderedByYCoordinate, new Comparator() {
@Override
public int compare(Point2D o1, Point2D o2) {
double delta = o1.getY() - o2.getY();
if (delta == 0.0) {
delta = o1.getX() - o2.getX();
}
return delta < 0 ? -1 : delta > 0 ? 1 : 0;
}
});
}
/**
* Internal helper method which implements the closest point pair algorithm.
*
* @param low
* the index, inclusive, delimiting the low boundary of the
* portion of the list in which to search for the closest point
* pair.
* @param high
* the index, exclusive, delimiting the high boundary of the
* portion of the list in which to search for the closest point
* pair.
* @param localPointsSortedByYCoordinate
* the points from the portion of the list delimited by the low
* and high parameters, sorted by y coordinate.
* @return a PairStructure containing the closest point pair among elements
* of the specified portion of the list.
*/
protected PairStructure closestPair(int low, int high,
List localPointsSortedByYCoordinate) {
int size = high - low;
if (size == 3) {
Point2D p1 = pointsOrderedByXCoordinate.get(low);
Point2D p2 = pointsOrderedByXCoordinate.get(low + 1);
Point2D p3 = pointsOrderedByXCoordinate.get(low + 2);
double d1 = p1.distanceSq(p2);
double d2 = p2.distanceSq(p3);
double d3 = p1.distanceSq(p3);
if (d1 < d2) {
if (d1 < d3) {
return new PairStructure(p1, p2, d1);
} else {
return new PairStructure(p1, p3, d3);
}
} else {
if (d2 < d3) {
return new PairStructure(p2, p3, d2);
} else {
return new PairStructure(p1, p3, d3);
}
}
} else if (size == 2) {
Point2D p1 = pointsOrderedByXCoordinate.get(low);
Point2D p2 = pointsOrderedByXCoordinate.get(low + 1);
return new PairStructure(p1, p2, p1.distanceSq(p2));
}
assert size > 3;
int mid = (low + high) >>> 1;
Set leftSubtreeMemberSet = new HashSet(mid - low);
for (int j = low; j < mid; j++) {
leftSubtreeMemberSet.add(pointsOrderedByXCoordinate.get(j));
}
/*
* Construct the lists of points ordered by y coordinate for the left
* and right subtrees in linear time by drawing upon the master list of
* points ordered by y coordinate.
*/
List leftPointsOrderedByYCoordinate = new ArrayList(
mid - low);
List rightPointsOrderedByYCoordinate = new ArrayList(
high - mid);
for (Point2D next : localPointsSortedByYCoordinate) {
if (leftSubtreeMemberSet.contains(next)) {
leftPointsOrderedByYCoordinate.add(next);
} else {
rightPointsOrderedByYCoordinate.add(next);
}
}
PairStructure leftSubtreeResult = closestPair(low, mid,
leftPointsOrderedByYCoordinate);
PairStructure rightSubtreeResult = closestPair(mid, high,
rightPointsOrderedByYCoordinate);
PairStructure result = leftSubtreeResult.distanceSq < rightSubtreeResult.distanceSq ? leftSubtreeResult
: rightSubtreeResult;
List boundaryPointsOrderedByYCoordinate = new ArrayList();
double midXCoordinate = pointsOrderedByXCoordinate.get(mid).getX();
for (Point2D next : localPointsSortedByYCoordinate) {
double v = next.getX() - midXCoordinate;
if (v * v < result.distanceSq) {
boundaryPointsOrderedByYCoordinate.add(next);
}
}
for (int i = 0; i < boundaryPointsOrderedByYCoordinate.size(); i++) {
Point2D next = boundaryPointsOrderedByYCoordinate.get(i);
int index;
for (int j = 1; (index = i + j) < boundaryPointsOrderedByYCoordinate
.size(); j += 1) {
Point2D candidatePartner = boundaryPointsOrderedByYCoordinate
.get(index);
/*
* Only a constant number of points will be so that their y
* coordinate is within the minimum of the result distances for
* the left/right subtrees.
*/
double v = candidatePartner.getY() - next.getY();
if (v * v >= result.distanceSq) {
break;
}
double candidateDistance = next.distanceSq(candidatePartner);
if (candidateDistance < result.distanceSq) {
result = new PairStructure(next, candidatePartner,
candidateDistance);
}
}
}
return result;
}
/**
* Execute the algorithm.
*
* @return a Point2D[] containing exactly two elements which are the closest
* pair of points among those in the collection used to construct
* this instance.
*/
public Point2D[] execute() {
PairStructure result = closestPair(0,
pointsOrderedByXCoordinate.size(), pointsOrderedByYCoordinate);
return new Point2D[] { result.p1, result.p2 };
}
/**
* Convenience data structure to hold a pair of points along with distance
* information.
*/
protected static class PairStructure {
private Point2D p1, p2;
private double distanceSq;
/**
* Constructor.
*
* @param point1
* the first point.
* @param point2
* the second point.
* @param distanceSq
* the distance between the two points, squared.
*/
public PairStructure(Point2D point1, Point2D point2, double distanceSq) {
this.p1 = point1;
this.p2 = point2;
this.distanceSq = distanceSq;
}
}
} euclid-euclid-2.13/src/main/java/blogspot/software_and_algorithms/stern_library/optimization/ 0000775 0000000 0000000 00000000000 15101666221 0032746 5 ustar 00root root 0000000 0000000 HungarianAlgorithm.java 0000664 0000000 0000000 00000025751 15101666221 0037327 0 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/java/blogspot/software_and_algorithms/stern_library/optimization package blogspot.software_and_algorithms.stern_library.optimization;
import java.util.Arrays;
/* Copyright (c) 2012 Kevin L. Stern
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* An implementation of the Hungarian algorithm for solving the assignment
* problem. An instance of the assignment problem consists of a number of
* workers along with a number of jobs and a cost matrix which gives the cost of
* assigning the i'th worker to the j'th job at position (i, j). The goal is to
* find an assignment of workers to jobs so that no job is assigned more than
* one worker and so that no worker is assigned to more than one job in such a
* manner so as to minimize the total cost of completing the jobs.
*
*
* An assignment for a cost matrix that has more workers than jobs will
* necessarily include unassigned workers, indicated by an assignment value of
* -1; in no other circumstance will there be unassigned workers. Similarly, an
* assignment for a cost matrix that has more jobs than workers will necessarily
* include unassigned jobs; in no other circumstance will there be unassigned
* jobs. For completeness, an assignment for a square cost matrix will give
* exactly one unique worker to each job.
*
*
* This version of the Hungarian algorithm runs in time O(n^3), where n is the
* maximum among the number of workers and the number of jobs.
*
* @author Kevin L. Stern
*/
public class HungarianAlgorithm {
private final double[][] costMatrix;
private final int rows, cols, dim;
private final double[] labelByWorker, labelByJob;
private final int[] minSlackWorkerByJob;
private final double[] minSlackValueByJob;
private final int[] matchJobByWorker, matchWorkerByJob;
private final int[] parentWorkerByCommittedJob;
private final boolean[] committedWorkers;
/**
* Construct an instance of the algorithm.
*
* @param costMatrix
* the cost matrix, where matrix[i][j] holds the cost of
* assigning worker i to job j, for all i, j. The cost matrix
* must not be irregular in the sense that all rows must be the
* same length.
*/
public HungarianAlgorithm(double[][] costMatrix) {
this.dim = Math.max(costMatrix.length, costMatrix[0].length);
this.rows = costMatrix.length;
this.cols = costMatrix[0].length;
this.costMatrix = new double[this.dim][this.dim];
for (int w = 0; w < this.dim; w++) {
if (w < costMatrix.length) {
if (costMatrix[w].length != this.cols) {
throw new IllegalArgumentException("Irregular cost matrix");
}
this.costMatrix[w] = Arrays.copyOf(costMatrix[w], this.dim);
} else {
this.costMatrix[w] = new double[this.dim];
}
}
labelByWorker = new double[this.dim];
labelByJob = new double[this.dim];
minSlackWorkerByJob = new int[this.dim];
minSlackValueByJob = new double[this.dim];
committedWorkers = new boolean[this.dim];
parentWorkerByCommittedJob = new int[this.dim];
matchJobByWorker = new int[this.dim];
Arrays.fill(matchJobByWorker, -1);
matchWorkerByJob = new int[this.dim];
Arrays.fill(matchWorkerByJob, -1);
}
/**
* Compute an initial feasible solution by assigning zero labels to the
* workers and by assigning to each job a label equal to the minimum cost
* among its incident edges.
*/
protected void computeInitialFeasibleSolution() {
for (int j = 0; j < dim; j++) {
labelByJob[j] = Double.POSITIVE_INFINITY;
}
for (int w = 0; w < dim; w++) {
for (int j = 0; j < dim; j++) {
if (costMatrix[w][j] < labelByJob[j]) {
labelByJob[j] = costMatrix[w][j];
}
}
}
}
/**
* Execute the algorithm.
*
* @return the minimum cost matching of workers to jobs based upon the
* provided cost matrix. A matching value of -1 indicates that the
* corresponding worker is unassigned.
*/
public int[] execute() {
/*
* Heuristics to improve performance: Reduce rows and columns by their
* smallest element, compute an initial non-zero dual feasible solution
* and create a greedy matching from workers to jobs of the cost matrix.
*/
reduce();
computeInitialFeasibleSolution();
greedyMatch();
int w = fetchUnmatchedWorker();
while (w < dim) {
initializePhase(w);
executePhase();
w = fetchUnmatchedWorker();
}
int[] result = Arrays.copyOf(matchJobByWorker, rows);
for (w = 0; w < result.length; w++) {
if (result[w] >= cols) {
result[w] = -1;
}
}
return result;
}
/**
* Execute a single phase of the algorithm. A phase of the Hungarian
* algorithm consists of building a set of committed workers and a set of
* committed jobs from a root unmatched worker by following alternating
* unmatched/matched zero-slack edges. If an unmatched job is encountered,
* then an augmenting path has been found and the matching is grown. If the
* connected zero-slack edges have been exhausted, the labels of committed
* workers are increased by the minimum slack among committed workers and
* non-committed jobs to create more zero-slack edges (the labels of
* committed jobs are simultaneously decreased by the same amount in order
* to maintain a feasible labeling).
*
*
* The runtime of a single phase of the algorithm is O(n^2), where n is the
* dimension of the internal square cost matrix, since each edge is visited
* at most once and since increasing the labeling is accomplished in time
* O(n) by maintaining the minimum slack values among non-committed jobs.
* When a phase completes, the matching will have increased in size.
*/
protected void executePhase() {
while (true) {
int minSlackWorker = -1, minSlackJob = -1;
double minSlackValue = Double.POSITIVE_INFINITY;
for (int j = 0; j < dim; j++) {
if (parentWorkerByCommittedJob[j] == -1) {
if (minSlackValueByJob[j] < minSlackValue) {
minSlackValue = minSlackValueByJob[j];
minSlackWorker = minSlackWorkerByJob[j];
minSlackJob = j;
}
}
}
if (minSlackValue > 0) {
updateLabeling(minSlackValue);
}
parentWorkerByCommittedJob[minSlackJob] = minSlackWorker;
if (matchWorkerByJob[minSlackJob] == -1) {
/*
* An augmenting path has been found.
*/
int committedJob = minSlackJob;
int parentWorker = parentWorkerByCommittedJob[committedJob];
while (true) {
int temp = matchJobByWorker[parentWorker];
match(parentWorker, committedJob);
committedJob = temp;
if (committedJob == -1) {
break;
}
parentWorker = parentWorkerByCommittedJob[committedJob];
}
return;
} else {
/*
* Update slack values since we increased the size of the
* committed workers set.
*/
int worker = matchWorkerByJob[minSlackJob];
committedWorkers[worker] = true;
for (int j = 0; j < dim; j++) {
if (parentWorkerByCommittedJob[j] == -1) {
double slack = costMatrix[worker][j]
- labelByWorker[worker] - labelByJob[j];
if (minSlackValueByJob[j] > slack) {
minSlackValueByJob[j] = slack;
minSlackWorkerByJob[j] = worker;
}
}
}
}
}
}
/**
*
* @return the first unmatched worker or {@link #dim} if none.
*/
protected int fetchUnmatchedWorker() {
int w;
for (w = 0; w < dim; w++) {
if (matchJobByWorker[w] == -1) {
break;
}
}
return w;
}
/**
* Find a valid matching by greedily selecting among zero-cost matchings.
* This is a heuristic to jump-start the augmentation algorithm.
*/
protected void greedyMatch() {
for (int w = 0; w < dim; w++) {
for (int j = 0; j < dim; j++) {
if (matchJobByWorker[w] == -1
&& matchWorkerByJob[j] == -1
&& costMatrix[w][j] - labelByWorker[w] - labelByJob[j] == 0) {
match(w, j);
}
}
}
}
/**
* Initialize the next phase of the algorithm by clearing the committed
* workers and jobs sets and by initializing the slack arrays to the values
* corresponding to the specified root worker.
*
* @param w
* the worker at which to root the next phase.
*/
protected void initializePhase(int w) {
Arrays.fill(committedWorkers, false);
Arrays.fill(parentWorkerByCommittedJob, -1);
committedWorkers[w] = true;
for (int j = 0; j < dim; j++) {
minSlackValueByJob[j] = costMatrix[w][j] - labelByWorker[w]
- labelByJob[j];
minSlackWorkerByJob[j] = w;
}
}
/**
* Helper method to record a matching between worker w and job j.
* @param w the worker
* @param j the job
*/
protected void match(int w, int j) {
matchJobByWorker[w] = j;
matchWorkerByJob[j] = w;
}
/**
* Reduce the cost matrix by subtracting the smallest element of each row
* from all elements of the row as well as the smallest element of each
* column from all elements of the column. Note that an optimal assignment
* for a reduced cost matrix is optimal for the original cost matrix.
*/
protected void reduce() {
for (int w = 0; w < dim; w++) {
double min = Double.POSITIVE_INFINITY;
for (int j = 0; j < dim; j++) {
if (costMatrix[w][j] < min) {
min = costMatrix[w][j];
}
}
for (int j = 0; j < dim; j++) {
costMatrix[w][j] -= min;
}
}
double[] min = new double[dim];
for (int j = 0; j < dim; j++) {
min[j] = Double.POSITIVE_INFINITY;
}
for (int w = 0; w < dim; w++) {
for (int j = 0; j < dim; j++) {
if (costMatrix[w][j] < min[j]) {
min[j] = costMatrix[w][j];
}
}
}
for (int w = 0; w < dim; w++) {
for (int j = 0; j < dim; j++) {
costMatrix[w][j] -= min[j];
}
}
}
/**
* Update labels with the specified slack by adding the slack value for
* committed workers and by subtracting the slack value for committed jobs.
* In addition, update the minimum slack values appropriately.
*
* @param slack the specified slack for which labels will be updated
*/
protected void updateLabeling(double slack) {
for (int w = 0; w < dim; w++) {
if (committedWorkers[w]) {
labelByWorker[w] += slack;
}
}
for (int j = 0; j < dim; j++) {
if (parentWorkerByCommittedJob[j] != -1) {
labelByJob[j] -= slack;
} else {
minSlackValueByJob[j] -= slack;
}
}
}
}
euclid-euclid-2.13/src/main/java/blogspot/software_and_algorithms/stern_library/string/ 0000775 0000000 0000000 00000000000 15101666221 0031526 5 ustar 00root root 0000000 0000000 DamerauLevenshteinAlgorithm.java 0000664 0000000 0000000 00000014254 15101666221 0037752 0 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/java/blogspot/software_and_algorithms/stern_library/string package blogspot.software_and_algorithms.stern_library.string;
import java.util.HashMap;
import java.util.Map;
/* Copyright (c) 2012 Kevin L. Stern
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* The Damerau-Levenshtein Algorithm is an extension to the Levenshtein
* Algorithm which solves the edit distance problem between a source string and
* a target string with the following operations:
*
*
*
Character Insertion
*
Character Deletion
*
Character Replacement
*
Adjacent Character Swap
*
*
* Note that the adjacent character swap operation is an edit that may be
* applied when two adjacent characters in the source string match two adjacent
* characters in the target string, but in reverse order, rather than a general
* allowance for adjacent character swaps.
*
*
* This implementation allows the client to specify the costs of the various
* edit operations with the restriction that the cost of two swap operations
* must not be less than the cost of a delete operation followed by an insert
* operation. This restriction is required to preclude two swaps involving the
* same character being required for optimality which, in turn, enables a fast
* dynamic programming solution.
*
*
* The running time of the Damerau-Levenshtein algorithm is O(n*m) where n is
* the length of the source string and m is the length of the target string.
* This implementation consumes O(n*m) space.
*
* @author Kevin L. Stern
*/
public class DamerauLevenshteinAlgorithm {
private final int deleteCost, insertCost, replaceCost, swapCost;
/**
* Constructor.
*
* @param deleteCost
* the cost of deleting a character.
* @param insertCost
* the cost of inserting a character.
* @param replaceCost
* the cost of replacing a character.
* @param swapCost
* the cost of swapping two adjacent characters.
*/
public DamerauLevenshteinAlgorithm(int deleteCost, int insertCost,
int replaceCost, int swapCost) {
/*
* Required to facilitate the premise to the algorithm that two swaps of
* the same character are never required for optimality.
*/
if (2 * swapCost < insertCost + deleteCost) {
throw new IllegalArgumentException("Unsupported cost assignment");
}
this.deleteCost = deleteCost;
this.insertCost = insertCost;
this.replaceCost = replaceCost;
this.swapCost = swapCost;
}
/**
* Compute the Damerau-Levenshtein distance between the specified source
* string and the specified target string.
* @param source the source string
* @param target the target string
* @return Damerau-Levenshtein distance between the specified source
*/
public int execute(String source, String target) {
if (source.length() == 0) {
return target.length() * insertCost;
}
if (target.length() == 0) {
return source.length() * deleteCost;
}
int[][] table = new int[source.length()][target.length()];
Map sourceIndexByCharacter = new HashMap();
if (source.charAt(0) != target.charAt(0)) {
table[0][0] = Math.min(replaceCost, deleteCost + insertCost);
}
sourceIndexByCharacter.put(source.charAt(0), 0);
for (int i = 1; i < source.length(); i++) {
int deleteDistance = table[i - 1][0] + deleteCost;
int insertDistance = (i + 1) * deleteCost + insertCost;
int matchDistance = i * deleteCost
+ (source.charAt(i) == target.charAt(0) ? 0 : replaceCost);
table[i][0] = Math.min(Math.min(deleteDistance, insertDistance),
matchDistance);
}
for (int j = 1; j < target.length(); j++) {
int deleteDistance = table[0][j - 1] + insertCost;
int insertDistance = (j + 1) * insertCost + deleteCost;
int matchDistance = j * insertCost
+ (source.charAt(0) == target.charAt(j) ? 0 : replaceCost);
table[0][j] = Math.min(Math.min(deleteDistance, insertDistance),
matchDistance);
}
for (int i = 1; i < source.length(); i++) {
int maxSourceLetterMatchIndex = source.charAt(i) == target
.charAt(0) ? 0 : -1;
for (int j = 1; j < target.length(); j++) {
Integer candidateSwapIndex = sourceIndexByCharacter.get(target
.charAt(j));
int jSwap = maxSourceLetterMatchIndex;
int deleteDistance = table[i - 1][j] + deleteCost;
int insertDistance = table[i][j - 1] + insertCost;
int matchDistance = table[i - 1][j - 1];
if (source.charAt(i) != target.charAt(j)) {
matchDistance += replaceCost;
} else {
maxSourceLetterMatchIndex = j;
}
int swapDistance;
if (candidateSwapIndex != null && jSwap != -1) {
int iSwap = candidateSwapIndex;
int preSwapCost;
if (iSwap == 0 && jSwap == 0) {
preSwapCost = 0;
} else {
preSwapCost = table[Math.max(0, iSwap - 1)][Math.max(0,
jSwap - 1)];
}
swapDistance = preSwapCost + (i - iSwap - 1) * deleteCost
+ (j - jSwap - 1) * insertCost + swapCost;
} else {
swapDistance = Integer.MAX_VALUE;
}
table[i][j] = Math.min(
Math.min(Math.min(deleteDistance, insertDistance),
matchDistance), swapDistance);
}
sourceIndexByCharacter.put(source.charAt(i), i);
}
return table[source.length() - 1][target.length() - 1];
}
}
KnuthMorrisPrattAlgorithm.java 0000664 0000000 0000000 00000007112 15101666221 0037462 0 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/java/blogspot/software_and_algorithms/stern_library/string package blogspot.software_and_algorithms.stern_library.string;
/* Copyright (c) 2012 Kevin L. Stern
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* An implementation of the Knuth Morris Pratt substring search algorithm. An
* instance of the algorithm is constructed around a needle string of length m,
* a process which consumes O(m) time as well as O(m) space. Once an instance is
* constructed, it is capable of searching for the needle string in any number
* of haystack strings. The search process consumes O(n) time in a haystack
* string of length n.
*
* @author Kevin L. Stern
*/
public class KnuthMorrisPrattAlgorithm {
private final String needle;
private final int[] stateTransitionTable;
/**
* Constructor.
*
* @param needle
* the search string for which the instance will be constructed.
*/
public KnuthMorrisPrattAlgorithm(String needle) {
this.needle = needle;
this.stateTransitionTable = new int[needle.length()];
stateTransitionTable[0] = -1;
int state = 0;
for (int i = 1; i < needle.length(); i++) {
int transition = state;
if (needle.charAt(transition) == needle.charAt(i)) {
transition = stateTransitionTable[transition];
}
stateTransitionTable[i] = transition;
if (needle.charAt(i) == needle.charAt(state)) {
state += 1;
} else {
state = 0;
}
}
}
/**
* Execute the search algorithm.
*
* @param haystack
* the string in which to search for the needle specified at
* construction time.
* @return the index of the first occurrence of the needle string within the
* specified haystack string, -1 if none.
*/
public int execute(String haystack) {
return execute(haystack, 0);
}
/**
* Execute the search algorithm.
*
* @param haystack
* the string in which to search for the needle specified at
* construction time.
* @param index
* the index at which to begin the search within the haystack
* string.
* @return the index of the first occurrence of the needle string within the
* specified portion of the haystack string, -1 if none.
*/
public int execute(String haystack, int index) {
int state = 0;
for (int i = index; i < haystack.length(); i++) {
if (haystack.charAt(i) == needle.charAt(state)) {
state += 1;
if (state == needle.length()) {
return i - needle.length() + 1;
}
} else {
do {
state = stateTransitionTable[state];
} while (state >= 0
&& haystack.charAt(i) != needle.charAt(state));
state += 1;
}
}
return -1;
}
}
euclid-euclid-2.13/src/main/java/org/ 0000775 0000000 0000000 00000000000 15101666221 0017372 5 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/java/org/xmlcml/ 0000775 0000000 0000000 00000000000 15101666221 0020666 5 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/java/org/xmlcml/args/ 0000775 0000000 0000000 00000000000 15101666221 0021622 5 ustar 00root root 0000000 0000000 euclid-euclid-2.13/src/main/java/org/xmlcml/args/ArgIterator.java-old 0000664 0000000 0000000 00000013103 15101666221 0025462 0 ustar 00root root 0000000 0000000 package org.xmlcml.args;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.xmlcml.euclid.IntArray;
import org.xmlcml.euclid.IntRange;
import org.xmlcml.euclid.RealArray;
import org.xmlcml.euclid.RealRange;
/** wraps ListIterator as this causes reflection problems.
*
* Tokens of form -[digit]... are treated as numbers
* Tokens of form -[letter]... are treated as flags
*
* @author pm286
*
*/
@Deprecated
public class ArgIterator {
private static final Logger LOG = Logger.getLogger(ArgIterator.class);
static {
LOG.setLevel(Level.DEBUG);
}
private final static char MINUS = '-';
private ListIterator listIterator;
private RealArray doubleArray;
public ArgIterator(ListIterator listIterator) {
this.listIterator = listIterator;
}
public ArgIterator(String[] args) {
listIterator = args == null ? null : Arrays.asList(args).listIterator();
}
public boolean hasNext() {
return listIterator == null ? false : listIterator.hasNext();
}
public String previous() {
return listIterator == null ? null : listIterator.previous();
}
public String next() {
return listIterator == null ? null : listIterator.next();
}
/** read tokens until next - sign.
*
* minus must be folloed by a letter, not a number
* leave iterator ready to read next minus
*
* @param argIterator
* @return
*/
public List createTokenListUpToNextNonDigitMinus(ArgumentOption argumentOption) {
List list = this.createTokenListUpToNextNonDigitMinus();
checkListSemantics(argumentOption, list);
return list;
}
private void checkListSemantics(ArgumentOption argumentOption, List list) {
String msg = null;
msg = argumentOption.checkArgumentCount(list);
if (msg != null) throw new IllegalArgumentException(argumentOption.getVerbose()+"; "+msg);
msg = argumentOption.checkArgumentValues(list);
if (msg != null) throw new IllegalArgumentException(argumentOption.getVerbose()+"; "+msg);
}
/** read tokens until next - sign.
*
* leave iterator ready to read next minus
*
* @param argIterator
* @return
*/
public List createTokenListUpToNextNonDigitMinus() {
List list = new ArrayList();
while (this.hasNext()) {
String next = this.next();
Character next1 = next.length() <= 1 ? null : next.charAt(1);
// flag is -letter... or --
if (next.charAt(0) == MINUS && (Character.isLetter(next1) || next1 == MINUS)) {
this.previous();
break;
}
list.add(next);
}
return list;
}
// STRING
public List getStrings(ArgumentOption option) {
return createTokenListUpToNextNonDigitMinus(option);
}
public String getString(ArgumentOption option) {
List tokens = createTokenListUpToNextNonDigitMinus(option);
if (tokens.size() != 1) {
throw new RuntimeException("Expected only 1 argument; found: "+tokens.size());
}
return tokens.get(0);
}
// BOOLEAN
public Boolean getBoolean(ArgumentOption option) {
Boolean bool = null;
String s = getString(option);
try {
bool = new Boolean(s);
} catch (Exception e) {
throw new RuntimeException("Cannot create a Boolean from: "+s);
}
return bool;
}
// DOUBLE
public Double getDouble(ArgumentOption option) {
Double dubble = null;
String s = getString(option);
try {
dubble = new Double(s);
} catch (Exception e) {
throw new RuntimeException("Cannot create a Double from: "+s);
}
return dubble;
}
// REAL RANGE
public RealRange getRealRange(ArgumentOption option) {
List tokens = this.createTokenListUpToNextNonDigitMinus(option);
List intRangeList = RealRange.createRealRangeList(tokens);
if (intRangeList.size() != 1) {
throw new RuntimeException("requires exactly one RealRange token: "+tokens);
}
return intRangeList.get(0);
}
public List getRealRangeList(ArgumentOption option) {
List tokens = this.createTokenListUpToNextNonDigitMinus(option);
return RealRange.createRealRangeList(tokens);
}
// REAL ARRAY
public RealArray getDoubleArray(ArgumentOption option) {
List tokens = this.createTokenListUpToNextNonDigitMinus(option);
RealArray realArray = null;
try {
realArray = new RealArray(tokens.toArray(new String[0]));
} catch (Exception e) {
throw new RuntimeException("bad real array"+tokens, e);
}
return realArray;
}
// INTEGER
public Integer getInteger(ArgumentOption option) {
Integer intg = null;
String s = getString(option);
try {
intg = new Integer(s);
} catch (Exception e) {
throw new RuntimeException("Cannot create an Integer from: "+s, e);
}
return intg;
}
// INT RANGE
public IntRange getIntRange(ArgumentOption option) {
List tokens = this.createTokenListUpToNextNonDigitMinus(option);
List intRangeList = IntRange.createIntRangeList(tokens);
if (intRangeList.size() != 1) {
throw new RuntimeException("requires exactly one IntRange token: "+tokens);
}
return intRangeList.get(0);
}
public List getIntRangeList(ArgumentOption option) {
List tokens = this.createTokenListUpToNextNonDigitMinus(option);
return IntRange.createIntRangeList(tokens);
}
// INT ARRAY
public IntArray getIntArray(ArgumentOption option) {
List tokens = this.createTokenListUpToNextNonDigitMinus(option);
IntArray intArray = null;
try {
intArray = new IntArray(tokens.toArray(new String[0]));
} catch (Exception e) {
throw new RuntimeException("bad integer array"+tokens, e);
}
return intArray;
}
} euclid-euclid-2.13/src/main/java/org/xmlcml/args/ArgumentOption.java-old 0000664 0000000 0000000 00000061666 15101666221 0026233 0 ustar 00root root 0000000 0000000 package org.xmlcml.args;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import nu.xom.Attribute;
import nu.xom.Element;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.xmlcml.euclid.IntRange;
import org.xmlcml.euclid.RealRange;
import org.xmlcml.xml.XMLUtil;
/** simple option for controlling arguments.
*
* @author pm286
*
*/
@Deprecated
public class ArgumentOption {
private static final String BRIEF = "brief";
private static final String LONG = "long";
public static final String NAME = "name";
private static final String HELP = "help";
public static final String VALUE = "value";
private static final String ARGS = "args";
private static final String CLASS_TYPE = "class";
private static final String DEFAULT = "default";
private static final String COUNT_RANGE = "countRange";
private static final String VALUE_RANGE = "valueRange";
private static final String FINAL_METHOD = "finalMethod";
private static final String INIT_METHOD = "initMethod";
private static final String OUTPUT_METHOD = "outputMethod";
private static final String PARSE_METHOD = "parseMethod";
private static final String RUN_METHOD = "runMethod";
// these may be obsolete
private static final String FORBIDDEN = "forbidden";
private static final String REQUIRED = "required";
private static final String PATTERN = "pattern";
private static final Pattern INT_RANGE = Pattern.compile("\\{(\\*|\\-?\\d+),(\\-?\\d*|\\*)\\}");
private static final Pattern DOUBLE_RANGE = Pattern.compile("\\{(\\-?\\+?\\d+\\.?\\d*|\\*),(\\-?\\+?\\d+\\.?\\d*|\\*)\\}");
public static String CLASSNAME = "className";
private static final Logger LOG = Logger.getLogger(ArgumentOption.class);
static {
LOG.setLevel(Level.DEBUG);
}
private static Set MANDATORY_ATTRIBUTES;
static {
MANDATORY_ATTRIBUTES = new HashSet();
MANDATORY_ATTRIBUTES.add(NAME);
MANDATORY_ATTRIBUTES.add(LONG);
MANDATORY_ATTRIBUTES.add(ARGS);
// MANDATORY_ATTRIBUTES.add(PARSE_METHOD); // not required for some args
}
private static Set MANDATORY_CHILDREN;
static {
MANDATORY_CHILDREN = new HashSet();
MANDATORY_CHILDREN.add(HELP);
}
private static Map OPTIONAL_ATTRIBUTES;
static {
OPTIONAL_ATTRIBUTES = new HashMap();
OPTIONAL_ATTRIBUTES.put(CLASS_TYPE, "java.lang.String"); // class defaults to String
OPTIONAL_ATTRIBUTES.put(DEFAULT, ""); // default defaults to ""
}
private String name;
private String brief;
private String verbose;
private String help;
private Class> classType;
private Object defalt;
private IntRange countRange;
private String countRangeString;
private IntRange intValueRange = null;
private RealRange realValueRange = null;
private String valueRangeString;
private String patternString = null;
private Pattern pattern = null;
private String forbiddenString = null;
private List forbiddenArguments = null;
private String requiredString = null;
private List requiredArguments = null;
private List defaultStrings;
private List defaultIntegers;
private List defaultDoubles;
private List stringValues;
private List doubleValues;
private List integerValues;
private Double defaultDouble;
private String defaultString;
private Integer defaultInteger;
private Boolean defaultBoolean;
private String stringValue;
private Integer integerValue;
private Double doubleValue;
private Boolean booleanValue;
private String args;
private List stringPairValues;
private String parseMethodName;
private String runMethodName;
private String outputMethodName;
private String finalMethodName;
private String initMethodName;
private Class extends DefaultArgProcessor> argProcessorClass;
private List valueNodes;
private List helpNodes;
private Element element;
public ArgumentOption(Class extends DefaultArgProcessor> argProcessorClass) {
setDefaults();
this.argProcessorClass = argProcessorClass;
}
private void setDefaults() {
brief = "";
intValueRange = new IntRange(-Integer.MAX_VALUE, Integer.MAX_VALUE);
realValueRange = new RealRange(-Double.MAX_VALUE, Double.MAX_VALUE);
}
/** factory method option for ArgumentOptions
*
* @param argProcessor
* @param element
* @return
*/
public static ArgumentOption createOption(Class extends DefaultArgProcessor> argProcessor, Element element) {
ArgumentOption argumentOption = new ArgumentOption(argProcessor);
argumentOption.setElement(element);
Set mandatorySet = new HashSet(MANDATORY_ATTRIBUTES);
Map optionalAttributes = new HashMap(OPTIONAL_ATTRIBUTES);
// get class first because so much else depends
String classType = element.getAttributeValue(CLASS_TYPE);
argumentOption.setClassType(classType);
lookForKnownAttributes(element, argumentOption, mandatorySet, optionalAttributes);
if (mandatorySet.size() > 0) {
throw new RuntimeException("The following attributes for "+argumentOption.name+" are mandatory: "+mandatorySet);
}
argumentOption.getDefaults(optionalAttributes);
argumentOption.getOrCreateHelpNodes();
argumentOption.getOrCreateValues();
return argumentOption;
}
private void setElement(Element element) {
this.element = element;
}
private void getDefaults(Map optionalAttributes) {
for (String name : optionalAttributes.keySet()) {
String value = optionalAttributes.get(name);
if (value != null) {
this.setValue(name, value);
}
}
}
public List