Passed
Push — master ( e0b928...937cde )
by Julian
03:04 queued 12s
created

add(int,int)   B

Complexity

Conditions 5

Size

Total Lines 29
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 19
c 0
b 0
f 0
dl 0
loc 29
rs 8.9833
1
/*
2
 *
3
 * Copyright (C) 2009-2017 Julian Mendez
4
 *
5
 *
6
 * This file is part of jcel.
7
 *
8
 *
9
 * The contents of this file are subject to the GNU Lesser General Public License
10
 * version 3
11
 *
12
 *
13
 * This program is free software: you can redistribute it and/or modify
14
 * it under the terms of the GNU Lesser General Public License as published by
15
 * the Free Software Foundation, either version 3 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU Lesser General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Lesser General Public License
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
25
 *
26
 *
27
 * Alternatively, the contents of this file may be used under the terms
28
 * of the Apache License, Version 2.0, in which case the
29
 * provisions of the Apache License, Version 2.0 are applicable instead of those
30
 * above.
31
 *
32
 *
33
 * Licensed under the Apache License, Version 2.0 (the "License");
34
 * you may not use this file except in compliance with the License.
35
 * You may obtain a copy of the License at
36
 *
37
 *     http://www.apache.org/licenses/LICENSE-2.0
38
 *
39
 * Unless required by applicable law or agreed to in writing, software
40
 * distributed under the License is distributed on an "AS IS" BASIS,
41
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
42
 * See the License for the specific language governing permissions and
43
 * limitations under the License.
44
 *
45
 */
46
47
package de.tudresden.inf.lat.jcel.core.graph;
48
49
import java.util.Collection;
50
import java.util.Collections;
51
import java.util.Optional;
52
import java.util.Set;
53
import java.util.concurrent.ConcurrentHashMap;
54
55
import de.tudresden.inf.lat.util.map.OptMap;
56
import de.tudresden.inf.lat.util.map.OptMapImpl;
57
58
/**
59
 * This class implements a binary relation. Its elements are integer numbers.
60
 *
61
 * @author Julian Mendez
62
 */
