Skip to content

Commit ff834e0

Browse files
committed
Merge pull request grafos-ml#11 from gdfm/bmatching
Maximum b-matching algorithm
2 parents cb8df9e + db9f765 commit ff834e0

8 files changed

Lines changed: 537 additions & 2 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ target
22
.settings
33
.classpath
44
.idea
5+
.project
56
graphlib.iml

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
<artifactId>maven-compiler-plugin</artifactId>
2323
<version>3.0</version>
2424
<configuration>
25-
<source>1.6</source>
26-
<target>1.6</target>
25+
<source>1.7</source>
26+
<target>1.7</target>
2727
</configuration>
2828
</plugin>
2929
<plugin>
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package ml.grafos.okapi.graphs.maxbmatching;
2+
3+
import java.io.DataInput;
4+
import java.io.DataOutput;
5+
import java.io.IOException;
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
9+
import org.apache.hadoop.io.Writable;
10+
11+
public class MBMEdgeValue implements Writable {
12+
private double weight;
13+
private State state;
14+
15+
public MBMEdgeValue() {
16+
this(0, State.DEFAULT);
17+
}
18+
19+
public MBMEdgeValue(double weight) {
20+
this(weight, State.DEFAULT);
21+
}
22+
23+
public MBMEdgeValue(double weight, State state) {
24+
this.setWeight(weight);
25+
this.setState(state);
26+
}
27+
28+
public double getWeight() {
29+
return weight;
30+
}
31+
32+
public void setWeight(double weight) {
33+
this.weight = weight;
34+
}
35+
36+
public State getState() {
37+
return state;
38+
}
39+
40+
public void setState(State state) {
41+
this.state = state;
42+
}
43+
44+
@Override
45+
public String toString() {
46+
return String.valueOf(weight) + "\t" + state.toString();
47+
}
48+
49+
@Override
50+
public int hashCode() {
51+
final int prime = 31;
52+
int result = 1;
53+
result = prime * result + ((state == null) ? 0 : state.hashCode());
54+
long temp;
55+
temp = Double.doubleToLongBits(weight);
56+
result = prime * result + (int) (temp ^ (temp >>> 32));
57+
return result;
58+
}
59+
60+
@Override
61+
public boolean equals(Object obj) {
62+
if (this == obj)
63+
return true;
64+
if (obj == null)
65+
return false;
66+
if (!(obj instanceof MBMEdgeValue))
67+
return false;
68+
MBMEdgeValue other = (MBMEdgeValue) obj;
69+
if (state != other.state)
70+
return false;
71+
if (Double.doubleToLongBits(weight) != Double.doubleToLongBits(other.weight))
72+
return false;
73+
return true;
74+
}
75+
76+
@Override
77+
public void readFields(DataInput in) throws IOException {
78+
weight = in.readDouble();
79+
state = State.fromValue(in.readByte());
80+
}
81+
82+
@Override
83+
public void write(DataOutput out) throws IOException {
84+
out.writeDouble(weight);
85+
out.writeByte(state.value());
86+
}
87+
88+
public static enum State {
89+
DEFAULT ((byte) 0), // starting state
90+
PROPOSED((byte) 1), // proposed for inclusion in the matching
91+
REMOVED ((byte) 2), // cannot be included in the matching
92+
INCLUDED((byte) 3); // included in the matching
93+
94+
private final byte value;
95+
private static final Map<Byte, State> lookup = new HashMap<Byte, State>();
96+
static {
97+
for (State s : values())
98+
lookup.put(s.value, s);
99+
}
100+
101+
State(byte value) {
102+
this.value = value;
103+
}
104+
105+
public static State fromValue(byte value) {
106+
State result = lookup.get(value);
107+
if (result == null)
108+
throw new IllegalArgumentException("Cannot build edge State from illegal value: " + value);
109+
return result;
110+
}
111+
112+
public byte value() {
113+
return value;
114+
}
115+
}
116+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package ml.grafos.okapi.graphs.maxbmatching;
2+
3+
import java.io.DataInput;
4+
import java.io.DataOutput;
5+
import java.io.IOException;
6+
7+
import ml.grafos.okapi.graphs.maxbmatching.MBMEdgeValue.State;
8+
9+
import org.apache.hadoop.io.LongWritable;
10+
import org.apache.hadoop.io.Writable;
11+
12+
public class MBMMessage implements Writable {
13+
private LongWritable vertexID;
14+
private State state;
15+
16+
public MBMMessage() {
17+
}
18+
19+
public MBMMessage(LongWritable id, State proposed) {
20+
this.vertexID = id;
21+
this.state = proposed;
22+
}
23+
24+
public LongWritable getId() {
25+
return vertexID;
26+
}
27+
28+
public void setId(LongWritable id) {
29+
this.vertexID = id;
30+
}
31+
32+
public State getState() {
33+
return state;
34+
}
35+
36+
public void setState(State state) {
37+
this.state = state;
38+
}
39+
40+
@Override
41+
public String toString() {
42+
return "(" + vertexID + ", " + state + ")";
43+
}
44+
45+
@Override
46+
public int hashCode() {
47+
final int prime = 31;
48+
int result = 1;
49+
result = prime * result + ((state == null) ? 0 : state.hashCode());
50+
result = prime * result + ((vertexID == null) ? 0 : vertexID.hashCode());
51+
return result;
52+
}
53+
54+
@Override
55+
public boolean equals(Object obj) {
56+
if (this == obj)
57+
return true;
58+
if (obj == null)
59+
return false;
60+
if (!(obj instanceof MBMMessage))
61+
return false;
62+
MBMMessage other = (MBMMessage) obj;
63+
if (state != other.state)
64+
return false;
65+
if (vertexID == null) {
66+
if (other.vertexID != null)
67+
return false;
68+
} else if (!vertexID.equals(other.vertexID))
69+
return false;
70+
return true;
71+
}
72+
73+
@Override
74+
public void readFields(DataInput in) throws IOException {
75+
vertexID = new LongWritable(in.readLong());
76+
state = State.fromValue(in.readByte());
77+
}
78+
79+
@Override
80+
public void write(DataOutput out) throws IOException {
81+
out.writeLong(vertexID.get());
82+
out.writeByte(state.value());
83+
}
84+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package ml.grafos.okapi.graphs.maxbmatching;
2+
3+
import org.apache.giraph.edge.Edge;
4+
import org.apache.giraph.edge.EdgeFactory;
5+
import org.apache.giraph.io.formats.AdjacencyListTextVertexInputFormat;
6+
import org.apache.hadoop.io.IntWritable;
7+
import org.apache.hadoop.io.LongWritable;
8+
import org.apache.hadoop.mapreduce.InputSplit;
9+
import org.apache.hadoop.mapreduce.TaskAttemptContext;
10+
11+
/**
12+
* The input format for the maximum b-matching algorithm. The input is an undirected graph in adjacency list format, one vertex per line. The algorithm assumes
13+
* that each edge is present twice in the input, once for each end-point. The line is composed by a vertex, and a list of edges. The vertex is composed by a long
14+
* id, and an integer capacity. Each edge is composed by a long id (the destination vertex id), and a double weight. The elements of the list are tab or space
15+
* separated.
16+
*
17+
* E.g., "1 5 2 0.5 3 0.1" creates a vertex with id=1, capacity=5, and two edges to vertices 2 and 3, with weights 0.5 and 0.1, respectively.
18+
*/
19+
public class MBMTextInputFormat extends AdjacencyListTextVertexInputFormat<LongWritable, IntWritable, MBMEdgeValue> {
20+
21+
@Override
22+
public AdjacencyListTextVertexReader createVertexReader(InputSplit split, TaskAttemptContext context) {
23+
return new MBMVertexReader();
24+
}
25+
26+
public class MBMVertexReader extends AdjacencyListTextVertexReader {
27+
28+
@Override
29+
public Edge<LongWritable, MBMEdgeValue> decodeEdge(String e, String w) {
30+
return EdgeFactory.create(new LongWritable(Long.parseLong(e)), new MBMEdgeValue(Double.parseDouble(w)));
31+
}
32+
33+
@Override
34+
public LongWritable decodeId(String s) {
35+
return new LongWritable(Long.parseLong(s));
36+
}
37+
38+
@Override
39+
public IntWritable decodeValue(String s) {
40+
return new IntWritable(Integer.parseInt(s));
41+
}
42+
}
43+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package ml.grafos.okapi.graphs.maxbmatching;
2+
3+
import java.io.IOException;
4+
5+
import org.apache.giraph.edge.Edge;
6+
import org.apache.giraph.graph.Vertex;
7+
import org.apache.giraph.io.formats.AdjacencyListTextVertexOutputFormat;
8+
import org.apache.hadoop.io.IntWritable;
9+
import org.apache.hadoop.io.LongWritable;
10+
import org.apache.hadoop.io.Text;
11+
import org.apache.hadoop.mapreduce.TaskAttemptContext;
12+
13+
public class MBMTextOutputFormat extends AdjacencyListTextVertexOutputFormat<LongWritable, IntWritable, MBMEdgeValue> {
14+
15+
@Override
16+
public AdjacencyListTextVertexOutputFormat<LongWritable, IntWritable, MBMEdgeValue>.AdjacencyListTextVertexWriter createVertexWriter(
17+
TaskAttemptContext context) {
18+
return new MBMVertexWriter();
19+
}
20+
21+
public class MBMVertexWriter extends AdjacencyListTextVertexWriter {
22+
protected String delimiter;
23+
24+
@Override
25+
public void initialize(TaskAttemptContext context) throws IOException, InterruptedException {
26+
super.initialize(context);
27+
delimiter = getConf().get(LINE_TOKENIZE_VALUE, LINE_TOKENIZE_VALUE_DEFAULT);
28+
}
29+
30+
@Override
31+
public Text convertVertexToLine(Vertex<LongWritable, IntWritable, MBMEdgeValue> vertex) throws IOException {
32+
StringBuffer sb = new StringBuffer(vertex.getId().toString());
33+
sb.append(delimiter);
34+
sb.append(vertex.getValue());
35+
36+
for (Edge<LongWritable, MBMEdgeValue> edge : vertex.getEdges()) {
37+
sb.append(delimiter).append(edge.getTargetVertexId());
38+
sb.append(delimiter).append(edge.getValue().getWeight());
39+
// skip the state, which is always INCLUDED
40+
}
41+
return new Text(sb.toString());
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)