Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f7b5a41
Add CompressionType enum
Jun 13, 2026
4f4a829
Add CompressionException and DecompressionException
Jun 13, 2026
9fe64ee
Add CompressedMatrix container class
Jun 13, 2026
27fc853
Add MatrixCompressor interface
Jun 13, 2026
858ed57
Add TopKData holder class
Jun 13, 2026
305ff09
Add TopKCompressor implementation
Jun 13, 2026
1f0c71f
Fix MatrixBlock API: setValue -> set in TopKCompressor
Jun 13, 2026
d00080f
Add QuantizedData holder class
Jun 29, 2026
dbb3438
Add ProbabilisticQuantizationCompressor implementation
Jun 29, 2026
e71c7cb
Add CompressionConfig builder
Jun 29, 2026
f910dd0
Add CompressionFactory with PassthroughCompressor
Jun 29, 2026
e334890
Add TopKCompressorTest - 9 tests passing
Jun 29, 2026
f176687
Add ProbabilisticQuantizationCompressorTest
Jun 29, 2026
d60f7fe
Add GitHub Actions CI/CD workflow for compression tests
Jun 29, 2026
d24a1a7
Integrate compression into FederationMap broadcast
Jun 29, 2026
6d4c87c
Fix deprecated upload-artifact v3 -> v4
Jun 29, 2026
7a083bf
Address code review feedback from David (ywcb00)
Jul 2, 2026
9edc0e3
Fix test files: add content, remove AutomatedTestBase, fix tab indent…
Jul 2, 2026
e2286a6
Remove old compress/ package files (moved to federated/compression/)
Jul 3, 2026
01e4b62
Address review: make compression configurable, transfer compressed da…
Jul 10, 2026
c347a5f
Add federated matrix compression integration test
Jul 10, 2026
4f6dcf5
Fix checkstyle: remove unused CompressionConfig import
Jul 10, 2026
f3019c8
Fix Eclipse formatter issues in compression files
Jul 10, 2026
93236a0
Fix CompressedMatrix checksum in FederatedRequest for network transfer
Jul 10, 2026
5fc676d
Fix DML script: use read() for federated JSON descriptor
Jul 14, 2026
20698d1
Apply Eclipse formatter to PR-edited lines via dev/format-changed.sh
Jul 16, 2026
c2f6dea
Use lossless compression settings in federated integration test
Jul 22, 2026
e01b4cb
Make federated integration test verify compression is actually applied
Jul 23, 2026
1d1b66c
Fix matrix dimension mismatch in federated compression test
Jul 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/main/java/org/apache/sysds/api/DMLScript.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import org.apache.sysds.runtime.controlprogram.context.SparkExecutionContext;
import org.apache.sysds.runtime.controlprogram.federated.FederatedData;
import org.apache.sysds.runtime.controlprogram.federated.FederatedWorker;
import org.apache.sysds.runtime.controlprogram.federated.compression.CompressionType;
import org.apache.sysds.runtime.controlprogram.federated.monitoring.FederatedMonitoringServer;
import org.apache.sysds.runtime.controlprogram.federated.monitoring.models.CoordinatorModel;
import org.apache.sysds.runtime.controlprogram.parfor.util.IDHandler;
Expand Down Expand Up @@ -131,6 +132,11 @@ public class DMLScript
public static double GPU_MEMORY_UTILIZATION_FACTOR = 0.9;
// Set GPU memory allocator to use
public static String GPU_MEMORY_ALLOCATOR = "cuda";
// Enable/disable federated compression
public static boolean FEDERATED_COMPRESSION = false;
public static CompressionType FEDERATED_COMPRESSION_TYPE = CompressionType.TOPK;
public static double FEDERATED_COMPRESSION_SPARSITY = 0.01;
public static int FEDERATED_COMPRESSION_BITS = 4;
// Enable/disable lineage tracing
public static boolean LINEAGE = DMLOptions.defaultOptions.lineage;
// Enable/disable deduplicate lineage items
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.apache.sysds.runtime.controlprogram.caching.CacheBlock;
import org.apache.sysds.runtime.controlprogram.caching.CacheDataOutput;
import org.apache.sysds.runtime.controlprogram.caching.LazyWriteBuffer;
import org.apache.sysds.runtime.controlprogram.federated.compression.CompressedMatrix;
import org.apache.sysds.runtime.controlprogram.parfor.util.IDHandler;
import org.apache.sysds.runtime.instructions.cp.ScalarObject;
import org.apache.sysds.runtime.lineage.Lineage;
Expand Down Expand Up @@ -149,8 +150,8 @@ public long getChecksum(int i) {
}