63
public class IntegerBinaryRelationImpl implements IntegerBinaryRelation {
64
65
	private final OptMap<Integer, Collection<Integer>> byFirstComp = new OptMapImpl<>(new ConcurrentHashMap<>());
66
	private final OptMap<Integer, Collection<Integer>> bySecondComp = new OptMapImpl<>(new ConcurrentHashMap<>());
67
68
	/**
69
	 * Constructs an empty binary relation.
70
	 */
71
	public IntegerBinaryRelationImpl() {
72
	}
73
74
	/**
75
	 * Adds an element to this binary relation. Although there is not any pair
76
	 * associated to the particular element, the element is belongs to the set
77
	 * of elements.
78
	 *
79
	 * @param elem
80
	 *            element
81
	 * @return <code>true</code> if and only if the element was added
82
	 */
83
	public boolean add(int elem) {
84
		boolean ret = false;
85
		ret |= addTo(elem, this.byFirstComp);
86
		ret |= addTo(elem, this.bySecondComp);
87
		return ret;
88
	}
89
90
	/**
91
	 * Adds a pair to this binary relation.
92
	 *
93
	 * @param first
94
	 *            first element
95
	 * @param second
96
	 *            second element
97
	 * @return <code>true</code> if and only if the pair was added
98
	 */
99
	public boolean add(int first, int second) {
100
		boolean ret = false;
101
102
		ret |= add(first);
103
		ret |= add(second);
104
105
		Optional<Collection<Integer>> optByFirst = this.byFirstComp.get(first);
106
		if (!optByFirst.isPresent()) {
107
			throw new IllegalStateException("Element is not present in the relation: '" + first + "'.");
108
		}
109
110
		Optional<Collection<Integer>> optBySecond = this.bySecondComp.get(second);
111
		if (!optBySecond.isPresent()) {
112
			throw new IllegalStateException("Element is not present in the relation: '" + second + "'.");
113
		}
114
115
		boolean found = false;
116
		if (optByFirst.get().size() < optBySecond.get().size()) {
117
			found = optByFirst.get().contains(second);
118
		} else {
119
			found = optBySecond.get().contains(first);
120
		}
121
122
		if (!found) {
123
			ret |= optByFirst.get().add(second);
124
			ret |= optBySecond.get().add(first);
125
		}
126
127
		return ret;
128
	}
129
130
	private boolean addTo(int elem, OptMap<Integer, Collection<Integer>> map) {
131
		boolean ret = false;
132
		if (!map.get(elem).isPresent()) {
133
			map.put(elem, new ArraySet());
134
			ret = true;
135
		}
136
		return ret;
137
	}
138
139
	@Override
140
	public boolean contains(int first, int second) {
141
		boolean ret = false;
142
		Optional<Collection<Integer>> byFirst = this.byFirstComp.get(first);
143
		ret = (byFirst.isPresent()) && byFirst.get().contains(second);
144
		return ret;
145
	}
146
147
	@Override
148
	public boolean equals(Object o) {
149
		boolean ret = (this == o);
150
		if (!ret && (o instanceof IntegerBinaryRelation)) {
151
			IntegerBinaryRelation other = (IntegerBinaryRelation) o;
152
			ret = getElements().equals(other.getElements());
153
154
			ret = ret && getElements().stream().allMatch(elem -> getByFirst(elem).equals(other.getByFirst(elem)));
155
		}
156
		return ret;
157
	}
158
159
	@Override
160
	public Collection<Integer> getByFirst(int first) {
161
		Collection<Integer> ret = Collections.emptySet();
162
		Optional<Collection<Integer>> optSet = this.byFirstComp.get(first);
163
		if (optSet.isPresent()) {
164
			ret = Collections.unmodifiableCollection(optSet.get());
165
		}
166
		return ret;
167
	}
168
169
	@Override
170
	public Collection<Integer> getBySecond(int second) {
171
		Collection<Integer> ret = Collections.emptySet();
172
		Optional<Collection<Integer>> optSet = this.bySecondComp.get(second);
173
		if (optSet.isPresent()) {
174
			ret = Collections.unmodifiableCollection(optSet.get());
175
		}
176
		return ret;
177
	}
178
179
	/**
180
	 * Returns the number of elements in the internal maps that are referred by
181
	 * the keys, without counting the keys themselves. This method recalculates
182
	 * the value every time it is called.
183
	 *
184
	 * @return the number of elements in the internal maps that are referred by
185
	 *         the keys, without counting the keys themselves
186
	 */
187
	public long getDeepSize() {
188
		long ret = 0;
189
190
		ret += this.byFirstComp.keySet().stream() //
191
				.map(key -> this.byFirstComp.get(key).get().size()) //
192
				.reduce(0, (accum, elem) -> (accum + elem));
193
194
		ret += this.bySecondComp.keySet().stream() //
195
				.map(key -> this.bySecondComp.get(key).get().size()) //
196
				.reduce(0, (accum, elem) -> (accum + elem));
197
198
		return ret;
199
	}
200
201
	@Override
202
	public Set<Integer> getElements() {
203
		return this.byFirstComp.keySet();
204
	}
205
206
	@Override
207
	public int hashCode() {
208
		return this.byFirstComp.hashCode();
209
	}
210
211
	@Override
212
	public String toString() {
213
		StringBuffer sbuf = new StringBuffer();
214
		Set<Integer> elements = getElements();
215
		sbuf.append("[");
216
		elements.forEach(firstComponent -> {
217
			Collection<Integer> connectedElem = getByFirst(firstComponent);
218
			connectedElem.forEach(secondComponent -> {
219
				sbuf.append(" (");
220
				sbuf.append(firstComponent);
221
				sbuf.append(",");
222
				sbuf.append(secondComponent);
223
				sbuf.append(")");
224
			});
225
		});
226
		sbuf.append(" ]");
227
		return sbuf.toString();
228
	}
229
230
}
231