pax_global_header 0000666 0000000 0000000 00000000064 15210735573 0014522 g ustar 00root root 0000000 0000000 52 comment=d175fcae974976666c6d0f0a8c1c9f8ec6272a14
euclid-euclid-2.18/ 0000775 0000000 0000000 00000000000 15210735573 0014164 5 ustar 00root root 0000000 0000000 euclid-euclid-2.18/.github/ 0000775 0000000 0000000 00000000000 15210735573 0015524 5 ustar 00root root 0000000 0000000 euclid-euclid-2.18/.github/workflows/ 0000775 0000000 0000000 00000000000 15210735573 0017561 5 ustar 00root root 0000000 0000000 euclid-euclid-2.18/.github/workflows/maven.yml 0000664 0000000 0000000 00000001713 15210735573 0021414 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.18/.gitignore 0000664 0000000 0000000 00000000172 15210735573 0016154 0 ustar 00root root 0000000 0000000 foo
.project
.settings/
.classpath
^.hgignore~$
^.gitignore~$
^target/.*
target/
# IntelliJ Idear files
/.idea/*
**/*.iml
euclid-euclid-2.18/CITATION.cff 0000664 0000000 0000000 00000001044 15210735573 0016055 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.18
date-released: 2026-06-06
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.18/LICENSE.txt 0000664 0000000 0000000 00000026135 15210735573 0016016 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.18/README.md 0000664 0000000 0000000 00000002327 15210735573 0015447 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.19-SNAPSHOT
```
Deploy to Sonatype with the following commands, for snapshots and releases respectively:
```shell
mvn clean deploy
```
euclid-euclid-2.18/pom.xml 0000664 0000000 0000000 00000027213 15210735573 0015506 0 ustar 00root root 0000000 0000000
* 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
* 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
* 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
* 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
*
* 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.18/src/main/java/blogspot/software_and_algorithms/stern_library/string/ 0000775 0000000 0000000 00000000000 15210735573 0031543 5 ustar 00root root 0000000 0000000 DamerauLevenshteinAlgorithm.java 0000664 0000000 0000000 00000014254 15210735573 0037767 0 ustar 00root root 0000000 0000000 euclid-euclid-2.18/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:
*
*
*
* 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
* To construct an angle the user must consciously use RADIANS
*
* The angle returned is always in RADIANS (except if getDegrees() is used)
*
*
* Default value of Angle is 0.0; Constructions of invalid angles should throw
* exceptions rather than try to make invalid angles.
*
* @author (C) P. Murray-Rust, 1996
*/
public class Angle {
private final static Logger LOG = Logger.getLogger(Angle.class);
/** units */
public enum Units {
/** */
DEGREES,
/** */
RADIANS;
}
/** range */
public enum Range {
/**
* any value.
*/
UNLIMITED,
/**
* 0 to 2*PI.
*/
UNSIGNED,
/**
* -PI to PI.
*/
SIGNED;
}
/**
* default is UNLIMITED
*/
Range range = Range.UNLIMITED;
/**
* default is RADIANS
*/
Units type = Units.RADIANS;
/** */
public final static double DEGREES_IN_RADIAN = 180.0 / Math.PI;
/**
* ALWAYS held as radians internally
*/
double angle = 0.0;
/**
* create default Angle default is (0.0)
*/
public Angle() {
}
/**
* create an angle IN RADIANS
*
* @param a radian value
*/
public Angle(double a) {
angle = a;
}
/**
* construct using degrees or radians
*
* @param a value of angle
* @param units unit of angle. It can either be in DEGREES or RADIANS
*/
public Angle(double a, Units units) {
angle = (units == Units.RADIANS) ? a : a / DEGREES_IN_RADIAN;
}
/**
* from X and Y components (uses atan2)
*
* @param x The x coordinate of the point
* @param y The y coordinate of the point
*/
public Angle(double y, double x) {
angle = Math.atan2(y, x);
}
/**
* copy constructor
*
* @param a Angle object that needs to be copied
*/
public Angle(Angle a) {
angle = a.angle;
range = a.range;
type = a.type;
}
/**
* shallowCopy
*
* @param a Angle object that needs to be copied
*/
public void shallowCopy(Angle a) {
range = a.range;
type = a.type;
angle = a.angle;
}
/**
* add two angles
*
* @param a2 the specified angle to be added to this angle
* @return new angle
*/
public Angle plus(Angle a2) {
Angle temp = new Angle(angle + a2.angle);
return temp;
}
/**
* subtract two angles
*
* @param a2 the specified angle to be subtracted from this angle
* @return new angle
*/
public Angle subtract(Angle a2) {
Angle temp = new Angle(angle - a2.angle);
return temp;
}
/**
* multiply an angle by a scalar
*
* @param f a floating point scalar value
* @return new angle
*/
public Angle multiplyBy(double f) {
Angle temp = new Angle(angle * f);
return temp;
}
/**
* trigonometric functions
*
* @return cosine of angle
*/
public double cos() {
return Math.cos(angle);
}
/**
* sin of angle
*
* @return sine
*/
public double sin() {
return Math.sin(angle);
}
/**
* tan.
*
* @return the tan
*/
public double tan() {
return Math.tan(angle);
}
/**
* normalise angle. to range 0 -{@literal >} 2*PI
*
* @param angle the angle to be normalised
* @return normalised angle
*/
public static double normalise(double angle) {
while (angle > 2 * Math.PI) {
angle -= 2 * Math.PI;
}
while (angle < 0.0) {
angle += 2 * Math.PI;
}
LOG.trace(angle);
return angle;
}
/** normalizes angle to be in range - Math.PI -{@literal >} Math.PI.
*
*/
public void normalizeToPlusMinusPI() {
angle = Angle.normalise(angle);
if (angle > Math.PI) {
angle -= 2 * Math.PI;
}
}
/**
* Normalises angle to be in range 0 -> Math.PI * 2.
*/
public void normalizeTo2Pi() {
angle = Angle.normalise(angle);
}
/**
* Tests whether this is a right angle.
*
* @param eps tolerance
* @return 1 for PI/2, -1 for -PI/2 else 0
*/
public Integer getRightAngle(Angle eps) {
if (eps == null) return null;
double absEps = Math.abs(eps.getRadian());
normalizeToPlusMinusPI();
Integer rt = 0;
if (Math.abs(Math.PI / 2. - this.getRadian()) < absEps) {
rt = 1;
} else if (Math.abs(-Math.PI / 2. - this.getRadian()) < absEps) {
rt = -1;
}
return rt;
}
/**
* relational operators normalise the angles internally before comparison
*/
/**
* are two normalised angles equal.
*
* @param a the specified angle to which this angle is compared
* @return boolean
* @deprecated // use epsilon method
*
*/
public boolean isEqualTo(double a) {
return Real.isEqual(Angle.normalise(angle), Angle.normalise(a));
}
/** compare angles allowing for epsilon
*
* @param a the specified angle to which this angle is compared to be equal to
* @param epsilon tolerance limit for equality
* @return boolean
*/
public boolean isEqualTo(double a, double epsilon) {
return Real.isEqual(Angle.normalise(angle), Angle.normalise(a), epsilon);
}
/**
* is one angle greater than another (after normalisation)
*
* @param a the specified angle to which this angle is compared to be greater
* @return greater than
*/
public boolean greaterThan(double a) {
return Angle.normalise(angle) > Angle.normalise(a);
}
/**
* is one angle greater than or equal to another (after normalisation)
*
* @param a the specified angle to which this angle is compared to be greater than or equal to
* @return greater than or equals
*/
public boolean greaterThanOrEquals(double a) {
return Angle.normalise(angle) >= Angle.normalise(a);
}
/**
* is one angle less than another (after normalisation)
*
* @param a the specified angle to which this angle is compared to be lesser
* @return {@literal <}
*/
public boolean lessThan(double a) {
return Angle.normalise(angle) < Angle.normalise(a);
}
/**
* is one angle less than or equal to another (after normalisation)
*
* @param a the specified angle to which this angle is compared to be lesser than or equal to
* @return {@literal <}=
*/
public boolean lessThanOrEquals(double a) {
return Angle.normalise(angle) <= Angle.normalise(a);
}
/**
* are two angles equal
*
* @param a the specified angle to which this angle is compared to be equal to
* @return ==
*/
public boolean isEqualTo(Angle a) {
return isEqualTo(a.angle);
}
/**
* are two angles equal
*
* @param a the specified angle to which this angle is compared to be equal to
* @param eps epsilon tolerance limit for equality
* @return ==
*/
public boolean isEqualTo(Angle a, double eps) {
return a != null && Real.isEqual(a.getRadian(), this.getRadian(), eps);
}
/**
* is one angle greater than another (after normalisation)
*
* @param a the specified angle to which this angle is compared to be greater (after normalisation)
* @return {@literal >}
*/
public boolean greaterThan(Angle a) {
return greaterThan(a.angle);
}
/**
* is one angle greater than or equal to another (after normalisation)
*
* @param a the specified angle to which this angle is compared to be greater than or equal to (after normalisation)
* @return {@literal >}=
*/
public boolean greaterThanOrEquals(Angle a) {
return greaterThanOrEquals(a.angle);
}
/**
* is one angle less than another (after normalisation)
*
* @param a the specified angle to which this angle is compared to be lesser (after normalisation)
* @return {@literal <}
*/
public boolean lessThan(Angle a) {
return lessThan(a.angle);
}
/**
* is one angle less than or equal to another (after normalisation)
*
* @param a the specified angle to which this angle is compared to be lesser than or equal to (after normalisation)
* @return {@literal <}=
*/
public boolean lessThanOrEquals(Angle a) {
return lessThanOrEquals(a.angle);
}
/**
* get angle in radians
*
* @return angle
*/
public double getAngle() {
return adjust(angle);
}
/**
* get angle in radians
*
* @return angle
*/
public double getRadian() {
return adjust(angle);
}
/**
* get angle in degrees
*
* @return angle
*/
public double getDegrees() {
return adjust(angle) * DEGREES_IN_RADIAN;
}
/**
* @param a angle in degrees
*/
public void putDegrees(double a) {
angle = a / DEGREES_IN_RADIAN;
}
/**
* set type of range
*
* @param range type of range
*/
public void setRange(Range range) {
this.range = range;
}
/**
* set angle to correct range
*/
private double adjust(double a) {
if (range == Range.UNLIMITED)
return a;
double temp = normalise(a);
if (range == Range.UNSIGNED) {
return temp;
}
if (temp > Math.PI) {
temp -= 2 * Math.PI;
} else if (temp < -Math.PI) {
temp += 2 * Math.PI;
}
return temp;
}
/**
* to string.
*
* @return string
*/
public String toString() {
StringBuffer s = new StringBuffer();
double temp = adjust(angle);
if (type == Units.DEGREES) {
s.append(temp).append(" degrees");
} else {
s.append(temp);
}
return s.toString();
}
}
euclid-euclid-2.18/src/main/java/org/xmlcml/euclid/ArrayBase.java 0000664 0000000 0000000 00000002341 15210735573 0024664 0 ustar 00root root 0000000 0000000 /**
* Copyright 2011 Peter Murray-Rust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.xmlcml.euclid;
import org.apache.log4j.Logger;
/**
* super class of array methods
*
* @author (C) P. Murray-Rust, 1996
*/
public abstract class ArrayBase implements EuclidConstants {
final static Logger LOG = Logger.getLogger(ArrayBase.class);
/** */
public enum Trim {
/** */
ABOVE(1),
/** */
BELOW(2);
/** */
public int trim;
private Trim(int t) {
this.trim = t;
}
}
/** splits string versions of arrays.
*
*/
public final static String ARRAY_REGEX = "\\s+|\\s*\\|\\s*|\\s*\\,\\s*";
}
euclid-euclid-2.18/src/main/java/org/xmlcml/euclid/Axis.java 0000664 0000000 0000000 00000004276 15210735573 0023730 0 ustar 00root root 0000000 0000000 /**
* Copyright 2011 Peter Murray-Rust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.xmlcml.euclid;
/**
* enums to represent 2- or 3-D axes
*
* @author (C) P. Murray-Rust, 2005
*/
public class Axis {
/** enum for x y z axes */
public enum Axis2 {
/**
* x axis. value is 0 for indexing arrays.
*/
X("x", 0),
/**
* y axis. value is 1 for indexing arrays.
*/
Y("y", 1);
/** string value */
public final String axis;
/** integer value */
public final int value;
/**
* constructor.
*
* @param axis
* label for the axis
* @param value
* serial number (starts at 0)
*/
private Axis2(String axis, int value) {
this.axis = axis;
this.value = value;
}
}
/** 3d axes */
public enum Axis3 {
/**
* x axis. value is 0 for indexing arrays.
*/
X("x", 0),
/**
* y axis. value is 1 for indexing arrays.
*/
Y("y", 1),
/**
* z axis. value is 2 for indexing arrays.
*/
Z("z", 2);
/** string value */
public final String axis;
/** int value */
public final int value;
/**
* constructor.
*
* @param axis
* label for the axis
* @param value
* serial number (starts at 0)
*/
private Axis3(String axis, int value) {
this.axis = axis;
this.value = value;
}
}
}
euclid-euclid-2.18/src/main/java/org/xmlcml/euclid/Bivariate.java 0000775 0000000 0000000 00000005166 15210735573 0024734 0 ustar 00root root 0000000 0000000 /**
* Copyright 2011 Peter Murray-Rust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.xmlcml.euclid;
import org.apache.log4j.Logger;
public class Bivariate {
private final static Logger LOG = Logger.getLogger(Bivariate.class);
private Real2Array real2Array;
private Double slope;
private Double intercept;
private RealArray xarr;
private RealArray yarr;
private Double corrCoeff;
private RealArray residuals;
public Bivariate(Real2Array real2Array) {
this.real2Array = real2Array;
this.xarr = real2Array.getXArray();
this.yarr = real2Array.getYArray();
}
public Double getSlope() {
ensureSlope();
return slope;
}
public Double getIntercept() {
ensureSlope();
return intercept;
}
private void ensureSlope() {
if (slope == null && xarr.size() > 1) {
double count = (double) xarr.size();
double sigmax = xarr.sumAllElements();
double sigmay = yarr.sumAllElements();
double sigmaxy = xarr.sumProductOfAllElements(yarr);
double numerator = sigmaxy - sigmax * sigmay / count;
double sigmax2 = xarr.sumProductOfAllElements(xarr);
double sigmay2 = yarr.sumProductOfAllElements(yarr);
double denominator = sigmax2 - sigmax * sigmax / count;
slope = numerator / denominator;
intercept = sigmay / count - slope * sigmax / count;
corrCoeff = (count * sigmaxy - sigmax * sigmay) /
Math.sqrt((count * sigmax2 - sigmax * sigmax)*(count * sigmay2 - sigmay * sigmay));
}
}
public Double getCorrelationCoefficient() {
ensureSlope();
return corrCoeff;
}
public RealArray getResiduals() {
ensureSlope();
residuals = new RealArray(xarr.size());
for (int i = 0; i < xarr.size(); i++) {
double deltay = yarr.elementAt(i) - (slope * xarr.elementAt(i) + intercept);
residuals.setElementAt(i, deltay);
}
return residuals;
}
public RealArray getNormalizedResiduals() {
getResiduals();
LOG.trace("R> "+residuals.format(2));
Univariate univariate = new Univariate(residuals);
RealArray normalisedResiduals = univariate.getNormalizedValues();
LOG.trace("N> "+normalisedResiduals.format(2));
return normalisedResiduals;
}
}
euclid-euclid-2.18/src/main/java/org/xmlcml/euclid/Complex.java 0000664 0000000 0000000 00000010177 15210735573 0024430 0 ustar 00root root 0000000 0000000 /**
* Copyright 2011 Peter Murray-Rust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.xmlcml.euclid;
/**
* A complex number derived from Real2
*
* Complex represents a complex number A reasonable number of arithmetic
* operations are included DeMoivre's theorem is used for some of them so there
* may be quicker implementations elsewhere.
*
* @author (C) P. Murray-Rust, 1996
*/
public class Complex extends Real2 {
/**
* constructor.
*/
public Complex() {
super();
}
/**
* real component only
*
* @param a
*/
public Complex(double a) {
super(a, 0.0);
}
/**
* from components
*
* @param a
* @param b
*/
public Complex(double a, double b) {
super(a, b);
}
/**
* from base class
*
* @param a
*/
public Complex(Real2 a) {
this.x = a.x;
this.y = a.y;
}
/**
* in polar coords
*
* @param r
* @param th
*/
public Complex(double r, Angle th) {
Polar p = new Polar(r, th);
x = p.getX();
y = p.getY();
}
/**
* construct from polar
*
* @param p
*/
public Complex(Polar p) {
x = p.getX();
y = p.getY();
}
/**
* copy constructor
*
* @param a
*/
public Complex(Complex a) {
this.x = a.x;
this.y = a.y;
}
/**
* gets real part.
*
* @return real part
*/
public double getReal() {
return x;
}
/**
* gets imaginary part.
*
* @return imaginary
*
*/
public double getImaginary() {
return y;
}
/**
* unary minus MODIFIES object
*/
public void negative() {
this.x = -this.x;
this.y = -this.y;
}
/**
* multiply a complex by a complex.
*
* @param f
* @return complex
*/
public Complex multiply(Complex f) {
Complex temp = new Complex(this);
temp.x = x * f.x - y * f.y;
temp.y = x * f.y + y * f.x;
return temp;
}
/**
* divide a complex by a complex.
*
* @param f
* @return complex
* @throws EuclidRuntimeException
*/
public Complex divideBy(Complex f) throws EuclidRuntimeException {
double denom = f.x * f.x + f.y * f.y;
if (Real.isZero(denom, Real.getEpsilon())) {
throw new EuclidRuntimeException("cannot divide by zero");
}
Complex temp = new Complex(f.x, -f.y);
temp = new Complex((temp.multiply(this)).multiplyBy(1 / denom));
return temp;
}
/**
* get as polar coords.
*
* @return radius
*/
public double getR() {
double t = Math.sqrt(x * x + y * y);
// double t = x * x + y * y;
return t;
}
/**
* angle.
*
* @return the angle
*/
public Angle getTheta() {
return new Angle(y, x);
}
/**
* polar object.
*
* @return polar object
*/
public Polar getPolar() {
return new Polar(getR(), getTheta());
}
/**
* complex square root.
*
* @param a
* @return complex sqrt
*/
public static Complex sqrt(Complex a) {
Polar temp = new Polar(a);
temp.r = Math.sqrt(temp.r);
temp.theta *= 0.5;
return new Complex(temp);
}
/**
* to string.
*
* @return string
*/
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(x + EC.S_COMMA + y);
return sb.toString();
}
}
euclid-euclid-2.18/src/main/java/org/xmlcml/euclid/DoubleTool.java 0000664 0000000 0000000 00000003413 15210735573 0025064 0 ustar 00root root 0000000 0000000 /**
* Copyright 2011 Peter Murray-Rust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.xmlcml.euclid;
/**
*
*
* Tool providing methods for working with doubles.
*
* Constants
*
* runtime exception for Euclid
*
* Default is two default/invalid IntRange components. Adding points will create
* valid ranges.
*
* @author (C) P. Murray-Rust, 1996
*/
public class Int2Range implements EuclidConstants {
/**
* X-range
*/
IntRange xrange;
/**
* Y-range
*/
IntRange yrange;
/**
* creates zero range.
*
*
*/
public Int2Range() {
xrange = new IntRange();
yrange = new IntRange();
}
/**
* initialise with min and max values;
*
* @param xr X-range
* @param yr Y-range
*/
public Int2Range(IntRange xr, IntRange yr) {
if (xr.isValid() && yr.isValid()) {
xrange = xr;
yrange = yr;
}
}
/**
* copy constructor
*
* @param r the IntRange object to be copied
*/
public Int2Range(Int2Range r) {
if (r.isValid()) {
xrange = new IntRange(r.xrange);
yrange = new IntRange(r.yrange);
}
}
/**
* copy constructor
*
* @param r the IntRange object to be copied
*/
public Int2Range(Real2Range r) {
xrange = new IntRange(r.xrange);
yrange = new IntRange(r.yrange);
}
/**
* a Int2Range is valid if both its constituent ranges are
*
* @return valid
*/
public boolean isValid() {
return (xrange != null && yrange != null && xrange.isValid() && yrange
.isValid());
}
/**
* is equal to.
*
* @param r2 the intRange to be compared with this intRange
* @return true if equal
*/
public boolean isEqualTo(Int2Range r2) {
if (isValid() && r2 != null && r2.isValid()) {
return (xrange.isEqualTo(r2.xrange) && yrange.isEqualTo(r2.yrange));
} else {
return false;
}
}
@Override
public boolean equals(Object o) {
boolean equals = false;
if (o != null && o instanceof Int2Range) {
Int2Range i2r =(Int2Range) o;
equals = this.getXRange().equals(i2r.getXRange()) &&
this.getYRange().equals(i2r.getYRange());
}
return equals;
}
@Override
public int hashCode() {
return 17*xrange.hashCode() + 31*yrange.hashCode();
}
/**
* merge two ranges and take the maximum extents
*
* @param r2 the intRange to be added with this intRange
* @return range
*/
public Int2Range plus(Int2Range r2) {
if (!isValid()) {
if (r2 == null || !r2.isValid()) {
return new Int2Range();
} else {
return new Int2Range(r2);
}
}
if (r2 == null || !r2.isValid()) {
return new Int2Range(this);
}
return new Int2Range(xrange.plus(r2.xrange), yrange.plus(r2.yrange));
}
/**
* intersect two ranges and take the range common to both; return invalid
* range if no overlap or either is null/invalid
*
* @param r2
* @return range
*
*/
public Int2Range intersectionWith(Int2Range r2) {
if (!isValid() || r2 == null || !r2.isValid()) {
return new Int2Range();
}
IntRange xr = this.getXRange().intersectionWith(r2.getXRange());
IntRange yr = this.getYRange().intersectionWith(r2.getYRange());
return new Int2Range(xr, yr);
}
/**
* get xrange
*
* @return range
*/
public IntRange getXRange() {
return xrange;
}
/**
* get yrange
*
* @return range
*/
public IntRange getYRange() {
return yrange;
}
/** extends XRange.
*
* does not alter this. Uses range.extendBy(). Positive numbers will expand the range
*
* @param leftSide
* @param rightSide
*/
public Int2Range getInt2RangeExtendedInX(int leftSide, int rightSide) {
Int2Range i2r = new Int2Range(this);
if (i2r.xrange != null) {
i2r.xrange = i2r.xrange.getRangeExtendedBy(leftSide, rightSide);
}
return i2r;
}
/** extends XRange.
*
* does not alter this. Uses range.extendBy(). Positive numbers will expand the range
*
* @param topExtend
* @param bottomExtend
*/
public Int2Range getInt2RangeExtendedInY(int topExtend, int bottomExtend) {
Int2Range i2r = new Int2Range(this);
if (i2r.yrange != null) {
i2r.yrange = i2r.yrange.getRangeExtendedBy(topExtend, bottomExtend);
}
return i2r;
}
/**
* is an Int2 within a Int2Range
*
* @param p
* @return includes
*/
public boolean includes(Int2 p) {
if (!isValid()) {
return false;
}
return (xrange.includes(p.getX()) && yrange.includes(p.getY()));
}
/**
* is one Int2Range completely within another
*
* @param r
* @return includes
*/
public boolean includes(Int2Range r) {
if (!isValid() || r == null || !r.isValid()) {
return false;
}
IntRange xr = r.getXRange();
IntRange yr = r.getYRange();
return (xrange.includes(xr) && yrange.includes(yr));
}
/**
* add a Int2 to a range
*
* @param p
*/
public void add(Int2 p) {
xrange.add(p.getX());
yrange.add(p.getY());
}
/**
* to string.
*
* @return string
*/
public String toString() {
return EC.S_LBRAK + xrange.toString() + EC.S_COMMA + yrange.toString() + EC.S_RBRAK;
}
/** do two boxes touch?
*
* if box a extends to x and box b extends from x+1 they are touching.
* uses IntRange.touches()
*
* Note that if box a and b share an integer coordinate then they *intersect*, not touch
*
* @param bbox
* @return
*/
public boolean touches(Int2Range bbox) {
return this.xrange.touches(bbox.xrange) || this.yrange.touches(bbox.yrange);
}
} euclid-euclid-2.18/src/main/java/org/xmlcml/euclid/IntArray.java 0000664 0000000 0000000 00000117411 15210735573 0024551 0 ustar 00root root 0000000 0000000 /**
* Copyright 2011 Peter Murray-Rust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.xmlcml.euclid;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
/**
* array of ints
*
* IntArray represents a 1-dimensional vector or array of ints and is basically
* a wrapper for int[] in Java There are a lot of useful member functions
* (sorting, ranges, parallel operations The default is an array with zero
* points All arrays are valid objects. Attempting to create an array with {@literal <} 0
* points creates a default array (zero points). Since int[] knows its length
* (unlike C), there are many cases where int[] can be safely used. However it
* is not a first-class object and IntArray supplies this feature int[] is
* referenceable through getArray() note that the length of the internal array
* may not be a useful guide to the number of elements
*
* @author (C) P. Murray-Rust, 1996
*/
public class IntArray extends ArrayBase implements Iterable
* Read the signature of each member function carefully as some MODIFY the
* object and some CREATE A NEW ONE. Among the reasons for this is that
* subclassing (e.g to IntSquareMatrix) is easier with one of these forms in
* certain cases. Note that if you modify an object, then all references to it
* will refer to the changed object
*
* @author (C) P. Murray-Rust, 1996
*/
public class IntMatrix implements EuclidConstants {
final static Logger LOG = Logger.getLogger(IntMatrix.class);
/**
* number of rows
*/
protected int rows = 0;
/**
* number of columns
*/
protected int cols = 0;
/**
* the matrix
*/
protected int[][] flmat = new int[0][0];
DecimalFormat format = null;
/**
* construct default matrix. cols = rows = 0
*/
public IntMatrix() {
}
/**
* Create matrix with given rows and columns. A rows*cols matrix values set
* to 0 (rows or cols {@literal <} 0 defaults to 0)
*
* @param r
* number of rows
* @param c
* number of columns
*/
public IntMatrix(int r, int c) {
if (r < 0)
r = 0;
if (c < 0)
c = 0;
rows = r;
cols = c;
flmat = new int[r][c];
}
/**
* Create from 1-D array. Formed by feeding in an existing 1-D array to a
* rowsXcols matrix THE COLUMN IS THE FASTEST MOVING INDEX, that is the
* matrix is filled as flmat(0,0), flmat(0,1) ... C-LIKE. COPIES the array
*
* @param rows
* @param cols
* @param array
* @exception EuclidRuntimeException
* size of array is not rows*cols
*/
public IntMatrix(int rows, int cols, int[] array) throws EuclidRuntimeException {
this(rows, cols);
check(rows, cols, array);
this.rows = rows;
this.cols = cols;
int count = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
flmat[i][j] = array[count++];
}
}
}
/**
* creates matrix with initialised values.
*
* @param r
* rows
* @param c
* columns
* @param f
* value to initialize with
*/
public IntMatrix(int r, int c, int f) {
this(r, c);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
flmat[i][j] = f;
}
}
}
/**
* create from submatrix of another matrix. fails if lowrow {@literal >} hirow, lowrow {@literal <}
* 0, etc
*
* COPIES the parts of
* Default is range with low {@literal >} high; this can be regarded as the uninitialised
* state. If points are added to a default IntRange it becomes initialised.
*
* @author (C) P. Murray-Rust, 1996
*/
public class IntRange implements EuclidConstants, Comparable
* Does not alter this.
*
* Inverse mapping. IntSets can be used to map one set of indexed data to
* another, for example
*
* {@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<=
* {@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
*
*
* 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.
*
* If SIGNED is used, the angle is in the range -180 to 180 (-pi to pi)
* If UNSIGNED is used, the angle is in the range 0 to 360 (0 to 2*pi)
* Default is SIGNED
* serialVersionUID
*/
private static final long serialVersionUID = 3617576011412288051L;
/**
* constructor.
*/
public EuclidException() {
super();
}
/**
* constructor.
*
* @param s
*/
public EuclidException(String s) {
super(s);
}
}
euclid-euclid-2.18/src/main/java/org/xmlcml/euclid/EuclidRuntimeException.java 0000664 0000000 0000000 00000003024 15210735573 0027442 0 ustar 00root root 0000000 0000000 /**
* Copyright 2011 Peter Murray-Rust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
*/
package org.xmlcml.euclid;
/**
*
*
*
* step is maxval / nn
*
* @param nn
* number of elements
* @param shape
* TRIANGLE or ZIGZAG
* @param maxval
* used to compute step
*/
public IntArray(int nn, String shape, int maxval) {
if (shape.toUpperCase().equals("TRIANGLE")) {
nelem = nn * 2 - 1;
if (!checkSize(nelem))
return;
array = new int[nelem];
int delta = maxval / ((int) nn);
for (int i = 0; i < nn; i++) {
array[i] = (i + 1) * delta;
array[nelem - i - 1] = array[i];
}
} else if (shape.toUpperCase().equals("ZIGZAG")) {
nelem = nn * 4 - 1;
if (!checkSize(nelem))
return;
array = new int[nelem];
int delta = maxval / ((int) nn);
for (int i = 0; i < nn; i++) {
array[i] = (i + 1) * delta;
array[2 * nn - i - 2] = array[i];
array[2 * nn + i] = -array[i];
array[nelem - i - 1] = -array[i];
}
array[2 * nn - 1] = 0;
}
}
/**
* construct from an array of Strings. must represent integers
*
* @param strings values as Strings
* @exception NumberFormatException
* a string could not be interpreted as integer
*/
public IntArray(String[] strings) throws NumberFormatException {
this(strings.length);
for (int i = 0; i < strings.length; i++) {
array[i] = (Integer.valueOf(strings[i])).intValue();
}
}
/**
* create from a space-separated string of integers.
*
* @param string
* of form "1 3 56 2..."
* @exception NumberFormatException
* a substring could not be interpreted as integer
*/
public IntArray(String string) throws NumberFormatException {
this(string.split(S_WHITEREGEX));
}
/**
* contracts internal array to be of same length as number of elements.
*
* should be used if the array will be used elsewhere with a fixed length.
*
*/
public void contractArray() {
int[] array1 = new int[nelem];
System.arraycopy(array, 0, array1, 0, nelem);
array = array1;
}
/**
* shallowCopy
*
* @param m
*/
public void shallowCopy(IntArray m) {
nelem = m.nelem;
bufsize = m.bufsize;
maxelem = m.maxelem;
array = m.array;
}
/**
* get element by index.
*
* @param elem
* the index
* @exception ArrayIndexOutOfBoundsException
* elem {@literal >}= size of this
* @return element value
*/
public int elementAt(int elem) throws ArrayIndexOutOfBoundsException {
return array[elem];
}
/**
* get actual number of elements.
*
* @return number of elements
*/
public int size() {
return nelem;
}
/**
* get java array.
*
* @return the array
*/
public int[] getArray() {
if (nelem != array.length) {
int[] temp = new int[nelem];
System.arraycopy(array, 0, temp, 0, nelem);
array = temp;
}
return array;
}
/**
* are two arrays equal.
*
* @param f
* array to compare
* @return true if arrays are of same size and elements are equal)
*/
public boolean equals(IntArray f) {
boolean equal = false;
try {
checkConformable(f);
equal = true;
for (int i = 0; i < nelem; i++) {
if (array[i] != f.array[i]) {
equal = false;
break;
}
}
} catch (Exception e) {
equal = false;
}
return equal;
}
/**
* clear all elements of array. sets value to 0
*/
public void clearArray() {
for (int i = 0; i < size(); i++) {
array[i] = 0;
}
}
/**
* get java array in reverse order.
*
* @return array
*/
public int[] getReverseArray() {
int count = size();
int[] temp = new int[count];
for (int i = 0; i < size(); i++) {
temp[i] = this.array[--count];
}
return temp;
}
/**
* reset the maximum index (for when poking elements) (no other effect)
*/
/*--
public void setMaxIndex(int max) {
maxelem = max;
}
--*/
private void checkConformable(IntArray m) throws EuclidRuntimeException {
if (nelem != m.nelem) {
throw new EuclidRuntimeException();
}
}
/**
* are two arrays equal.
*
* @param f
* array to compare
* @return true if arrays are of same size and this(i) = f(i)
*/
public boolean isEqualTo(IntArray f) {
boolean equal = false;
try {
checkConformable(f);
equal = true;
for (int i = 0; i < nelem; i++) {
if (array[i] != f.array[i]) {
equal = false;
break;
}
}
} catch (Exception e) {
equal = false;
}
return equal;
}
/**
* adds arrays. does not modify this
*
* @param f
* array to add
* @exception EuclidRuntimeException
* f is different size from this
* @return new array as this + f
*/
public IntArray plus(IntArray f) throws EuclidRuntimeException {
checkConformable(f);
IntArray m = (IntArray) this.clone();
for (int i = 0; i < nelem; i++) {
m.array[i] = f.array[i] + array[i];
}
return m;
}
/**
* subtracts arrays. does not modify this
*
* @param f
* array to substract
* @exception EuclidRuntimeException
* f is different size from this
* @return new array as this - f
*/
public IntArray subtract(IntArray f) throws EuclidRuntimeException {
checkConformable(f);
IntArray m = (IntArray) this.clone();
for (int i = 0; i < nelem; i++) {
m.array[i] = array[i] - f.array[i];
}
return m;
}
/**
* array subtraction. modifies this -= f
*
* @param f
* array to subtract
* @exception EuclidRuntimeException
* f is different size from this
*/
public void subtractEquals(IntArray f) throws EuclidRuntimeException {
checkConformable(f);
for (int i = 0; i < nelem; i++) {
array[i] -= f.array[i];
}
}
/**
* change the sign of all elements. MODIFIES this
*/
public void negative() {
for (int i = 0; i < size(); i++) {
array[i] = -array[i];
}
}
/**
* add a scalar to all elements. creates new array; does NOT modify 'this';
* for subtraction use negative scalar
*
* @param f
* to add
* @return new array
*/
/*--
public RealArray addScalar(int f) {
RealArray m = (RealArray) this.clone();
for(int i = 0; i < nelem; i++) {
m.array[i] += f;
}
return m;
}
--*/
/**
* array multiplication by a scalar. creates new array; does NOT modify
* 'this'
*
* @param f
* multiplier
* @return the new array
*/
public IntArray multiplyBy(int f) {
IntArray m = (IntArray) this.clone();
for (int i = 0; i < nelem; i++) {
m.array[i] *= f;
}
return m;
}
/**
* set element value.
*
* @param elem
* index
* @param f
* value
* @exception ArrayIndexOutOfBoundsException
* elem {@literal >}= size of this
*/
public void setElementAt(int elem, int f)
throws ArrayIndexOutOfBoundsException {
array[elem] = f;
}
/**
* get array slice. creates new array; does not modify this
*
* @param start
* index inclusive
* @param end
* index inclusive
* @return new array
*/
public IntArray getSubArray(int start, int end) {
int nel = end - start + 1;
IntArray f = new IntArray(nel, 0);
System.arraycopy(array, start, f.array, 0, nel);
return f;
}
/**
* set array slice. copy whole array into the array.
*
* @param start
* index in this
* @param a
* array to copy
* @throws ArrayIndexOutOfBoundsException
* start {@literal <} 0 or start+a.length {@literal >} this.size()
*/
public void setElements(int start, int[] a) {
if (start < 0 || start + a.length > nelem) {
throw new ArrayIndexOutOfBoundsException();
}
System.arraycopy(a, 0, this.array, start, a.length);
}
/**
* is the array filled with zeros.
*
* @return true if this(i) = 0
*/
public boolean isClear() {
for (int i = 0; i < nelem; i++) {
if (array[i] != 0)
return false;
}
return true;
}
/**
* initialise array to given value. this(i) = f
*
* @param f
* value to set
*/
public void setAllElements(int f) {
Int.initArray(nelem, array, f);
}
/**
* sum all elements.
*
* @return sigma(this(i))
*/
public int sumAllElements() {
int sum = 0;
for (int i = 0; i < nelem; i++) {
sum += array[i];
}
return sum;
}
/**
* sum of all absolute element values.
*
* @return sigma(abs(this(i)))
*/
public int absSumAllElements() {
int sum = 0;
for (int i = 0; i < nelem; i++) {
sum += Math.abs(array[i]);
}
return sum;
}
/**
* inner product. dotProduct(this)
*
* @return sigma(this(i)**2)
*/
public int innerProduct() {
int result = Integer.MIN_VALUE;
try {
result = this.dotProduct(this);
} catch (EuclidRuntimeException x) {
throw new EuclidRuntimeException("bug " + x);
}
return result;
}
/**
* dot product of two arrays. sigma(this(i)*(f(i));
*
* @param f
* array to multiply
* @exception EuclidRuntimeException
* f is different size from this
* @return dot
*/
public int dotProduct(IntArray f) throws EuclidRuntimeException {
checkConformable(f);
int sum = 0;
for (int i = 0; i < nelem; i++) {
sum += array[i] * f.array[i];
}
return sum;
}
/**
* cumulative sum of array. create new array as elem[i] = sum(k = 0 to i)
* f[k] does not modify 'this'
*
* @return each element is cumulative sum to that point
*/
public IntArray cumulativeSum() {
IntArray temp = new IntArray(nelem);
int sum = 0;
for (int i = 0; i < nelem; i++) {
sum += array[i];
temp.array[i] = sum;
}
return temp;
}
/**
* apply filter. convolute array with another array. This is 1-D image
* processing. If filter has {@literal <}= 1 element, return this
* unchanged. filter should have an odd number of elements. The
* filter can be created with a IntArray constructor filter is moved along
* stepwise
*
* @param filter
* to apply normally smaller than this
* @return filtered array
*/
public IntArray applyFilter(IntArray filter) {
if (nelem == 0 || filter == null || filter.nelem <= 1) {
return this;
}
int nfilter = filter.size();
int midfilter = (nfilter - 1) / 2;
IntArray temp = new IntArray(nelem);
int wt = 0;
int sum = 0;
for (int j = 0; j < midfilter; j++) {
// get weight
wt = 0;
sum = 0;
int l = 0;
for (int k = midfilter - j; k < nfilter; k++) {
wt += Math.abs(filter.array[k]);
sum += filter.array[k] * this.array[l++];
}
temp.array[j] = sum / wt;
}
wt = filter.absSumAllElements();
for (int j = midfilter; j < nelem - midfilter; j++) {
sum = 0;
int l = j - midfilter;
for (int k = 0; k < nfilter; k++) {
sum += filter.array[k] * this.array[l++];
}
temp.array[j] = sum / wt;
}
for (int j = nelem - midfilter; j < nelem; j++) {
// get weight
wt = 0;
sum = 0;
int l = j - midfilter;
for (int k = 0; k < midfilter + nelem - j; k++) {
wt += Math.abs(filter.array[k]);
sum += filter.array[k] * this.array[l++];
}
temp.array[j] = sum / wt;
}
return temp;
}
/**
* trims array to lie within limit.
*
* if flag == BELOW values below limit are set to limit. if flag == ABOVE
* values above limit are set to limit. by repeated use of trim() values can
* be constrained to lie within or outside a window does not modify this.
*
* @param flag
* BELOW or ABOVE
* @param limit
* value to constrain
* @return new array
*/
public IntArray trim(Trim flag, int limit) {
IntArray temp = new IntArray(nelem);
for (int i = 0; i < nelem; i++) {
int v = array[i];
if ((flag == Trim.BELOW && v < limit)
|| (flag == Trim.ABOVE && v > limit))
v = limit;
temp.array[i] = v;
}
return temp;
}
/**
* index of largest element.
*
* @throws ArrayIndexOutOfBoundsException
* array is zero length
* @return index
*/
public int indexOfLargestElement() throws ArrayIndexOutOfBoundsException {
if (nelem == 0) {
throw new ArrayIndexOutOfBoundsException();
}
int index = -1;
int value = Integer.MIN_VALUE;
for (int i = 0; i < nelem; i++) {
if (array[i] > value) {
value = array[i];
index = i;
}
}
return index;
}
/**
* index of smallest element.
*
* @throws ArrayIndexOutOfBoundsException
* array is zero length
* @return index
*/
public int indexOfSmallestElement() throws ArrayIndexOutOfBoundsException {
if (nelem == 0) {
throw new ArrayIndexOutOfBoundsException();
}
int index = -1;
int value = Integer.MAX_VALUE;
for (int i = 0; i < nelem; i++) {
if (array[i] < value) {
value = array[i];
index = i;
}
}
return index;
}
/**
* value of largest element.
*
* @throws ArrayIndexOutOfBoundsException
* array is zero length
* @return value
*/
public int largestElement() throws ArrayIndexOutOfBoundsException {
return array[indexOfLargestElement()];
}
/**
* value of largest element. synonym for largestElement();
*
* @throws ArrayIndexOutOfBoundsException
* array is zero length
* @return value
*/
public int getMax() throws ArrayIndexOutOfBoundsException {
return array[indexOfLargestElement()];
}
/**
* value of smallest element.
*
* @throws ArrayIndexOutOfBoundsException
* array is zero length
* @return index
*/
public int smallestElement() throws ArrayIndexOutOfBoundsException {
return array[indexOfSmallestElement()];
}
/**
* value of smallest element. synonym for smallestElement();
*
* @throws ArrayIndexOutOfBoundsException
* array is zero length
* @return value
*/
public int getMin() throws ArrayIndexOutOfBoundsException {
return array[indexOfSmallestElement()];
}
/**
* range of array.
*
* @throws ArrayIndexOutOfBoundsException
* array is zero length
* @return (minValue, maxValue)
*/
public IntRange getRange() throws ArrayIndexOutOfBoundsException {
IntRange r = null;
if (nelem == 0) {
throw new ArrayIndexOutOfBoundsException();
}
r = new IntRange();
for (int i = 0; i < nelem; i++) {
r.add(array[i]);
}
return r;
}
/**
* as above (deprecated)
*/
/*--
public RealRange range() {return this.getRange();}
--*/
/**
* delete element and close up. modifies this.
*
* @param elem
* to delete
* @throws ArrayIndexOutOfBoundsException
* elem out of range
*/
public void deleteElement(int elem) throws ArrayIndexOutOfBoundsException {
if (elem < 0 || elem >= nelem) {
throw new ArrayIndexOutOfBoundsException();
}
nelem--;
if (bufsize > nelem * 2) {
bufsize /= 2;
}
int[] temp = new int[bufsize];
System.arraycopy(array, 0, temp, 0, elem);
System.arraycopy(array, elem + 1, temp, elem, nelem - elem);
array = temp;
}
/**
* delete elements and close up. modifies this.
*
* @param low
* lowest index inclusive
* @param high
* highest index inclusive
* @throws ArrayIndexOutOfBoundsException
* low or high out of range or low > high
*/
/**
* delete elements and close up. modifies this.
*
* @param low
* lowest index inclusive
* @param high
* highest index inclusive
* @throws ArrayIndexOutOfBoundsException
* low or high out of range or low {@literal >} high
*/
public void deleteElements(int low, int high)
throws ArrayIndexOutOfBoundsException {
if (low < 0 || low > high || high >= nelem) {
throw new ArrayIndexOutOfBoundsException();
}
int ndeleted = high - low + 1;
int[] temp = new int[nelem - ndeleted];
System.arraycopy(array, 0, temp, 0, low);
System.arraycopy(array, high + 1, temp, low, nelem - low - ndeleted);
array = temp;
nelem -= ndeleted;
bufsize = nelem;
int[] array = new int[nelem];
System.arraycopy(temp, 0, array, 0, nelem);
}
/**
* insert element and expand. modifies this.
*
* @param elem
* index of element to insert
* @param f
* value of element
* @throws ArrayIndexOutOfBoundsException
* elem out of range
*/
public void insertElementAt(int elem, int f)
throws ArrayIndexOutOfBoundsException {
if (elem < 0 || elem > nelem) {
throw new ArrayIndexOutOfBoundsException();
}
int[] array1 = new int[nelem + 1];
System.arraycopy(array, 0, array1, 0, elem);
array1[elem] = f;
System.arraycopy(array, elem, array1, elem + 1, nelem - elem);
nelem++;
array = array1;
}
/**
* insert an array and expand. modifies this.
*
* @param elem
* index of element to insert
* @param f
* value of element
* @throws ArrayIndexOutOfBoundsException
* elem out of range
*/
public void insertArray(int elem, IntArray f)
throws ArrayIndexOutOfBoundsException {
int n = f.size();
if (elem < 0 || elem >= nelem || n < 1) {
throw new ArrayIndexOutOfBoundsException();
}
nelem += n;
int[] array1 = new int[nelem];
System.arraycopy(array, 0, array1, 0, elem);
System.arraycopy(f.getArray(), 0, array1, elem, n);
System.arraycopy(array, elem, array1, n + elem, nelem - elem - n);
array = array1;
}
/**
* append element. modifies this.
*
* @param f
* element to append
*/
public void addElement(int f) {
makeSpace(nelem + 1);
array[nelem++] = f;
}
/**
* append elements. modifies this.
*
* @param f
* elements to append
*/
public void addArray(IntArray f) {
makeSpace(nelem + f.nelem);
System.arraycopy(f.array, 0, array, nelem, f.nelem);
nelem += f.nelem;
}
/**
* get reordered Array. reorder by index in IntSet new(i) = this(idx(i))
* does NOT modify array
*
* @param idx
* array of indexes
* @exception EuclidRuntimeException
* an element of idx is outside range of this
* @return array
*/
public IntArray getReorderedArray(IntSet idx) throws EuclidRuntimeException {
IntArray temp = new IntArray(nelem);
for (int i = 0; i < nelem; i++) {
int index = idx.elementAt(i);
if (index > nelem) {
throw new EuclidRuntimeException();
}
temp.array[i] = array[index];
}
return temp;
}
/**
* get elements within a range.
*
* @param r
* within which element values must lie
* @return indexes of conforming elements
*/
public IntSet inRange(IntRange r) {
int n = size();
IntSet temp = new IntSet();
for (int i = 0; i < n; i++) {
if (r.isValid() && r.includes(array[i])) {
temp.addElement(i);
}
}
return temp;
}
/**
* get elements outside a range.
*
* @param r
* outside which element values must lie
* @return indexes of conforming elements
*/
public IntSet outOfRange(IntRange r) {
int n = size();
IntSet temp = new IntSet();
for (int i = 0; i < n; i++) {
if (r.isValid() && !r.includes(array[i])) {
temp.addElement(i);
}
}
return temp;
}
/**
* returns values as strings.
*
* @return string values of elements
*/
public String[] getStringValues() {
String[] temp = new String[nelem];
for (int i = 0; i < nelem; i++) {
temp[i] = Integer.toString(array[i]);
}
return temp;
}
/**
* gets values as string.
*
* @return element values seperated with spaces
*/
public String toString() {
// don't change this routine!!!
StringBuffer s = new StringBuffer();
s.append(S_LBRAK);
for (int i = 0; i < nelem; i++) {
if (i > 0) {
s.append(S_COMMA);
}
s.append(array[i]);
}
s.append(S_RBRAK);
return s.toString();
}
/**
* delete elements. utility routine. delete elements from java routine and
* close up
*
* @param low
* index inclusive
* @param hi
* index inclusive if hi >= float.length hi is reset to
* float.length-1.
*/
static int[] deleteElements(int[] f, int low, int hi) {
if (hi >= f.length)
hi = f.length - 1;
if (low < 0)
low = 0;
int ndel = hi - low + 1;
if (ndel <= 0)
return f;
int[] temp = new int[f.length - ndel];
System.arraycopy(f, 0, temp, 0, low);
System.arraycopy(f, hi + 1, temp, low, f.length - hi - 1);
return temp;
}
/**
* copy java array utility routine
*/
static int[] copy(int[] f) {
int temp[] = new int[f.length];
System.arraycopy(f, 0, temp, 0, f.length);
return temp;
}
/**
* quick sort - modified from p96 - 97 (Hansen - C++ answer book)
*
* Scalar sort refers to sorting IntArray and IntArray (and similar classes)
* where the objects themeselves are sorted.
*
* Index sort refers to sorting indexes (held as IntSet's) to the object and
* getting the sorted object(s) with reorderBy(IntSet idx);
*
*/
void xfswap(int[] x, int a, int b) {
int tmp = x[a];
x[a] = x[b];
x[b] = tmp;
}
// scalar sort routines (internal)
static final int CUTOFF = 16;
private void inssort(int left, int right) {
int k;
for (int i = left + 1; i <= right; i++) {
int v = array[i];
int j;
for (j = i, k = j - 1; j > 0 && array[k] > v; j--, k--) {
array[j] = array[k];
}
array[j] = v;
}
}
private int partition(int left, int right) {
int mid = (left + right) / 2;
if (array[left] > array[mid])
xfswap(array, left, mid);
if (array[left] > array[right])
xfswap(array, left, right);
if (array[mid] > array[right])
xfswap(array, mid, right);
int j = right - 1;
xfswap(array, mid, j);
int i = left;
int v = array[j];
do {
do {
i++;
} while (array[i] < v);
do {
j--;
} while (array[j] > v);
xfswap(array, i, j);
} while (i < j);
xfswap(array, j, i);
xfswap(array, i, right - 1);
return i;
}
private void iqsort(int left, int right) {
while (right - left > CUTOFF) {
int i = partition(left, right);
if (i - left > right - i) {
iqsort(i + 1, right);
right = i - 1;
} else {
iqsort(left, i - 1);
left = i + 1;
}
}
}
/**
* sorts array into ascending order. MODIFIES this
*/
public void sortAscending() {
if (nelem <= 0)
return;
iqsort(0, nelem - 1);
inssort(0, nelem - 1);
}
/**
* sorts array into descending order. MODIFIES this
*/
public void sortDescending() {
sortAscending();
reverse();
}
/**
* puts array into reverse order. MODIFIES this
*/
public void reverse() {
int i = 0, j = nelem - 1;
while (i < j) {
xfswap(array, i, j);
i++;
j--;
}
}
private static final int XXCUTOFF = 16;
/**
* get indexes of ascending sorted array. this array NOT MODIFIED
*
* @return indexes idx so that element(idx(0)) is lowest
*/
public IntSet indexSortAscending() {
if (nelem <= 0) {
return new IntSet();
}
IntSet idx = new IntSet(nelem);
IntArray iarray = new IntArray(idx.getElements());
xxiqsort(iarray, array, 0, nelem - 1);
xxinssort(iarray, array, 0, nelem - 1);
try {
idx = new IntSet(iarray.getArray());
} catch (Exception e) {
throw new EuclidRuntimeException(e.toString());
}
return idx;
}
/**
* get indexes of descending sorted array. this array NOT MODIFIED
*
* @return indexes idx so that element(idx(0)) is highest
*/
public IntSet indexSortDescending() {
IntSet idx;
idx = indexSortAscending();
int[] temp = new IntArray(idx.getElements()).getReverseArray();
try {
idx = new IntSet(temp);
} catch (Exception e) {
throw new EuclidRuntimeException(e.toString());
}
return idx;
}
private void xxinssort(IntArray iarr, int[] pfl, int left, int right) {
int j, k;
for (int i = left + 1; i <= right; i++) {
int v = iarr.elementAt(i);
for (j = i, k = j - 1; j > 0 && pfl[iarr.elementAt(k)] > pfl[v]; j--, k--) {
iarr.setElementAt(j, iarr.elementAt(k));
}
iarr.setElementAt(j, v);
}
}
private int xxpartition(IntArray iarr, int[] pfl, int left, int right) {
int mid = (left + right) / 2;
if (pfl[iarr.elementAt(left)] > pfl[iarr.elementAt(mid)])
xxfswap(iarr, left, mid);
if (pfl[iarr.elementAt(left)] > pfl[iarr.elementAt(right)])
xxfswap(iarr, left, right);
if (pfl[iarr.elementAt(mid)] > pfl[iarr.elementAt(right)])
xxfswap(iarr, mid, right);
int j = right - 1;
xxfswap(iarr, mid, j);
int i = left;
int v = pfl[iarr.elementAt(j)];
do {
do {
i++;
} while (pfl[iarr.elementAt(i)] < v);
do {
j--;
} while (pfl[iarr.elementAt(j)] > v);
xxfswap(iarr, i, j);
} while (i < j);
xxfswap(iarr, j, i);
xxfswap(iarr, i, right - 1);
return i;
}
private void xxiqsort(IntArray iarr, int[] pfl, int left, int right) {
while (right - left > XXCUTOFF) {
int i = xxpartition(iarr, pfl, left, right);
if (i - left > right - i) {
xxiqsort(iarr, pfl, i + 1, right);
right = i - 1;
} else {
xxiqsort(iarr, pfl, left, i - 1);
left = i + 1;
}
}
}
private void xxfswap(IntArray iarr, int a, int b) {
int t = iarr.elementAt(a);
iarr.setElementAt(a, iarr.elementAt(b));
iarr.setElementAt(b, t);
}
/**
* parse string as integerArray.
*
* @param s
* @param delimiterRegex
* @return true if can be parsed.
*/
public static boolean isIntArray(String s, String delimiterRegex) {
boolean couldBeIntArray = true;
String[] ss = s.split(delimiterRegex);
try {
new IntArray(ss);
} catch (NumberFormatException e) {
couldBeIntArray = false;
}
return couldBeIntArray;
}
/** returns true if array is of form: i, i+delta, i+2*delta ...
*
* @param delta
* @return
*/
public boolean isArithmeticProgression(int delta) {
for (int i = 1; i < nelem; i++) {
if (array[i] -array[i-1] != delta) {
return false;
}
}
return true;
}
/** if all values are equal returns value else null
*
* @return null if no values or unequal else value
*/
public Integer getConstant() {
if (nelem == 0) return null;
for (int i = 1; i < nelem; i++) {
if (array[i] != array[0]) {
return null;
}
}
return array[0];
}
public void decrementElementAt(int i) {
if (i >= 0 && i < nelem) {
array[i]--;
}
}
public void incrementElementAt(int i) {
if (i >= 0 && i < nelem) {
array[i]++;
}
}
public Iteratorm
*
* @param m
* the matrix to slice
* @param lowcol
* lowest column index
* @param hicol
* highest column index
* @param lowrow
* lowest row index
* @param hirow
* highest row index
* @exception EuclidRuntimeException
* impossible value of hirow, hicol, lowrow, lowcol
*/
public IntMatrix(IntMatrix m, int lowrow, int hirow, int lowcol, int hicol)
throws EuclidRuntimeException {
this(hirow - lowrow + 1, hicol - lowcol + 1);
if (hirow >= m.getRows() || lowrow < 0) {
throw new EuclidRuntimeException("bad row index: " + lowrow + S_SLASH + hirow
+ " outside 0/" + m.getRows());
}
if (hicol >= m.getCols() || lowcol < 0) {
throw new EuclidRuntimeException("bad col index: " + lowcol + S_SLASH + hicol
+ " outside 0/" + m.getCols());
}
for (int i = 0, mrow = lowrow; i < rows; i++, mrow++) {
for (int j = 0, mcol = lowcol; j < cols; j++, mcol++) {
flmat[i][j] = m.flmat[mrow][mcol];
}
}
}
/**
* copy constructor. copies matrix including values
*
* @param m
* matrix to copy
*/
public IntMatrix(IntMatrix m) {
this(m.rows, m.cols);
for (int i = 0; i < rows; i++) {
System.arraycopy(m.flmat[i], 0, flmat[i], 0, cols);
}
}
/** create from list of rowvalues
*
* @param intListList
* @return
*/
public static IntMatrix createByRows(List> intListList) {
IntMatrix intMatrix = null;
if (intListList != null) {
int rows = intListList.size();
if (rows > 0) {
List
this are different sizes
* @return new matrix
*/
public IntMatrix plus(IntMatrix m2) throws EuclidRuntimeException {
IntMatrix m = new IntMatrix(m2.rows, m2.cols);
checkConformable(m2);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
m.flmat[i][j] = flmat[i][j] + m2.flmat[i][j];
}
}
return m;
}
/**
* matrix subtraction. subtracts conformable matrices giving NEW matrix this
* is unaltered
*
* @param m2
* @exception EuclidRuntimeException
* m and this are different sizes
* @return new matrix
*/
public IntMatrix subtract(IntMatrix m2) throws EuclidRuntimeException {
IntMatrix m = new IntMatrix(m2.rows, m2.cols);
checkConformable(m2);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
m.flmat[i][j] = flmat[i][j] - m2.flmat[i][j];
}
}
return m;
}
/**
* unary minus. negate all elements of matrix; MODIFIES matrix
*/
public void negative() {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
flmat[i][j] = -flmat[i][j];
}
}
}
/**
* matrix multiplication.
*
* multiplies conformable matrices to give NEW matrix. this is unaltered
* result = 'this' * m; (order matters)
*
* @param m
* @exception EuclidRuntimeException
* m and this are different sizes
* @return new matrix
*/
public IntMatrix multiply(IntMatrix m) throws EuclidRuntimeException {
checkConformable2(m);
IntMatrix m1 = new IntMatrix(rows, m.cols);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < m.cols; j++) {
m1.flmat[i][j] = 0;
for (int k = 0; k < cols; k++) {
m1.flmat[i][j] += flmat[i][k] * m.flmat[k][j];
}
}
}
return m1;
}
/**
* matrix multiplication by a scalar. creates this(i,j) = f*this(i,j)
* MODIFIES matrix
*
* @param f
* scalar
*/
public void multiplyBy(int f) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
flmat[i][j] *= f;
}
}
}
/**
* matrix multiplication. multiplies conformable matrices and stores result
* in this matrix. this = 'this' * m;
*
* @param m
* matrix to multiply by
* @exception EuclidRuntimeException
* m and this are different sizes
*/
public void multiplyEquals(IntMatrix m) throws EuclidRuntimeException {
IntMatrix mm = this.multiply(m);
this.rows = mm.rows;
this.cols = mm.cols;
this.flmat = new int[this.rows][];
for (int i = 0; i < rows; i++) {
this.flmat[i] = new int[this.cols];
System.arraycopy(mm.flmat[i], 0, this.flmat[i], 0, this.cols);
}
}
/**
* subtract value from each row. this[i,j] = this[i,j] - d[j] modifies this
*
* @param d
* array of ints to subtract
*/
/*--
public void translateByRow(int[] d) {
checkColumns(d);
for (int i = rows - 1; i >= 0; -- i) {
for (int j = cols - 1; j >= 0; -- j) {
flmat [i] [j] -= d [j];
}
}
}
--*/
/**
* check.
*
* @param d
* @throws EuclidRuntimeException
*/
/* private */void checkColumns(int[] d) throws EuclidRuntimeException {
if (d.length != cols) {
throw new EuclidRuntimeException("array size " + d.length
+ "!= cols length " + cols);
}
}
private void checkRows(int[] d) throws EuclidRuntimeException {
if (d.length != rows) {
throw new EuclidRuntimeException("array size " + d.length
+ "!= rows length " + rows);
}
}
/**
* subtract value from each colum. this[i,j] = this[i,j] - d[i] modifies
* this
*
* @param d
* array of ints to subtract
* @throws EuclidRuntimeException
*/
public void translateByColumn(int[] d) throws EuclidRuntimeException {
checkRows(d);
for (int i = cols - 1; i >= 0; --i) {
for (int j = rows - 1; j >= 0; --j) {
flmat[j][i] -= d[j];
}
}
}
/**
* matrix multiplication of a COLUMN vector. creates new vector
*
* @param f
* vector to multiply
* @exception EuclidRuntimeException
* f.size() differs from cols
* @return transformed array
*/
public IntArray multiply(IntArray f) throws EuclidRuntimeException {
if (f.size() != this.cols) {
throw new EuclidRuntimeException("unequal matrices");
}
int[] temp = new int[rows];
int[] farray = f.getArray();
for (int i = 0; i < rows; i++) {
temp[i] = 0;
for (int j = 0; j < cols; j++) {
temp[i] += this.flmat[i][j] * farray[j];
}
}
IntArray ff = new IntArray(temp);
return ff;
}
/**
* divide each column of a matrix by a vector of scalars (that is mat[i][j] =
* mat[i][j] / vect[i] - MODIFIES matrix
*
* @param f
* array to divide by
* @exception EuclidRuntimeException
* f.size() and rows differ
*/
public void columnwiseDivide(IntArray f) throws EuclidRuntimeException {
if (this.cols != f.size()) {
throw new EuclidRuntimeException("unequal matrices " + this.cols + S_SLASH
+ f.size());
}
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
this.flmat[i][j] /= f.elementAt(j);
}
}
}
/**
* extracts a given element.
*
* @param row
* @param col
* @throws EuclidRuntimeException
* bad value of row or column
* @return the element at row,col
*/
public int elementAt(int row, int col) throws EuclidRuntimeException {
checkRow(row);
checkColumn(col);
return flmat[row][col];
}
/**
* checks a row is in range.
*
* @throws EuclidRuntimeException
* if it isn't
*/
private void checkRow(int row) throws EuclidRuntimeException {
if (row < 0 || row >= rows)
throw new EuclidRuntimeException("Bad value of row: " + row + S_SLASH + rows);
}
/**
* checks a col is in range.
*
* @throws EuclidRuntimeException
* if it isn't
*/
private void checkColumn(int col) throws EuclidRuntimeException {
if (col < 0 || col >= cols)
throw new EuclidRuntimeException("Bad value of col: " + col + S_SLASH + cols);
}
/**
* extracts a given element.
*
* @param rowcol
* represents row,col
* @return the element at row,col
* @throws EuclidRuntimeException
*/
public int elementAt(Int2 rowcol) throws EuclidRuntimeException {
return elementAt(rowcol.elementAt(0), rowcol.elementAt(1));
}
/**
* sets a given element MODIFIES matrix
*
* @param row
* @param col
* @param f
* @throws EuclidRuntimeException
*/
public void setElementAt(int row, int col, int f) throws EuclidRuntimeException {
checkRow(row);
checkColumn(col);
flmat[row][col] = f;
}
/**
* get value of largest element.
*
* @return value of largest element
*/
public int largestElement() {
Int2 temp = indexOfLargestElement();
if (temp == null) {
throw new EuclidRuntimeException("bug; null index for largest element");
}
int d = this.elementAt(temp);
return d;
}
/**
* get index of largest element.
*
* @return (row, col)
*/
public Int2 indexOfLargestElement() {
Int2 int2 = null;
if (cols != 0 && rows != 0) {
int f = Integer.MIN_VALUE;
int im = 0;
int jm = 0;
for (int irow = 0; irow < rows; irow++) {
for (int jcol = 0; jcol < cols; jcol++) {
if (f < flmat[irow][jcol]) {
f = flmat[irow][jcol];
im = irow;
jm = jcol;
}
}
}
int2 = new Int2(im, jm);
}
return int2;
}
/**
* get value of largest element in a column
*
* @param jcol
* @throws EuclidRuntimeException
* @return the value
*/
public int largestElementInColumn(int jcol) throws EuclidRuntimeException {
return this.elementAt(indexOfLargestElementInColumn(jcol), jcol);
}
/**
* get index of largest element in column.
*
* @param jcol
* index
* @return index (-1 if empty matrix)
* @throws EuclidRuntimeException
* bad value of jcol
*/
public int indexOfLargestElementInColumn(int jcol) throws EuclidRuntimeException {
checkColumn(jcol);
int imax = -1;
int max = Integer.MIN_VALUE;
for (int irow = 0; irow < rows; irow++) {
if (max < flmat[irow][jcol]) {
max = flmat[irow][jcol];
imax = irow;
}
}
return imax;
}
/**
* get index of largest element in row.
*
* @param irow
* index
* @return index (-1 if empty matrix)
* @throws EuclidRuntimeException
* bad value of irow
*/
public int indexOfLargestElementInRow(int irow) throws EuclidRuntimeException {
checkRow(irow);
int imax = -1;
int max = Integer.MIN_VALUE;
for (int jcol = 0; jcol < cols; jcol++) {
if (max < flmat[irow][jcol]) {
max = flmat[irow][jcol];
imax = jcol;
}
}
return imax;
}
/**
* get index of smallest element in column.
*
* @param jcol
* index
* @return index (-1 if empty matrix)
* @throws EuclidRuntimeException
* bad value of jcol
*/
public int indexOfSmallestElementInColumn(int jcol) throws EuclidRuntimeException {
checkColumn(jcol);
int imin = -1;
int min = Integer.MAX_VALUE;
for (int irow = 0; irow < rows; irow++) {
if (min > flmat[irow][jcol]) {
min = flmat[irow][jcol];
imin = irow;
}
}
return imin;
}
protected boolean checkNonEmptyMatrix() {
return (cols > 0 && rows > 0);
}
/**
* get value of largest element in a row.
*
* @param irow
* @return value (0 if no columns)
* @throws EuclidRuntimeException
*/
public int largestElementInRow(int irow) throws EuclidRuntimeException {
int idx = indexOfLargestElementInRow(irow);
if (idx < 0) {
throw new EuclidRuntimeException("empty matrix");
}
return this.elementAt(irow, idx);
}
/**
* get index of smallest element in row.
*
* @param irow
* index
* @return index (-1 if empty matrix)
* @throws EuclidRuntimeException
* bad value of irow
*/
public int indexOfSmallestElementInRow(int irow) throws EuclidRuntimeException {
checkRow(irow);
int imin = -1;
int min = Integer.MAX_VALUE;
for (int jcol = 0; jcol < cols; jcol++) {
if (min > flmat[irow][jcol]) {
min = flmat[irow][jcol];
imin = jcol;
}
}
return imin;
}
/**
* get value of smallest element.
*
* @return value
* @throws EuclidRuntimeException
*/
public int smallestElement() throws EuclidRuntimeException {
Int2 temp = indexOfSmallestElement();
return this.elementAt(temp);
}
/**
* get index of smallest element.
*
* @return (row,col) or null for empty matrix
*/
public Int2 indexOfSmallestElement() {
int f = Integer.MAX_VALUE;
int im = -1;
int jm = -1;
for (int irow = 0; irow < rows; irow++) {
for (int jcol = 0; jcol < cols; jcol++) {
if (f > flmat[irow][jcol]) {
f = flmat[irow][jcol];
im = irow;
jm = jcol;
}
}
}
return (im >= 0) ? new Int2(im, jm) : null;
}
/**
* get smallest element in a column.
*
* @param jcol
* @return smallest value
* @exception EuclidRuntimeException
* bad value of jcol
*/
public int smallestElementInColumn(int jcol) throws EuclidRuntimeException {
int idx = indexOfSmallestElementInColumn(jcol);
if (idx < 0) {
throw new EuclidRuntimeException("empty matrix");
}
return this.elementAt(idx, jcol);
}
/**
* get smallest element in a row.
*
* @param irow
* @return smallest value
* @exception EuclidRuntimeException
* bad value of irow
*/
public int smallestElementInRow(int irow) throws EuclidRuntimeException {
int idx = indexOfSmallestElementInRow(irow);
if (idx < 0) {
throw new EuclidRuntimeException("empty matrix");
}
return this.elementAt(irow, idx);
}
/**
* is matrix Orthogonal row-wise.
*
* that is row(i) * row(j) = 0 if i not equals j.
*
* @return true if orthogonal
*/
public boolean isOrthogonal() {
for (int i = 1; i < rows; i++) {
IntArray rowi = extractRowData(i);
int dot = 0;
for (int j = i + 1; j < rows; j++) {
IntArray rowj = extractRowData(j);
dot = rowi.dotProduct(rowj);
if (dot != 0)
return false;
}
}
return true;
}
/**
* get column data from matrix.
*
* @param col
* the column
* @return the column data (or length rows)
* @throws EuclidRuntimeException
*/
public IntArray extractColumnData(int col) throws EuclidRuntimeException {
checkColumn(col);
IntArray fa = new IntArray(rows);
for (int i = 0; i < rows; i++) {
fa.setElementAt(i, this.flmat[i][col]);
}
return fa;
}
/**
* get row data from matrix.
*
* @param row
* the column
* @return the column data (of length cols)
*/
public IntArray extractRowData(int row) {
return new IntArray(flmat[row]);
}
/**
* clear matrix.
*/
public void clearMatrix() {
for (int irow = 0; irow < rows; irow++) {
for (int jcol = 0; jcol < cols; jcol++) {
flmat[irow][jcol] = 0;
}
}
}
/**
* initialise matrix to given int.
*
* @param f
*/
public void setAllElements(int f) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
flmat[i][j] = f;
}
}
}
/**
* transpose matrix - creates new Matrix
*
* @return transpose
*/
public IntMatrix getTranspose() {
int[][] m = new int[cols][rows];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
m[j][i] = this.flmat[i][j];
}
}
return new IntMatrix(m);
}
/**
* is the matrix square
*
* @return is square
*/
public boolean isSquare() {
return (cols == rows && cols > 0);
}
/**
* delete column from matrix and close up. no-op if impermissible value of
* col
*
* @param col
* the column
*/
public void deleteColumn(int col) {
if (col >= 0 && col < cols) {
int[][] temp = new int[rows][cols - 1];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < col; j++) {
temp[i][j] = flmat[i][j];
}
for (int j = col + 1; j < cols; j++) {
temp[i][j - 1] = flmat[i][j];
}
}
cols--;
flmat = temp;
}
}
/**
* delete 2 or more adjacent columns (inclusive) from matrix and close up.
* no action if impermissible value of low and high
*
* @param low
* start column
* @param high
* end column
*/
public void deleteColumns(int low, int high) {
high = (high > cols - 1) ? cols - 1 : high;
low = (low < 0) ? 0 : low;
for (int i = 0; i < rows; i++) {
this.flmat[i] = IntArray.deleteElements(this.flmat[i], low, high);
}
this.cols -= (high - low + 1);
}
/**
* delete row from matrix and close up.
*
* @param row
*/
public void deleteRow(int row) {
deleteRows(row, row);
}
/**
* delete 2 or more adjacent rows (inclusive) from matrix and close up. if
* (high {@literal >} rows-1 high -{@literal >} rows-1; or low {@literal <} 0, low -{@literal >} 0
*
* @param low
* start row
* @param high
* end row
*/
public void deleteRows(int low, int high) {
high = (high >= rows) ? rows - 1 : high;
low = (low < 0) ? 0 : low;
if (low > high)
return;
int newrows = rows + high - low - 1;
int temp[][] = new int[newrows][cols];
int oldrow = 0;
int newrow = 0;
while (oldrow < rows) {
if (oldrow < low || oldrow > high) {
temp[newrow++] = flmat[oldrow];
}
oldrow++;
}
this.rows = newrows;
flmat = temp;
}
/**
* replace data in a single column.
*
* @param column
* @param f
* data must be of length rows
* @throws EuclidRuntimeException
*/
public void replaceColumnData(int column, IntArray f)
throws EuclidRuntimeException {
checkRows(f);
checkColumn(column);
int[] temp = f.getArray();
for (int i = 0; i < rows; i++) {
flmat[i][column] = temp[i];
}
}
private void checkRows(IntArray f) throws EuclidRuntimeException {
if (f == null || f.size() != rows) {
throw new EuclidRuntimeException("incompatible value of array size: "
+ f.size() + S_SLASH + rows);
}
}
private void checkColumns(IntArray f) throws EuclidRuntimeException {
if (f == null || f.size() != cols) {
throw new EuclidRuntimeException("incompatible value of array size: "
+ f.size() + S_SLASH + cols);
}
}
private void checkColumns(IntSet is) throws EuclidRuntimeException {
if (is == null || is.size() != cols) {
throw new EuclidRuntimeException("incompatible value of IntSet size: "
+ is.size() + S_SLASH + cols);
}
}
private void checkColumns(IntMatrix m) throws EuclidRuntimeException {
if (m == null || m.getCols() != cols) {
throw new EuclidRuntimeException("incompatible value of matrix size: "
+ m.getCols() + S_SLASH + cols);
}
}
private void checkRows(IntMatrix m) throws EuclidRuntimeException {
if (m == null || m.getRows() != rows) {
throw new EuclidRuntimeException("incompatible value of matrix size: "
+ m.getRows() + S_SLASH + rows);
}
}
/**
* replace data in a single column.
*
* @param starting_col
* @param f
* data must be of length rows
* @throws EuclidRuntimeException
*/
public void replaceColumnData(int starting_col, int[] f)
throws EuclidRuntimeException {
replaceColumnData(starting_col, new IntArray(rows, f));
}
/**
* replace data in a block of columns.
*
* @param start_column
* (gets overwritten)
* @param m
* must have same row count and fit into gap
* @throws EuclidRuntimeException
*/
public void replaceColumnData(int start_column, IntMatrix m)
throws EuclidRuntimeException {
// must trap copying a matrix into itself!
if (this == m) {
return;
}
cols = this.getCols();
int mcols = m.getCols();
checkRows(m);
if (start_column < 0) {
throw new EuclidRuntimeException("cannot start at negative column: "
+ start_column);
}
int end_column = start_column + mcols;
if (end_column > cols) {
throw new EuclidRuntimeException("too many columns to copy: "
+ start_column + "|" + mcols + S_SLASH + cols);
}
copyColumns(m.flmat, start_column, mcols);
}
private void copyColumns(int[][] mat, int start_column, int nToCopy) {
for (int j = 0; j < nToCopy; j++) {
for (int i = 0; i < rows; i++) {
this.flmat[i][start_column + j] = mat[i][j];
}
}
}
/**
* insert a hole into the matrix and expand. result is blank space in matrix
*
* @param after_col
* @param delta_cols
*/
public void makeSpaceForNewColumns(int after_col, int delta_cols) {
if (after_col >= 0 && after_col <= cols && delta_cols > 0) {
int newcols = delta_cols + cols;
IntMatrix temp = new IntMatrix(rows, newcols);
for (int irow = 0; irow < rows; irow++) {
for (int jcol = 0; jcol < after_col; jcol++) {
temp.flmat[irow][jcol] = this.flmat[irow][jcol];
}
for (int jcol = after_col; jcol < cols; jcol++) {
temp.flmat[irow][jcol + delta_cols] = this.flmat[irow][jcol];
}
}
shallowCopy(temp);
}
}
/**
* add data as column or column block into matrix and expand. column is
* inserted after given column
*
* @param after_col
* -1 to cols-1
* @param f
* @throws EuclidRuntimeException
*/
public void insertColumnData(int after_col, IntArray f)
throws EuclidRuntimeException {
checkRows(f);
if (cols == 0) {
rows = f.size();
flmat = new int[rows][1];
int[] arr = f.getArray();
cols = 1;
for (int i = 0; i < rows; i++) {
flmat[i][0] = arr[i];
}
} else {
if (f.size() == rows) {
makeSpaceForNewColumns(after_col + 1, 1);
replaceColumnData(after_col + 1, f);
}
}
}
/**
* add data as column or column block into matrix and expand.
*
* @param afterCol
* -1 to cols-1
* @param m
* @throws EuclidRuntimeException
*/
public void insertColumnData(int afterCol, IntMatrix m)
throws EuclidRuntimeException {
// must trap copying a matrix into itself!
if (this == m) {
return;
}
checkRows(m);
int mcols = m.getCols();
cols = this.getCols();
if (afterCol < -1 || afterCol >= cols) {
throw new EuclidRuntimeException("afterCol must be >= -1 or < cols: "
+ afterCol);
}
makeSpaceForNewColumns(afterCol + 1, mcols);
replaceColumnData(afterCol + 1, m);
}
/**
* make space for new rows in matrix and expand.
*
* @param after_row
* -1 to rows-1
* @param delta_rows
* size of space
*/
public void insertRows(int after_row, int delta_rows) {
if (after_row >= 0 && after_row <= cols && delta_rows > 0) {
int newrows = delta_rows + rows;
IntMatrix temp = new IntMatrix(newrows, cols);
for (int jcol = 0; jcol < cols; jcol++) {
for (int irow = 0; irow < after_row; irow++) {
temp.flmat[irow][jcol] = this.flmat[irow][jcol];
}
for (int irow = after_row; irow < rows; irow++) {
temp.flmat[irow + delta_rows][jcol] = this.flmat[irow][jcol];
}
}
shallowCopy(temp);
}
}
/**
* overwrite existing row of data.
*
* @param row
* to replace
* @param f
* row to use
* @exception EuclidRuntimeException
* f.size() and cols differ
*/
public void replaceRowData(int row, IntArray f) throws EuclidRuntimeException {
checkColumns(f);
int mcols = f.size();
System.arraycopy(f.getArray(), 0, flmat[row], 0, mcols);
}
/**
* overwrite existing row of data.
*
* @param row
* to replace
* @param f
* row to use
* @exception EuclidRuntimeException
* f.length and cols differ
*/
public void replaceRowData(int row, int[] f) throws EuclidRuntimeException {
IntArray temp = new IntArray(cols, f);
replaceRowData(row, temp);
}
/**
* overwrite existing block of rows; if too big, copying is truncated
*
* @param afterRow
* from -1 to rows-1
* @param m
* data to replace with
* @exception EuclidRuntimeException
* m.rows and this.rows differ
*/
public void replaceRowData(int afterRow, IntMatrix m)
throws EuclidRuntimeException {
// must trap copying a matrix into itself!
if (this == m)
return;
checkColumns(m);
if (afterRow < -1) {
throw new EuclidRuntimeException("afterRow must be >= -1 :" + afterRow);
}
if (!(afterRow <= (rows - m.rows))) {
throw new EuclidRuntimeException("afterRow (" + afterRow
+ ")must be <= rows (" + rows + ") - m.rows (" + m.rows
+ S_RBRAK);
}
copyRowData(m.flmat, afterRow + 1, m.rows);
}
/**
* insert 2 or more adjacent rows of data into matrix and expand
*
* @param afterRow
* from -1 to rows-1
* @param m
* data to insert
* @exception EuclidRuntimeException
* m.cols and this.colsdiffer
*/
public void insertRowData(int afterRow, IntMatrix m) throws EuclidRuntimeException {
// must trap copying a matrix into itself!
if (this == m) {
return;
}
rows = this.getRows();
int mrows = m.getRows();
checkColumns(m);
if (afterRow < -1) {
throw new EuclidRuntimeException("must insert after -1 or higher");
}
if (afterRow >= rows) {
throw new EuclidRuntimeException("must insert after nrows-1 or lower");
}
insertRows(afterRow + 1, mrows);
copyRowData(m.flmat, afterRow + 1, mrows);
}
private void copyRowData(int[][] mat, int afterRow, int nrows) {
for (int i = 0; i < nrows; i++) {
for (int j = 0; j < cols; j++) {
this.flmat[afterRow + i][j] = mat[i][j];
}
}
}
/**
* insert row of data into matrix and expand.
*
* @param after_row
* from -1 to rows-1
* @param f
* data to insert
* @exception EuclidRuntimeException
* f.size() and this.cols differ
*/
public void insertRowData(int after_row, IntArray f) throws EuclidRuntimeException {
checkColumns(f);
int mcols = f.size();
if (after_row >= -1 && after_row <= rows && mcols == cols) {
insertRows(after_row + 1, 1);
replaceRowData(after_row + 1, f);
} else {
throw new EuclidRuntimeException("Cannot add array after row" + after_row
+ S_SLASH + rows + "==" + mcols + S_SLASH + cols);
}
}
/**
* append data to matrix columnwise.
*
* @param f
* data to append
* @exception EuclidRuntimeException
* f.size() and this.rows differ
*/
public void appendColumnData(IntArray f) throws EuclidRuntimeException {
if (cols == 0) {
rows = f.size();
}
insertColumnData(cols - 1, f);
}
/**
* append data to matrix columnwise.
*
* @param m data to append
* @exception EuclidRuntimeException m.rows and this.rows differ
*/
public void appendColumnData(IntMatrix m) throws EuclidRuntimeException {
if (cols == 0) {
rows = m.getRows();
}
insertColumnData(cols - 1, m);
}
/**
* append data to matrix rowwise.
*
* @param f
* data to append
* @exception EuclidRuntimeException
* m.cols and this.cols differ
*/
public void appendRowData(IntArray f) throws EuclidRuntimeException {
if (rows == 0) {
cols = f.size();
}
insertRowData(rows - 1, f);
}
/**
* append data to matrix rowwise.
*
* @param m
* data to append
* @exception EuclidRuntimeException
* m.cols and this.cols differ
*/
public void appendRowData(IntMatrix m) throws EuclidRuntimeException {
if (rows == 0) {
cols = m.getCols();
}
insertRowData(rows - 1, m);
}
/**
* replaces the data in a submatrix. starts at (low_row, low_col) and
* extends by the dimensions for the matrix m
*
* @param low_row
* starting row
* @param low_col
* starting col
* @param m
* data to append
*/
public void replaceSubMatrixData(int low_row, int low_col, IntMatrix m) {
if (this == m)
return;
if (low_row > 0 && low_col > 0) {
int mrows = m.getRows();
int mcols = m.getCols();
if (low_row + mrows - 1 < rows && low_col + mcols - 1 < cols) {
for (int i = 0; i < mrows; i++) {
for (int j = 0; j < mcols; j++) {
flmat[i + low_row - 1][j] = m.flmat[i][j];
}
}
}
}
}
/**
* reorder the columns of a matrix.
*
* @param is
* indexes to reorder by
* @exception EuclidRuntimeException
* is.size() and this.cols differ
* @return new matrix
*/
public IntMatrix reorderColumnsBy(IntSet is) throws EuclidRuntimeException {
checkColumns(is);
IntMatrix temp = new IntMatrix(rows, is.size());
for (int i = 0; i < is.size(); i++) {
int icol = is.elementAt(i);
if (icol >= cols || icol < 0) {
throw new ArrayIndexOutOfBoundsException();
}
IntArray coldat = this.extractColumnData(icol);
temp.replaceColumnData(i, coldat);
}
return temp;
}
/**
* reorder the rows of a matrix Deleting rows is allowed
*
* @param is
* indexes to reprder by
* @exception EuclidRuntimeException
* is.size() and this.rows differ
* @return matrix
*/
public IntMatrix reorderRowsBy(IntSet is) throws EuclidRuntimeException {
if (is.size() != rows) {
throw new EuclidRuntimeException("unequal matrices");
}
IntMatrix temp = new IntMatrix(is.size(), cols);
for (int i = 0; i < is.size(); i++) {
int irow = is.elementAt(i);
if (irow >= rows || irow < 0) {
throw new EuclidRuntimeException("irow: " + irow);
}
IntArray rowdat = this.extractRowData(irow);
temp.replaceRowData(i, rowdat);
}
return temp;
}
/**
* extract a IntMatrix submatrix from a IntMatrix
*
* @param low_row
* starting row
* @param high_row
* end row
* @param low_col
* starting col
* @param high_col
* end col
* @exception EuclidRuntimeException
* low/high_row/col are outside range of this
* @return matrix
*/
public IntMatrix extractSubMatrixData(int low_row, int high_row,
int low_col, int high_col) throws EuclidRuntimeException {
return new IntMatrix(this, low_row, high_row, low_col, high_col);
}
/**
* make an Int2_Array from columns.
*
* @param col1
* @param col2
* @throws EuclidRuntimeException
* bad values of columns
* @return 2*rows data
*/
public Int2Array extractColumns(int col1, int col2) throws EuclidRuntimeException {
IntArray x = this.extractColumnData(col1);
IntArray y = this.extractColumnData(col2);
return new Int2Array(x, y);
}
/**
* make an Int2_Array from rows.
*
* @param row1
* @param row2
* @throws EuclidRuntimeException
* bad values of rows
* @return 2*cols data
*/
public Int2Array extractRows(int row1, int row2) throws EuclidRuntimeException {
IntArray x = this.extractRowData(row1);
IntArray y = this.extractRowData(row2);
return new Int2Array(x, y);
}
/**
* produce a mask of those elements which fall in a range. result is matrix
* with (1) else (0)
*
* @param r
* the range
* @throws EuclidRuntimeException
* bad values of rows
* @return matrix with 1s where data is in range else 0
*/
public IntMatrix elementsInRange(IntRange r) throws EuclidRuntimeException {
IntMatrix m = new IntMatrix(rows, cols);
for (int irow = 0; irow < rows; irow++) {
for (int jcol = 0; jcol < cols; jcol++) {
int elem = 0;
if (r.includes(elementAt(irow, jcol))) {
elem = 1;
}
m.setElementAt(irow, jcol, elem);
}
}
return m;
}
/**
* output matrix - very crude
*
* @return the string
*/
public String toString() {
StringBuffer sb = new StringBuffer();
// rows and cols
if (rows > 0 && cols > 0) {
sb.append(S_LCURLY);
sb.append(rows);
sb.append(S_COMMA);
sb.append(cols);
sb.append(S_RCURLY);
} else {
sb.append(S_LBRAK);
}
for (int i = 0; i < rows; i++) {
sb.append(S_NEWLINE);
sb.append(S_LBRAK);
for (int j = 0; j < cols; j++) {
if (j > 0) {
sb.append(S_COMMA);
}
if (format == null) {
sb.append(flmat[i][j]);
} else {
sb.append(format.format(flmat[i][j]));
}
}
sb.append(S_RBRAK);
}
if (rows == 0 || cols == 0) {
sb.append(S_RBRAK);
}
return sb.toString();
}
/**
* output xml as a CML matrix.
*
* @param w
* the writer
* @exception IOException
*/
public void writeXML(Writer w) throws IOException {
StringBuffer sb = new StringBuffer();
sb.append(" RealArray x = someFunction();