private void calcChecksum() throws IOException {
for (Object ob : _data) {
if (!(ob instanceof CacheBlock) && !(ob instanceof ScalarObject))
for(Object ob : _data) {
if(!(ob instanceof CacheBlock) && !(ob instanceof ScalarObject) && !(ob instanceof CompressedMatrix))
continue;

Checksum checksum = new Adler32();
Expand All @@ -174,6 +175,21 @@ private void calcChecksum() throws IOException {
throw new IOException("Failed to serialize cache block.", ex);
}
}

if(ob instanceof CompressedMatrix) {
try {
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(baos);
oos.writeObject(ob);
oos.flush();
byte[] bytes = baos.toByteArray();
checksum.update(bytes, 0, bytes.length);
_checksums.add(checksum.getValue());
}
catch(Exception ex) {
throw new IOException("Failed to serialize CompressedMatrix.", ex);
}
}
}
}

Expand All @@ -187,6 +203,8 @@ public long estimateSerializationBufferSize() {
for(Object obj : _data) {
if(obj instanceof CacheBlock)
minBufferSize += ((CacheBlock<?>)obj).getExactSerializedSize();
else if(obj instanceof CompressedMatrix)
minBufferSize += 1024 * 1024; // conservative 1MB estimate for compressed matrix
}
}
if(_lineageTrace != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
import org.apache.sysds.runtime.controlprogram.context.SparkExecutionContext;
import org.apache.sysds.runtime.controlprogram.federated.FederatedRequest.RequestType;
import org.apache.sysds.runtime.controlprogram.federated.FederatedResponse.ResponseType;
import org.apache.sysds.runtime.controlprogram.federated.compression.CompressedMatrix;
import org.apache.sysds.runtime.controlprogram.federated.compression.CompressionFactory;
import org.apache.sysds.runtime.controlprogram.federated.monitoring.models.DataObjectModel;
import org.apache.sysds.runtime.controlprogram.federated.monitoring.models.EventModel;
import org.apache.sysds.runtime.controlprogram.federated.monitoring.models.EventStageModel;
Expand Down Expand Up @@ -488,7 +490,21 @@ private FederatedResponse putVariable(FederatedRequest request, ExecutionContext
// wrap transferred cache block into cacheable data
Data data;
long size = 0;
if(v instanceof CacheBlock) {
if(v instanceof CompressedMatrix) {
try {
CompressedMatrix cm = (CompressedMatrix) v;
org.apache.sysds.runtime.controlprogram.federated.compression.MatrixCompressor compressor = CompressionFactory
.createForDecompression(cm.getType());
org.apache.sysds.runtime.matrix.data.MatrixBlock decompressed = compressor.decompress(cm);
var block = ExecutionContext.createCacheableData(decompressed);
size = block.getDataSize();
data = block;
}
catch(Exception e) {
throw new FederatedWorkerHandlerException("Failed to decompress matrix: " + e.getMessage());
}
}
else if(v instanceof CacheBlock) {
var block = ExecutionContext.createCacheableData((CacheBlock<?>) v);
size = block.getDataSize();
data = block;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,18 @@
import org.apache.sysds.hops.fedplanner.FTypes.AlignType;
import org.apache.sysds.hops.fedplanner.FTypes.FType;
import org.apache.sysds.lops.RightIndex;
import org.apache.sysds.api.DMLScript;
import org.apache.sysds.runtime.DMLRuntimeException;
import org.apache.sysds.runtime.controlprogram.caching.CacheBlock;
import org.apache.sysds.runtime.controlprogram.caching.CacheableData;
import org.apache.sysds.runtime.controlprogram.federated.FederatedRequest.RequestType;
import org.apache.sysds.runtime.instructions.cp.CPOperand;
import org.apache.sysds.runtime.instructions.cp.ScalarObject;
import org.apache.sysds.runtime.controlprogram.federated.compression.CompressionConfig;
import org.apache.sysds.runtime.controlprogram.federated.compression.CompressionFactory;
import org.apache.sysds.runtime.controlprogram.federated.compression.CompressedMatrix;
import org.apache.sysds.runtime.controlprogram.federated.compression.MatrixCompressor;
import org.apache.sysds.runtime.matrix.data.MatrixBlock;
import org.apache.sysds.runtime.instructions.cp.VariableCPInstruction;
import org.apache.sysds.runtime.lineage.LineageItem;
import org.apache.sysds.runtime.util.IndexRange;
Expand Down Expand Up @@ -138,6 +144,25 @@ private FederatedRequest broadcast(CacheableData<?> data, LineageItem lineageIte
// is fine, because with broadcast all data on all workers)
data.setFedMapping(copyWithNewIDAndRange(
cb.getNumRows(), cb.getNumColumns(), id, FType.BROADCAST));

// === COMPRESSION INTEGRATION ===
// Compress matrix before network transfer; worker decompresses on receipt
if(DMLScript.FEDERATED_COMPRESSION && cb instanceof MatrixBlock) {
try {
CompressionConfig config = CompressionConfig.builder().enable(true)
.withType(DMLScript.FEDERATED_COMPRESSION_TYPE)
.withSparsity(DMLScript.FEDERATED_COMPRESSION_SPARSITY)
.withBits(DMLScript.FEDERATED_COMPRESSION_BITS).build();
MatrixCompressor compressor = CompressionFactory.create(config);
CompressedMatrix compressed = compressor.compress((MatrixBlock) cb);
return new FederatedRequest(RequestType.PUT_VAR, lineageItem, id, compressed);
}
catch(Exception ex) {
// Fall back to uncompressed on any error
}
}
// === END COMPRESSION INTEGRATION ===

return new FederatedRequest(RequestType.PUT_VAR, lineageItem, id, cb);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.sysds.runtime.controlprogram.federated.compression;

import java.io.Serializable;

/**
* Generic container for compressed matrix data. Stores the compressed representation along with metadata needed for
* decompression and size estimation.
*/
public class CompressedMatrix implements Serializable {

private static final long serialVersionUID = 1L;

private final CompressionType type;
private final int numRows;
private final int numCols;
private final Object compressedData; // Technique-specific data
private final double compressionRatio;
private final byte[] metadata; // Optional: scaling factors, etc.

public CompressedMatrix(CompressionType type, int numRows, int numCols, Object compressedData,
double compressionRatio) {
this(type, numRows, numCols, compressedData, compressionRatio, null);
}

public CompressedMatrix(CompressionType type, int numRows, int numCols, Object compressedData,
double compressionRatio, byte[] metadata) {
this.type = type;
this.numRows = numRows;
this.numCols = numCols;
this.compressedData = compressedData;
this.compressionRatio = compressionRatio;
this.metadata = metadata;
}

public CompressionType getType() {
return type;
}

public int getNumRows() {
return numRows;
}

public int getNumCols() {
return numCols;
}

public Object getCompressedData() {
return compressedData;
}

public double getCompressionRatio() {
return compressionRatio;
}

public byte[] getMetadata() {
return metadata;
}

/** Estimate original size in bytes (8 bytes per double) */
public long estimateOriginalSizeBytes() {
return (long) numRows * numCols * 8;
}

/** Estimate compressed size in bytes */
public long getCompressedSizeBytes() {
if(compressedData instanceof byte[]) {
return ((byte[]) compressedData).length;
}
return 0;
}

@Override
public String toString() {
return String.format("CompressedMatrix[%s, %dx%d, ratio=%.2fx]", type.getId(), numRows, numCols,
compressionRatio);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.sysds.runtime.controlprogram.federated.compression;

import java.util.HashMap;
import java.util.Map;

/**
* Immutable configuration for compression in federated operations. Uses the Builder pattern for flexible, readable
* configuration.
*
* Usage example: CompressionConfig config = CompressionConfig.builder() .enable(true) .withType(CompressionType.TOPK)
* .withSparsity(0.01) .build();
*/
public class CompressionConfig {

private final boolean enabled;
private final CompressionType type;
private final Map<String, Object> parameters;

private CompressionConfig(Builder builder) {
this.enabled = builder.enabled;
this.type = builder.enabled ? builder.type : CompressionType.NONE;
this.parameters = new HashMap<>(builder.parameters);
}

public boolean isEnabled() {
return enabled;
}

public CompressionType getType() {
return type;
}

public Map<String, Object> getParameters() {
return new HashMap<>(parameters);
}

/** Convenience getter for sparsity parameter (TopK) */
public double getSparsity() {
return (double) parameters.getOrDefault("sparsity", 0.01);
}

/** Convenience getter for bits parameter (Quantization) */
public int getBits() {
return (int) parameters.getOrDefault("bits", 4);
}

@Override
public String toString() {
return String.format("CompressionConfig[enabled=%s, type=%s, params=%s]", enabled, type.getId(), parameters);
}

// -----------------------------------------------------------------------
// Builder
// -----------------------------------------------------------------------

public static Builder builder() {
return new Builder();
}

public static class Builder {
private boolean enabled = false;
private CompressionType type = CompressionType.NONE;
private final Map<String, Object> parameters = new HashMap<>();

public Builder enable(boolean enabled) {
this.enabled = enabled;
return this;
}

public Builder withType(CompressionType type) {
this.type = type;
return this;
}

public Builder withParameter(String key, Object value) {
this.parameters.put(key, value);
return this;
}

/** Shorthand for TopK sparsity ratio */
public Builder withSparsity(double sparsity) {
return withParameter("sparsity", sparsity);
}

/** Shorthand for quantization bit width */
public Builder withBits(int bits) {
return withParameter("bits", bits);
}

public CompressionConfig build() {
return new CompressionConfig(this);
}
}
}
Loading
Loading