PageRenderTime 54ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/java/src/jmat/impl/MatrixJC.java

http://groovy-matrix.googlecode.com/
Java | 1199 lines | 1077 code | 100 blank | 22 comment | 308 complexity | 400ec8ac7d500a031a4735647b3caa6f MD5 | raw file
  1. /**
  2. *
  3. */
  4. package jmat.impl;
  5. import java.util.ArrayList;
  6. import java.util.HashMap;
  7. import java.util.Iterator;
  8. import java.util.List;
  9. import java.util.TreeSet;
  10. import java.util.Map.Entry;
  11. import jmat.intr.Matrix;
  12. /**
  13. * @author Aram Altschudjian
  14. *
  15. */
  16. public class MatrixJC implements Matrix{
  17. private int dimensions = 0;
  18. private ArrayList<Integer> sizes = null;
  19. private ArrayList<Object> data = null;
  20. private ArrayList<HashMap<String, Integer>> names = null;
  21. private int entries = 0;
  22. private Object defaultValue = 0;
  23. public MatrixJC(){
  24. }
  25. public MatrixJC(Integer... sizes){
  26. setSize(sizes);
  27. init(defaultValue);
  28. }
  29. public MatrixJC(ArrayList<Object> data){
  30. assign(data);
  31. }
  32. public MatrixJC(ArrayList<Object> data, ArrayList<Integer> sizes){
  33. this.data = data;
  34. setSize(sizes);
  35. }
  36. public MatrixJC(ArrayList<Object> data, Integer... sizes){
  37. this.data = data;
  38. setSize(sizes);
  39. }
  40. public void init(Object defaultValue, ArrayList<Integer> sizes){
  41. setSize(sizes);
  42. init(defaultValue);
  43. }
  44. public void init(Object defaultValue, Integer... sizes){
  45. setSize(sizes);
  46. init(defaultValue);
  47. }
  48. public void init(Object defaultValue){
  49. validate();
  50. this.defaultValue = defaultValue;
  51. entries = 0;
  52. data = new ArrayList<Object>(size(0));
  53. fill(0, data);
  54. }
  55. private void fill(int dimension, ArrayList<Object> data) {
  56. if(dimension + 1 == dimensions){
  57. for(int i = data.size(); i < size(dimension); ++i){
  58. data.add(defaultValue);
  59. }
  60. } else if(dimension + 1 < dimensions){
  61. for(int i = data.size(); i < size(dimension); ++i){
  62. ArrayList<Object> next = new ArrayList<Object>(size(dimension + 1));
  63. fill(dimension + 1, next);
  64. data.add(next);
  65. }
  66. } else{
  67. throw new IndexOutOfBoundsException();
  68. }
  69. }
  70. public void setDefault(Object defaultValue){
  71. this.defaultValue = defaultValue;
  72. }
  73. @SuppressWarnings("unchecked")
  74. public void data(Object data){
  75. if(data instanceof ArrayList){
  76. this.data = (ArrayList<Object>)data;
  77. } else if(data instanceof List){
  78. this.data = new ArrayList<Object>((List<Object>)data);
  79. } else{
  80. throw new IllegalArgumentException("Illegal data type.");
  81. }
  82. }
  83. public ArrayList<Object> data(){
  84. return data;
  85. }
  86. @SuppressWarnings("unchecked")
  87. public Object val(){
  88. if(entries() == 1){
  89. Object result = data;
  90. for(int i = 0; i < dimensions; ++i){
  91. result = ((ArrayList<Object>)result).get(0);
  92. }
  93. return result;
  94. } else{
  95. throw new UnsupportedOperationException("Value request for dimensions = " + dimensions + " and sizes " + size() + " not supported.");
  96. }
  97. }
  98. public boolean valid(){
  99. if(dimensions == 0 || sizes == null || sizes.size() != dimensions){
  100. return false;
  101. }
  102. return true;
  103. }
  104. public void reset(){
  105. dimensions = 0;
  106. sizes = null;
  107. data = null;
  108. names = null;
  109. entries = 0;
  110. }
  111. public int entries(){
  112. if(entries == 0){
  113. entries = 1;
  114. for(int i = 0; i < dimensions; ++i){
  115. entries *= sizes.get(i);
  116. }
  117. }
  118. return entries;
  119. }
  120. public ArrayList<Integer> indices(){
  121. ArrayList<Integer> indices = new ArrayList<Integer>(entries());
  122. for(int i = 0; i < entries(); ++i){
  123. indices.add(i);
  124. }
  125. return indices;
  126. }
  127. @SuppressWarnings("unchecked")
  128. public void assign(Object data){
  129. data(data);
  130. ArrayList<Integer> sizes = new ArrayList<Integer>();
  131. if(data != null){
  132. while(data instanceof ArrayList){
  133. int size = ((ArrayList<Integer>)data).size();
  134. if(size > 0){
  135. sizes.add(size);
  136. data = ((ArrayList<Integer>)data).get(0);
  137. if(data == null){
  138. break;
  139. }
  140. } else{
  141. break;
  142. }
  143. }
  144. }
  145. setSize(sizes);
  146. }
  147. public void assign(Matrix matrix){
  148. if(!(matrix instanceof MatrixJC)){
  149. throw new IllegalArgumentException("Assignment of different Matrix types is currently not supported.");
  150. } else{
  151. MatrixJC input = (MatrixJC)matrix;
  152. data(input.data());
  153. setSize(input.size());
  154. }
  155. }
  156. public Matrix get(Object... address){
  157. if(address.length == 1){
  158. return get(address[0]);
  159. } else{
  160. return get((Object)address);
  161. }
  162. }
  163. @SuppressWarnings("unchecked")
  164. public Matrix get(Object address){
  165. if(address instanceof List){
  166. // Multiple 1D-coordinates
  167. List<Object> list = (List<Object>)address;
  168. ArrayList<Object> results = new ArrayList<Object>(list.size());
  169. for(int i = 0; i < list.size(); ++i){
  170. results.add(fetch(new Address(this, list.get(i)), 0, data));
  171. }
  172. return new MatrixJC(results, results.size());
  173. } else{
  174. // One or more multi-dim coordinates
  175. Address jAddress = new Address(this, address);
  176. return new MatrixJC(assemble(jAddress, 0, data), jAddress.size());
  177. }
  178. }
  179. @SuppressWarnings("unchecked")
  180. private Object fetch(Address address, int dimension, ArrayList<Object> data) {
  181. if(dimension + 1 == dimensions){
  182. return data.get(address.get(dimension, 0));
  183. } else if(dimension + 1 < dimensions){
  184. return fetch(address, dimension + 1, (ArrayList<Object>)data.get(address.get(dimension, 0)));
  185. } else{
  186. throw new IllegalArgumentException("Dimension mismatch.");
  187. }
  188. }
  189. @SuppressWarnings("unchecked")
  190. private ArrayList<Object> assemble(Address address, int dimension, ArrayList<Object> data) {
  191. ArrayList<Object> result = new ArrayList<Object>(address.size(dimension));
  192. if(dimension + 1 == dimensions){
  193. for(int i = 0; i < address.size(dimension); ++i){
  194. result.add(data.get(address.get(dimension, i)));
  195. }
  196. } else if(dimension + 1 < dimensions){
  197. for(int i = 0; i < address.size(dimension); ++i){
  198. result.add(assemble(address, dimension + 1, (ArrayList<Object>)data.get(address.get(dimension, i))));
  199. }
  200. } else{
  201. throw new IllegalArgumentException("Dimension mismatch.");
  202. }
  203. return result;
  204. }
  205. @SuppressWarnings("unchecked")
  206. public void put(Object address, Object entry){
  207. Address jAddress = new Address(this, address);
  208. // Ensure capacity
  209. int[] maxima = jAddress.max();
  210. for(int i = 0; i < dimensions; ++i){
  211. int diff = maxima[i] - size(i) + 1;
  212. if(diff > 0){
  213. extend(i, diff);
  214. }
  215. }
  216. // Switching by entry type
  217. if(entry instanceof Matrix){
  218. // Multiple entries
  219. List<Object> list = ((Matrix)entry).list();
  220. // Make sure sizes match
  221. if(list.size() != jAddress.entries()){
  222. throw new IllegalArgumentException("Assignment size mismatch.");
  223. }
  224. // Distribute entries among addresses
  225. distribute(jAddress, 0, list, data);
  226. } else if(entry instanceof List){
  227. // Multiple entries
  228. List<Object> list = (List<Object>)entry;
  229. // Make sure sizes match
  230. if(list.size() != jAddress.entries()){
  231. throw new IllegalArgumentException("Assignment size mismatch.");
  232. }
  233. // Distribute entries among addresses
  234. distribute(jAddress, 0, list, data);
  235. } else{
  236. // Single entry
  237. place(jAddress, 0, entry, data);
  238. }
  239. }
  240. @SuppressWarnings("unchecked")
  241. private void place(Address address, int dimension, Object value, ArrayList<Object> data) {
  242. if(dimension + 1 == dimensions){
  243. data.set(address.get(dimension, 0), value);
  244. } else if(dimension + 1 < dimensions){
  245. place(address, dimension + 1, value, (ArrayList<Object>)data.get(address.get(dimension, 0)));
  246. } else{
  247. throw new IllegalArgumentException("Dimension mismatch.");
  248. }
  249. }
  250. @SuppressWarnings("unchecked")
  251. private void distribute(Address address, int dimension, List<Object> values, ArrayList<Object> data) {
  252. if(dimension + 1 == dimensions){
  253. if(address.size(dimension) != values.size()){
  254. throw new RuntimeException("Program logic error.");
  255. }
  256. for(int i = 0; i < address.size(dimension); ++i){
  257. data.set(address.get(dimension, i), values.get(i));
  258. }
  259. } else if(dimension + 1 < dimensions){
  260. int clusterSize = values.size() / address.size(dimension);
  261. int fromIndex = 0;
  262. int toIndex = clusterSize;
  263. for(int i = 0; i < address.size(dimension); ++i){
  264. distribute(address, dimension + 1, values.subList(fromIndex, toIndex), (ArrayList<Object>)data.get(address.get(dimension, i)));
  265. fromIndex = toIndex;
  266. toIndex += clusterSize;
  267. }
  268. } else{
  269. throw new IllegalArgumentException("Dimension mismatch.");
  270. }
  271. }
  272. public ArrayList<Integer> find(Object entry){
  273. ArrayList<Integer> results = new ArrayList<Integer>();
  274. find(0, new ArrayList<Integer>(), data, entry, results);
  275. return results;
  276. }
  277. @SuppressWarnings("unchecked")
  278. private void find(int dimension, ArrayList<Integer> address, ArrayList<Object> data, Object entry, ArrayList<Integer> results) {
  279. if(dimension + 1 == dimensions){
  280. for(int i = 0; i < size(i); ++i){
  281. if(data.get(i).equals(entry)){
  282. ArrayList<Integer> match = new ArrayList<Integer>(address);
  283. match.add(i);
  284. results.add(convert(match));
  285. }
  286. }
  287. } else if(dimension + 1 < dimensions){
  288. for(int i = 0; i < size(i); ++i){
  289. ArrayList<Integer> next = new ArrayList<Integer>(address);
  290. next.add(i);
  291. find(dimension + 1, next, (ArrayList<Object>)data.get(i), entry, results);
  292. }
  293. } else{
  294. throw new IndexOutOfBoundsException();
  295. }
  296. }
  297. public ArrayList<Integer> nfind(Object entry){
  298. ArrayList<Integer> results = new ArrayList<Integer>();
  299. nfind(0, new ArrayList<Integer>(), data, entry, results);
  300. return results;
  301. }
  302. @SuppressWarnings("unchecked")
  303. private void nfind(int dimension, ArrayList<Integer> address, ArrayList<Object> data, Object entry, ArrayList<Integer> results) {
  304. if(dimension + 1 == dimensions){
  305. for(int i = 0; i < size(i); ++i){
  306. if(!data.get(i).equals(entry)){
  307. ArrayList<Integer> match = new ArrayList<Integer>(address);
  308. match.add(i);
  309. results.add(convert(match));
  310. }
  311. }
  312. } else if(dimension + 1 < dimensions){
  313. for(int i = 0; i < size(i); ++i){
  314. ArrayList<Integer> next = new ArrayList<Integer>(address);
  315. next.add(i);
  316. find(dimension + 1, next, (ArrayList<Object>)data.get(i), entry, results);
  317. }
  318. } else{
  319. throw new IndexOutOfBoundsException();
  320. }
  321. }
  322. public int count(Object entry){
  323. return count(0, data, entry);
  324. }
  325. @SuppressWarnings("unchecked")
  326. private int count(int dimension, ArrayList<Object> data, Object entry) {
  327. int counter = 0;
  328. if(dimension + 1 == dimensions){
  329. for(int i = 0; i < size(dimension); ++i){
  330. if(data.get(i).equals(entry)){
  331. ++counter;
  332. }
  333. }
  334. } else if(dimension + 1 < dimensions){
  335. for(int i = 0; i < size(dimension); ++i){
  336. counter += count(dimension + 1, (ArrayList<Object>)data.get(i), entry);
  337. }
  338. } else{
  339. throw new IndexOutOfBoundsException();
  340. }
  341. return counter;
  342. }
  343. public void setDim(int dimensions){
  344. this.dimensions = dimensions;
  345. if(names == null){
  346. names = new ArrayList<HashMap<String, Integer>>(dimensions);
  347. } else{
  348. names.ensureCapacity(dimensions);
  349. }
  350. }
  351. public int getDim(){
  352. return dimensions;
  353. }
  354. public void setSize(ArrayList<Integer> sizes){
  355. this.sizes = sizes;
  356. setDim(this.sizes.size());
  357. entries = 0;
  358. }
  359. public void setSize(Integer... sizes){
  360. this.sizes = new ArrayList<Integer>(sizes.length);
  361. for(int i = 0; i < sizes.length; ++i){
  362. this.sizes.add(sizes[i]);
  363. }
  364. setDim(this.sizes.size());
  365. entries = 0;
  366. }
  367. public ArrayList<Integer> size(){
  368. return sizes;
  369. }
  370. public int size(int dimension){
  371. return sizes.get(dimension);
  372. }
  373. public ArrayList<Object> list(){
  374. ArrayList<Object> list = new ArrayList<Object>(entries());
  375. for(int i = 0; i < entries(); ++i){
  376. list.add(get(i).val());
  377. }
  378. return list;
  379. }
  380. public ArrayList<Object> unique(){
  381. TreeSet<Object> set = new TreeSet<Object>(list());
  382. Iterator<Object> iterator = set.iterator();
  383. ArrayList<Object> result = new ArrayList<Object>(set.size());
  384. while(iterator.hasNext()){
  385. result.add(iterator.next());
  386. }
  387. return result;
  388. }
  389. public boolean isEmpty(){
  390. return entries() == 0;
  391. }
  392. public boolean equals(MatrixJC candidate){
  393. return data.equals(candidate.data());
  394. }
  395. public boolean equals(Matrix candidate){
  396. if(candidate instanceof MatrixJC){
  397. return equals((MatrixJC)candidate);
  398. }
  399. boolean isEqual = entries() == candidate.entries() && size().equals(candidate.size());
  400. int i = 0;
  401. while(isEqual && i < entries()){
  402. isEqual = get(i).val().equals(candidate.get(i).val());
  403. ++i;
  404. }
  405. return isEqual;
  406. }
  407. public Object max(){
  408. Double result = max(0, data);
  409. if(result.intValue() == result.doubleValue()){
  410. return result.intValue();
  411. } else{
  412. return result;
  413. }
  414. }
  415. @SuppressWarnings("unchecked")
  416. private Double max(int dimension, ArrayList<Object> data){
  417. Double result = Double.NEGATIVE_INFINITY;
  418. if(dimension + 1 == dimensions){
  419. for(int i = 0; i < size(dimension); ++i){
  420. if(data.get(i) instanceof Number){
  421. result = java.lang.Math.max(result, ((Number)data.get(i)).doubleValue());
  422. }
  423. }
  424. } else if(dimension + 1 < dimensions){
  425. for(int i = 0; i < size(dimension); ++i){
  426. result = java.lang.Math.max(result, max(dimension + 1, (ArrayList<Object>)data.get(i)));
  427. }
  428. } else{
  429. throw new IndexOutOfBoundsException("Should not happen.");
  430. }
  431. return result;
  432. }
  433. public int maxIndex(){
  434. // This is not a performance-optimal implementation
  435. ArrayList<Object> elements = list();
  436. Double max = Double.NEGATIVE_INFINITY;
  437. int index = 0;
  438. Object element;
  439. for(int i = 0; i < entries(); ++i){
  440. element = elements.get(i);
  441. if(element instanceof Number && ((Number)element).doubleValue() > max){
  442. max = ((Number)element).doubleValue();
  443. index = i;
  444. }
  445. }
  446. return index;
  447. }
  448. public Object min(){
  449. Double result = min(0, data);
  450. if(result.intValue() == result.doubleValue()){
  451. return result.intValue();
  452. } else{
  453. return result;
  454. }
  455. }
  456. @SuppressWarnings("unchecked")
  457. private Double min(int dimension, ArrayList<Object> data){
  458. Double result = Double.POSITIVE_INFINITY;
  459. if(dimension + 1 == dimensions){
  460. for(int i = 0; i < size(dimension); ++i){
  461. if(data.get(i) instanceof Number){
  462. result = java.lang.Math.min(result, ((Number)data.get(i)).doubleValue());
  463. }
  464. }
  465. } else if(dimension + 1 < dimensions){
  466. for(int i = 0; i < size(dimension); ++i){
  467. result = java.lang.Math.min(result, min(dimension + 1, (ArrayList<Object>)data.get(i)));
  468. }
  469. } else{
  470. throw new IndexOutOfBoundsException("Should not happen.");
  471. }
  472. return result;
  473. }
  474. public int minIndex(){
  475. // This is not a performance-optimal implementation
  476. ArrayList<Object> elements = list();
  477. Double min = Double.POSITIVE_INFINITY;
  478. int index = 0;
  479. Object element;
  480. for(int i = 0; i < entries(); ++i){
  481. element = elements.get(i);
  482. if(element instanceof Number && ((Number)element).doubleValue() < min){
  483. min = ((Number)element).doubleValue();
  484. index = i;
  485. }
  486. }
  487. return index;
  488. }
  489. public Matrix sum(){
  490. if(dimensions == 2){
  491. return new MatrixJC(twoDSum());
  492. } else if(dimensions == 1){
  493. ArrayList<Object> sum = new ArrayList<Object>(1);
  494. sum.add(sumAll());
  495. return new MatrixJC(sum);
  496. } else{
  497. throw new UnsupportedOperationException("Currently can only form sum for 1- and 2-dimensional matrices.");
  498. }
  499. }
  500. @SuppressWarnings("unchecked")
  501. private ArrayList<Object> twoDSum(){
  502. ArrayList<Object> result = new ArrayList<Object>(size(1));
  503. for(int i = 0; i < size(1); ++i){
  504. Double sum = 0.0;
  505. Object element;
  506. for(int j = 0; j < size(0); ++j){
  507. element = ((ArrayList<Object>)data.get(j)).get(i);
  508. if(element instanceof Number){
  509. sum += ((Number)element).doubleValue();
  510. }
  511. }
  512. if(sum.intValue() == sum.doubleValue()){
  513. result.add(sum.intValue());
  514. } else{
  515. result.add(sum);
  516. }
  517. }
  518. return result;
  519. }
  520. public Object sumAll(){
  521. Double result = sumAll(0, data);
  522. if(result.intValue() == result.doubleValue()){
  523. return result.intValue();
  524. } else{
  525. return result;
  526. }
  527. }
  528. @SuppressWarnings("unchecked")
  529. private Double sumAll(int dimension, ArrayList<Object> data){
  530. Double result = 0.0;
  531. if(dimension + 1 == dimensions){
  532. for(int i = 0; i < size(dimension); ++i){
  533. if(data.get(i) instanceof Number){
  534. result += ((Number)data.get(i)).doubleValue();
  535. }
  536. }
  537. } else if(dimension + 1 < dimensions){
  538. for(int i = 0; i < size(dimension); ++i){
  539. result += sumAll(dimension + 1, (ArrayList<Object>)data.get(i));
  540. }
  541. } else{
  542. throw new IndexOutOfBoundsException("Should not happen.");
  543. }
  544. return result;
  545. }
  546. public Matrix plus(Matrix matrix){
  547. if(!(matrix instanceof MatrixJC)){
  548. throw new IllegalArgumentException("Currently can only add matrices of the same implementation type.");
  549. } else if(!size().equals(matrix.size())){
  550. throw new IllegalArgumentException("Size mismatch between " + size() + " and " + matrix.size());
  551. } else{
  552. MatrixJC result = new MatrixJC(plus(0, data(), ((MatrixJC)matrix).data()));
  553. result.names = names;
  554. return result;
  555. }
  556. }
  557. @SuppressWarnings("unchecked")
  558. private ArrayList<Object> plus(int dimension, ArrayList<Object> own, ArrayList<Object> other){
  559. ArrayList<Object> result = new ArrayList<Object>(size(dimension));
  560. if(dimension + 1 == dimensions){
  561. for(int i = 0; i < size(dimension); ++i){
  562. if(own.get(i) instanceof Number && other.get(i) instanceof Number){
  563. Double calc = ((Number)own.get(i)).doubleValue() + ((Number)other.get(i)).doubleValue();
  564. if(calc.intValue() == calc.doubleValue()){
  565. result.add(calc.intValue());
  566. } else{
  567. result.add(calc.doubleValue());
  568. }
  569. } else{
  570. result.add(own.get(i));
  571. }
  572. }
  573. } else if(dimension + 1 < dimensions){
  574. for(int i = 0; i < size(dimension); ++i){
  575. result.add(plus(dimension + 1, (ArrayList<Object>)own.get(i), (ArrayList<Object>)other.get(i)));
  576. }
  577. } else{
  578. throw new IndexOutOfBoundsException("Should not happen.");
  579. }
  580. return result;
  581. }
  582. public Matrix plus(Number number){
  583. MatrixJC result = new MatrixJC(plus(0, data(), number));
  584. result.names = names;
  585. return result;
  586. }
  587. @SuppressWarnings("unchecked")
  588. private ArrayList<Object> plus(int dimension, ArrayList<Object> own, Number number){
  589. ArrayList<Object> result = new ArrayList<Object>(size(dimension));
  590. if(dimension + 1 == dimensions){
  591. for(int i = 0; i < size(dimension); ++i){
  592. if(own.get(i) instanceof Number){
  593. Double calc = ((Number)own.get(i)).doubleValue() + number.doubleValue();
  594. if(calc.intValue() == calc.doubleValue()){
  595. result.add(calc.intValue());
  596. } else{
  597. result.add(calc.doubleValue());
  598. }
  599. } else{
  600. result.add(own.get(i));
  601. }
  602. }
  603. } else if(dimension + 1 < dimensions){
  604. for(int i = 0; i < size(dimension); ++i){
  605. result.add(plus(dimension + 1, (ArrayList<Object>)own.get(i), number));
  606. }
  607. } else{
  608. throw new IndexOutOfBoundsException("Should not happen.");
  609. }
  610. return result;
  611. }
  612. public Matrix minus(Matrix matrix){
  613. if(!(matrix instanceof MatrixJC)){
  614. throw new IllegalArgumentException("Currently can only add matrices of the same implementation type.");
  615. } else if(!size().equals(matrix.size())){
  616. throw new IllegalArgumentException("Size mismatch between " + size() + " and " + matrix.size());
  617. } else{
  618. MatrixJC result = new MatrixJC(minus(0, data(), ((MatrixJC)matrix).data()));
  619. result.names = names;
  620. return result;
  621. }
  622. }
  623. @SuppressWarnings("unchecked")
  624. private ArrayList<Object> minus(int dimension, ArrayList<Object> own, ArrayList<Object> other){
  625. ArrayList<Object> result = new ArrayList<Object>(size(dimension));
  626. if(dimension + 1 == dimensions){
  627. for(int i = 0; i < size(dimension); ++i){
  628. if(own.get(i) instanceof Number && other.get(i) instanceof Number){
  629. Double calc = ((Number)own.get(i)).doubleValue() - ((Number)other.get(i)).doubleValue();
  630. if(calc.intValue() == calc.doubleValue()){
  631. result.add(calc.intValue());
  632. } else{
  633. result.add(calc.doubleValue());
  634. }
  635. } else{
  636. result.add(own.get(i));
  637. }
  638. }
  639. } else if(dimension + 1 < dimensions){
  640. for(int i = 0; i < size(dimension); ++i){
  641. result.add(minus(dimension + 1, (ArrayList<Object>)own.get(i), (ArrayList<Object>)other.get(i)));
  642. }
  643. } else{
  644. throw new IndexOutOfBoundsException("Should not happen.");
  645. }
  646. return result;
  647. }
  648. public Matrix minus(Number number){
  649. MatrixJC result = new MatrixJC(minus(0, data(), number));
  650. result.names = names;
  651. return result;
  652. }
  653. @SuppressWarnings("unchecked")
  654. private ArrayList<Object> minus(int dimension, ArrayList<Object> own, Number number){
  655. ArrayList<Object> result = new ArrayList<Object>(size(dimension));
  656. if(dimension + 1 == dimensions){
  657. for(int i = 0; i < size(dimension); ++i){
  658. if(own.get(i) instanceof Number){
  659. Double calc = ((Number)own.get(i)).doubleValue() - number.doubleValue();
  660. if(calc.intValue() == calc.doubleValue()){
  661. result.add(calc.intValue());
  662. } else{
  663. result.add(calc.doubleValue());
  664. }
  665. } else{
  666. result.add(own.get(i));
  667. }
  668. }
  669. } else if(dimension + 1 < dimensions){
  670. for(int i = 0; i < size(dimension); ++i){
  671. result.add(minus(dimension + 1, (ArrayList<Object>)own.get(i), number));
  672. }
  673. } else{
  674. throw new IndexOutOfBoundsException("Should not happen.");
  675. }
  676. return result;
  677. }
  678. public Matrix mult(Matrix matrix){
  679. if(!(matrix instanceof MatrixJC)){
  680. throw new IllegalArgumentException("Currently can only add matrices of the same implementation type.");
  681. } else if(!size().equals(matrix.size())){
  682. throw new IllegalArgumentException("Size mismatch between " + size() + " and " + matrix.size());
  683. } else{
  684. MatrixJC result = new MatrixJC(mult(0, data(), ((MatrixJC)matrix).data()));
  685. result.names = names;
  686. return result;
  687. }
  688. }
  689. @SuppressWarnings("unchecked")
  690. private ArrayList<Object> mult(int dimension, ArrayList<Object> own, ArrayList<Object> other){
  691. ArrayList<Object> result = new ArrayList<Object>(size(dimension));
  692. if(dimension + 1 == dimensions){
  693. for(int i = 0; i < size(dimension); ++i){
  694. if(own.get(i) instanceof Number && other.get(i) instanceof Number){
  695. Double calc = ((Number)own.get(i)).doubleValue() * ((Number)other.get(i)).doubleValue();
  696. if(calc.intValue() == calc.doubleValue()){
  697. result.add(calc.intValue());
  698. } else{
  699. result.add(calc.doubleValue());
  700. }
  701. } else{
  702. result.add(own.get(i));
  703. }
  704. }
  705. } else if(dimension + 1 < dimensions){
  706. for(int i = 0; i < size(dimension); ++i){
  707. result.add(mult(dimension + 1, (ArrayList<Object>)own.get(i), (ArrayList<Object>)other.get(i)));
  708. }
  709. } else{
  710. throw new IndexOutOfBoundsException("Should not happen.");
  711. }
  712. return result;
  713. }
  714. public Matrix mult(Number number){
  715. MatrixJC result = new MatrixJC(mult(0, data(), number));
  716. result.names = names;
  717. return result;
  718. }
  719. @SuppressWarnings("unchecked")
  720. private ArrayList<Object> mult(int dimension, ArrayList<Object> own, Number number){
  721. ArrayList<Object> result = new ArrayList<Object>(size(dimension));
  722. if(dimension + 1 == dimensions){
  723. for(int i = 0; i < size(dimension); ++i){
  724. if(own.get(i) instanceof Number){
  725. Double calc = ((Number)own.get(i)).doubleValue() * number.doubleValue();
  726. if(calc.intValue() == calc.doubleValue()){
  727. result.add(calc.intValue());
  728. } else{
  729. result.add(calc.doubleValue());
  730. }
  731. } else{
  732. result.add(own.get(i));
  733. }
  734. }
  735. } else if(dimension + 1 < dimensions){
  736. for(int i = 0; i < size(dimension); ++i){
  737. result.add(mult(dimension + 1, (ArrayList<Object>)own.get(i), number));
  738. }
  739. } else{
  740. throw new IndexOutOfBoundsException("Should not happen.");
  741. }
  742. return result;
  743. }
  744. public Matrix div(Matrix matrix){
  745. if(!(matrix instanceof MatrixJC)){
  746. throw new IllegalArgumentException("Currently can only add matrices of the same implementation type.");
  747. } else if(!size().equals(matrix.size())){
  748. throw new IllegalArgumentException("Size mismatch between " + size() + " and " + matrix.size());
  749. } else{
  750. MatrixJC result = new MatrixJC(div(0, data(), ((MatrixJC)matrix).data()));
  751. result.names = names;
  752. return result;
  753. }
  754. }
  755. @SuppressWarnings("unchecked")
  756. private ArrayList<Object> div(int dimension, ArrayList<Object> own, ArrayList<Object> other){
  757. ArrayList<Object> result = new ArrayList<Object>(size(dimension));
  758. if(dimension + 1 == dimensions){
  759. for(int i = 0; i < size(dimension); ++i){
  760. if(own.get(i) instanceof Number && other.get(i) instanceof Number){
  761. Double calc = ((Number)own.get(i)).doubleValue() / ((Number)other.get(i)).doubleValue();
  762. if(calc.intValue() == calc.doubleValue()){
  763. result.add(calc.intValue());
  764. } else{
  765. result.add(calc.doubleValue());
  766. }
  767. } else{
  768. result.add(own.get(i));
  769. }
  770. }
  771. } else if(dimension + 1 < dimensions){
  772. for(int i = 0; i < size(dimension); ++i){
  773. result.add(div(dimension + 1, (ArrayList<Object>)own.get(i), (ArrayList<Object>)other.get(i)));
  774. }
  775. } else{
  776. throw new IndexOutOfBoundsException("Should not happen.");
  777. }
  778. return result;
  779. }
  780. public Matrix div(Number number){
  781. MatrixJC result = new MatrixJC(div(0, data(), number));
  782. result.names = names;
  783. return result;
  784. }
  785. @SuppressWarnings("unchecked")
  786. private ArrayList<Object> div(int dimension, ArrayList<Object> own, Number number){
  787. ArrayList<Object> result = new ArrayList<Object>(size(dimension));
  788. if(dimension + 1 == dimensions){
  789. for(int i = 0; i < size(dimension); ++i){
  790. if(own.get(i) instanceof Number){
  791. Double calc = ((Number)own.get(i)).doubleValue() / number.doubleValue();
  792. if(calc.intValue() == calc.doubleValue()){
  793. result.add(calc.intValue());
  794. } else{
  795. result.add(calc.doubleValue());
  796. }
  797. } else{
  798. result.add(own.get(i));
  799. }
  800. }
  801. } else if(dimension + 1 < dimensions){
  802. for(int i = 0; i < size(dimension); ++i){
  803. result.add(div(dimension + 1, (ArrayList<Object>)own.get(i), number));
  804. }
  805. } else{
  806. throw new IndexOutOfBoundsException("Should not happen.");
  807. }
  808. return result;
  809. }
  810. public Matrix log(){
  811. MatrixJC result = new MatrixJC(log(0, data()));
  812. result.names = names;
  813. return result;
  814. }
  815. @SuppressWarnings("unchecked")
  816. private ArrayList<Object> log(int dimension, ArrayList<Object> own){
  817. ArrayList<Object> result = new ArrayList<Object>(size(dimension));
  818. if(dimension + 1 == dimensions){
  819. for(int i = 0; i < size(dimension); ++i){
  820. if(own.get(i) instanceof Number){
  821. result.add(java.lang.Math.log(((Number)own.get(i)).doubleValue()));
  822. } else{
  823. result.add(own.get(i));
  824. }
  825. }
  826. } else if(dimension + 1 < dimensions){
  827. for(int i = 0; i < size(dimension); ++i){
  828. result.add(log(dimension + 1, (ArrayList<Object>)own.get(i)));
  829. }
  830. } else{
  831. throw new IndexOutOfBoundsException("Should not happen.");
  832. }
  833. return result;
  834. }
  835. public Matrix subFrom(Number minuend){
  836. MatrixJC result = new MatrixJC();
  837. result.init(minuend, size());
  838. result.names = names;
  839. return result.minus(this);
  840. }
  841. public void extend(int dimension){
  842. extend(dimension, 1);
  843. }
  844. public void extend(int dimension, int amount){
  845. sizes.set(dimension, sizes.get(dimension) + amount);
  846. enlarge(dimension, 0, data, amount);
  847. entries = 0;
  848. }
  849. @SuppressWarnings("unchecked")
  850. private void enlarge(int goal, int current, ArrayList<Object> data, int amount) {
  851. if(current == goal){
  852. data.ensureCapacity(data.size() + amount);
  853. fill(current, data);
  854. } else if(current < goal){
  855. for(int i = 0; i < size(current); ++i){
  856. enlarge(goal, current + 1, (ArrayList<Object>)data.get(i), amount);
  857. }
  858. } else{
  859. throw new IndexOutOfBoundsException();
  860. }
  861. }
  862. @SuppressWarnings("unchecked")
  863. public void delete(Object address){
  864. if(isAll(address)){
  865. // Set all entries to 'null', but keep structure and name resolution.
  866. // For a total reset, use reset() instead.
  867. data = null;
  868. init(defaultValue);
  869. } else if(address instanceof ArrayList){
  870. entries = 0;
  871. ArrayList<Object> list = (ArrayList<Object>)address;
  872. if(list.size() != dimensions){
  873. throw new IllegalArgumentException("Dimension mismatch.");
  874. }
  875. for(int i = list.size() - 1; i >= 0; --i){
  876. if(!isAll(list.get(i))){
  877. delete(i, list.get(i));
  878. }
  879. }
  880. } else{
  881. throw new IllegalArgumentException("Address format mismatch.");
  882. }
  883. }
  884. public void delete(Object... address){
  885. entries = 0;
  886. if(address.length != dimensions){
  887. throw new IllegalArgumentException("Dimension mismatch.");
  888. }
  889. for(int i = address.length - 1; i >= 0; --i){
  890. if(!isAll(address[i])){
  891. delete(i, address[i]);
  892. }
  893. }
  894. }
  895. public void delete(int dimension, Object... address){
  896. delete(dimension, (Object)address);
  897. }
  898. @SuppressWarnings("unchecked")
  899. public void delete(int dimension, Object address){
  900. entries = 0;
  901. ArrayList<Integer> indices;
  902. if(isAll(address)){
  903. delete(all);
  904. return;
  905. } else if(address instanceof Integer){
  906. indices = new ArrayList<Integer>(1);
  907. int index = (Integer)address;
  908. indices.add(index < 0 ? size(dimension) + index : index);
  909. } else if(address instanceof String){
  910. indices = new ArrayList<Integer>(1);
  911. indices.add(resolve(dimension, (String)address));
  912. } else if(address instanceof Object[]){
  913. Object[] array = (Object[])address;
  914. indices = new ArrayList<Integer>(array.length);
  915. for(int i = 0; i < array.length; ++i){
  916. if(array[i] instanceof Integer){
  917. indices.add((Integer)array[i]);
  918. } else if(array[i] instanceof String){
  919. indices.add(resolve(dimension, (String)array[i]));
  920. } else{
  921. throw new IllegalArgumentException("Illegal index format.");
  922. }
  923. }
  924. } else if(address instanceof List){
  925. List<Object> list = (List<Object>)address;
  926. indices = new ArrayList<Integer>(list.size());
  927. for(int i = 0; i < list.size(); ++i){
  928. if(list.get(i) instanceof Integer){
  929. int index = (Integer)list.get(i);
  930. indices.add(index < 0 ? size(dimension) + index : index);
  931. } else if(list.get(i) instanceof String){
  932. indices.add(resolve(dimension, (String)list.get(i)));
  933. } else{
  934. throw new IllegalArgumentException("Illegal index format.");
  935. }
  936. }
  937. } else{
  938. throw new IllegalArgumentException("Illegal index format.");
  939. }
  940. purge(dimension, 0, indices, data);
  941. }
  942. @SuppressWarnings("unchecked")
  943. private void purge(int goal, int current, ArrayList<Integer> indices, ArrayList<Object> data) {
  944. if(current == goal){
  945. for(int i = 0; i < indices.size(); ++i){
  946. data.remove(indices.get(i));
  947. fixNames(goal, indices.get(i));
  948. }
  949. sizes.set(current, sizes.get(current) - indices.size());
  950. } else if(current < goal){
  951. for(int i = 0; i < size(current); ++i){
  952. purge(goal, current + 1, indices, (ArrayList<Object>)data.get(i));
  953. }
  954. } else{
  955. throw new IllegalArgumentException("Dimension mismatch.");
  956. }
  957. }
  958. private void fixNames(int dimension, int removed) {
  959. if(names == null || getNames(dimension) == null){
  960. return;
  961. }
  962. Iterator<Entry<String, Integer>> iterator = getNames(dimension).entrySet().iterator();
  963. while(iterator.hasNext()){
  964. Entry<String, Integer> entry = iterator.next();
  965. if(entry.getValue() == removed){
  966. iterator.remove();
  967. } else if(entry.getValue() > removed){
  968. entry.setValue(entry.getValue() - 1);
  969. }
  970. }
  971. }
  972. public void setOrder(int dimension, ArrayList<Integer> order){
  973. setOrder(dimension, order.toArray(new Integer[0]));
  974. }
  975. public void setOrder(int dimension, Integer... order){
  976. int size = size(dimension);
  977. if(order.length != size){
  978. throw new IllegalArgumentException("Please supply order indices for all elements of the dimension.");
  979. }
  980. int diff = 0;
  981. for(int i = 0; i < size; ++i){
  982. if(order[i] - size + 1 > diff){
  983. diff = order[i] - size + 1;
  984. }
  985. }
  986. if(diff > 0){
  987. extend(dimension, diff);
  988. }
  989. data = reorder(dimension, 0, order, data);
  990. }
  991. @SuppressWarnings("unchecked")
  992. private ArrayList<Object> reorder(int goal, int current, Integer[] order, ArrayList<Object> data) {
  993. ArrayList<Object> result = new ArrayList<Object>(size(current));
  994. if(current == goal){
  995. for(int i = 0; i < order.length; ++i){
  996. result.set(order[i], data.get(i));
  997. }
  998. } else if(current < goal){
  999. for(int i = 0; i < size(current); ++i){
  1000. result.add(reorder(goal, current + 1, order, (ArrayList<Object>)data.get(i)));
  1001. }
  1002. } else{
  1003. throw new IndexOutOfBoundsException();
  1004. }
  1005. return result;
  1006. }
  1007. public void addDim(int size, int index){
  1008. entries = 0;
  1009. ArrayList<Object> newData = new ArrayList<Object>(size);
  1010. for(int i = 0; i < size; ++i){
  1011. if(i == index){
  1012. newData.add(data);
  1013. } else{
  1014. newData.add(null);
  1015. }
  1016. }
  1017. ++dimensions;
  1018. ArrayList<Integer> newSizes = new ArrayList<Integer>(dimensions);
  1019. newSizes.add(size);
  1020. newSizes.addAll(sizes);
  1021. data = newData;
  1022. sizes = newSizes;
  1023. }
  1024. public void setName(int dimension, int index, String name){
  1025. if(names == null){
  1026. names = new ArrayList<HashMap<String,Integer>>(dimensions);
  1027. }
  1028. HashMap<String, Integer> map = names.get(dimension);
  1029. if(map == null){
  1030. map = new HashMap<String, Integer>(sizes.get(dimension));
  1031. names.set(dimension, map);
  1032. }
  1033. map.put(name, index);
  1034. }
  1035. public void setNames(int dimension, HashMap<String, Integer> nameToIndexMap){
  1036. if(names == null){
  1037. names = new ArrayList<HashMap<String,Integer>>(dimensions);
  1038. }
  1039. HashMap<String, Integer> map = names.get(dimension);
  1040. if(map == null){
  1041. names.set(dimension, nameToIndexMap);
  1042. } else{
  1043. map.putAll(nameToIndexMap);
  1044. }
  1045. }
  1046. public HashMap<String, Integer> getNames(int dimension){
  1047. return names.get(dimension);
  1048. }
  1049. public int resolve(int dimension, String name){
  1050. return names.get(dimension).get(name);
  1051. }
  1052. public boolean isAll(Object candidate) {
  1053. if(candidate instanceof Integer){
  1054. return (Integer)candidate == Matrix.all;
  1055. }
  1056. return false;
  1057. }
  1058. public Integer[] convert(int address){
  1059. Integer[] coordinates = new Integer[dimensions];
  1060. int div = 1;
  1061. int mod = 1;
  1062. for(int i = 0; i < dimensions; ++i){
  1063. mod *= size(i);
  1064. coordinates[i] = (address % mod) / div;
  1065. div = mod;
  1066. }
  1067. return coordinates;
  1068. }
  1069. public int convert(ArrayList<Object> address){
  1070. return convert(address.toArray());
  1071. }
  1072. public int convert(Object... address){
  1073. Integer[] coordinates;
  1074. if(address instanceof Integer[]){
  1075. coordinates = (Integer[])address;
  1076. } else{
  1077. throw new IllegalArgumentException("Address format mismatch");
  1078. }
  1079. int index = 0;
  1080. int dimensionSize = 1;
  1081. for(int i = 0; i < coordinates.length; ++i){
  1082. index += (coordinates[i] < 0 ? (size(i) + coordinates[i]) * dimensionSize : coordinates[i] * dimensionSize);
  1083. dimensionSize *= size(i);
  1084. }
  1085. return index;
  1086. }
  1087. private void validate(){
  1088. if(!valid()){
  1089. throw new RuntimeException("Inconsistent or uninitialized structure description.");
  1090. }
  1091. }
  1092. public String toString(){
  1093. if(data != null){
  1094. return data.toString();
  1095. } else{
  1096. throw new RuntimeException("Requesting String representation of an uninitialized structure.");
  1097. }
  1098. }
  1099. }