### Run LinSATNet Example Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/README.md Navigate into the cloned repository and execute the main example script using Python. ```shell cd LinSATNet python LinSATNet/linsat.py ``` -------------------------------- ### Install LinSATNet Source: https://context7.com/thinklab-sjtu/linsatnet/llms.txt Install the LinSATNet library using pip. ```bash pip install linsatnet ``` -------------------------------- ### Install LinSATNet Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/README.md Install the LinSATNet library using pip. This command upgrades to the latest version if already installed. ```shell pip install linsatnet ``` ```shell pip install --upgrade linsatnet ``` -------------------------------- ### Install Dependencies Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/portfolio_exp/README.md Install all necessary packages for the project using pip. Ensure you have the specified versions of numpy, scipy, pandas, and torch. ```bash pip install linsatnet numpy==1.19.5 scipy==1.5.4 pandas==1.1.5 torch==1.7.1 ``` -------------------------------- ### Clone LinSATNet Repository Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/README.md Clone the LinSATNet repository from GitHub to access the example code. ```shell git clone https://github.com/Thinklab-SJTU/LinSATNet.git ``` -------------------------------- ### Gradient-Based Optimization Example Source: https://context7.com/thinklab-sjtu/linsatnet/llms.txt Illustrates a complete training loop for optimizing neural network weights to satisfy constraints and match a target output. Uses SGD optimizer and monitors loss and constraint violation. ```python import torch from LinSATNet import linsat_layer # Doubly-stochastic constraint E = torch.tensor( [[1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1], [1, 0, 0, 1, 0, 0, 1, 0, 0], [0, 1, 0, 0, 1, 0, 0, 1, 0], [0, 0, 1, 0, 0, 1, 0, 0, 1]], dtype=torch.float32 ) f = torch.tensor([1, 1, 1, 1, 1, 1], dtype=torch.float32) # Initialize "neural network output" (learnable parameter) w = torch.rand(9, requires_grad=True) # Target: identity matrix (diagonal) x_gt = torch.tensor([1, 0, 0, 0, 1, 0, 0, 0, 1], dtype=torch.float32) # Training loop optimizer = torch.optim.SGD([w], lr=0.1, momentum=0.9) num_iters = 20 for i in range(num_iters): # Forward pass through LinSAT layer x = linsat_layer(w, E=E, f=f, tau=0.1, max_iter=10, dummy_val=0) # Compute loss loss = ((x - x_gt) ** 2).sum() # Backward pass loss.backward() # Update weights optimizer.step() optimizer.zero_grad() # Check constraint violation cv = torch.matmul(E, x) - f if i % 5 == 0: print(f"Iter {i}: loss={loss.item():.4f}, " f"constraint_violation={torch.sum(torch.abs(cv)).item():.6f}") print(f"\nFinal output:\n{x.reshape(3, 3)}") ``` -------------------------------- ### Gradient-Based Optimization of w Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/README.md Perform gradient-based optimization over 'w' to minimize the difference between the linsat_layer output and 'x_gt'. This simulates training a neural network. Includes optimizer setup, training loop, and printing of metrics. ```python niters = 10 opt = torch.optim.SGD([w], lr=0.1, momentum=0.9) for i in range(niters): x = linsat_layer(w, E=E, f=f, tau=0.1, max_iter=10, dummy_val=0) cv = torch.matmul(E, x.t()).t() - f.unsqueeze(0) loss = ((x - x_gt) ** 2).sum() loss.backward() opt.step() opt.zero_grad() print(f'{i}/{niters}\n' f' underlying obj={torch.sum(w * x)}, ' f' loss={loss}, ' f' sum(constraint violation)={torch.sum(cv[cv > 0])}, ' f' x={x}, ' f' constraint violation={cv}') ``` -------------------------------- ### Build TSP Constraints with Start/End City Source: https://context7.com/thinklab-sjtu/linsatnet/llms.txt Constructs equality constraints for the Traveling Salesman Problem, specifying the starting and ending cities. Ensures each city is visited exactly once and each step visits exactly one city. ```python import torch from LinSATNet import linsat_layer def build_tsp_constraints(n_cities, start_city, end_city): """ Build equality constraints for TSP with start/end cities. X[i,k]=1 means city i is visited at step k. Constraints: - Each city visited exactly once: sum_k X[i,k] = 1 for all i - Each step visits exactly one city: sum_i X[i,k] = 1 for all k - Start city at step 1: X[start, 0] = 1 - End city at step n: X[end, n-1] = 1 """ num_vars = n_cities * n_cities constraints = [] rhs = [] # Row constraints: each city visited once for i in range(n_cities): row = torch.zeros(num_vars) for k in range(n_cities): row[i * n_cities + k] = 1 constraints.append(row) rhs.append(1.0) # Column constraints: each step visits one city for k in range(n_cities): col = torch.zeros(num_vars) for i in range(n_cities): col[i * n_cities + k] = 1 constraints.append(col) rhs.append(1.0) # Start constraint start_row = torch.zeros(num_vars) start_row[start_city * n_cities + 0] = 1 constraints.append(start_row) rhs.append(1.0) # End constraint end_row = torch.zeros(num_vars) end_row[end_city * n_cities + (n_cities - 1)] = 1 constraints.append(end_row) rhs.append(1.0) E = torch.stack(constraints) f = torch.tensor(rhs) return E, f # Example: 5-city TSP, start at city 0, end at city 4 n_cities = 5 E, f = build_tsp_constraints(n_cities, start_city=0, end_city=4) # Simulated neural network output for TSP solution w = torch.rand(n_cities * n_cities, requires_grad=True) # Project to satisfy TSP constraints x = linsat_layer(w, E=E, f=f, tau=0.05, max_iter=100, dummy_val=0) # Reshape to tour matrix tour_matrix = x.reshape(n_cities, n_cities) print("Tour matrix (X[i,k]=prob city i visited at step k):") print(tour_matrix) # Get most likely tour tour = torch.argmax(tour_matrix, dim=0) print(f"\nMost likely tour order: {tour.tolist()}") ``` -------------------------------- ### Define Ground-Truth Target (x_gt) Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/README.md Define the ground-truth target vector 'x_gt'. In this example, it represents a diagonal matrix, serving as the desired output for the linsat_layer. ```python x_gt = torch.tensor( [1, 0, 0, 0, 1, 0, 0, 0, 1], dtype=torch.float32 ) ``` -------------------------------- ### Run Experiment with LinSATNet Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/portfolio_exp/README.md Reproduce the main result of the portfolio optimization experiment using LinSATNet. This command executes the main script with the --use_linsatnet flag. ```python python main.py --use_linsatnet ``` -------------------------------- ### Classic Sinkhorn Algorithm Steps Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/README.md Illustrates the iterative steps for the classic Sinkhorn algorithm. Initialize the matrix and then repeatedly normalize with respect to row and column marginals until convergence. ```math Initialize $\Gamma_{i,j}=\frac{s_{i,j}}{\sum_{i=1}^m s_{i,j}}$ $\quad$**repeat**: $\qquad{\Gamma}_{i,j}^{\prime} = \frac{{\Gamma}_{i,j}v_{i}}{\sum_{j=1}^n {\Gamma}_{i,j}u_{j}}$; $`\triangleright`$ normalize w.r.t. $\mathbf{v}$ $\qquad{\Gamma}_{i,j} = \frac{{\Gamma}_{i,j}^{\prime}u_{j}}{\sum_{i=1}^m {\Gamma}_{i,j}^{\prime}u_{j}}$; $`\triangleright`$ normalize w.r.t. $\mathbf{u}$ $\quad$**until** convergence. ``` -------------------------------- ### GPU Acceleration with LinSATNet Source: https://context7.com/thinklab-sjtu/linsatnet/llms.txt Demonstrates how to utilize CUDA for GPU-accelerated training with LinSATNet. Constraints are moved to the GPU, and the `init_constraints` function is used for pre-initialization. ```python import torch from LinSATNet import linsat_layer, init_constraints device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') print(f"Using device: {device}") # Move constraints to GPU E = torch.tensor( [[1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1], [1, 0, 0, 1, 0, 0, 1, 0, 0], [0, 1, 0, 0, 1, 0, 0, 1, 0], [0, 0, 1, 0, 0, 1, 0, 0, 1]], dtype=torch.float32, device=device ) f = torch.tensor([1, 1, 1, 1, 1, 1], dtype=torch.float32, device=device) # Pre-init constraints on GPU constr_dict = init_constraints(num_var=9, E=E, f=f, grouped=True) ``` -------------------------------- ### Mixed Constraints: Packing, Covering, and Equality Source: https://context7.com/thinklab-sjtu/linsatnet/llms.txt Demonstrates how to combine packing (Ax <= b), covering (Cx >= d), and equality (Ex = f) constraints within a single linsat_layer call. Ensure correct matrix and vector dimensions for each constraint type. ```python import torch from LinSATNet import linsat_layer num_vars = 6 # Equality constraint: x0 + x1 + x2 = 1 (variables must sum to 1) E = torch.tensor([[1, 1, 1, 0, 0, 0]], dtype=torch.float32) f = torch.tensor([1.0], dtype=torch.float32) # Packing constraint: x3 + x4 <= 0.5 (upper bound on sum) A = torch.tensor([[0, 0, 0, 1, 1, 0]], dtype=torch.float32) b = torch.tensor([0.5], dtype=torch.float32) # Covering constraint: x4 + x5 >= 0.3 (lower bound on sum) C = torch.tensor([[0, 0, 0, 0, 1, 1]], dtype=torch.float32) d = torch.tensor([0.3], dtype=torch.float32) # Neural network output w = torch.rand(num_vars, requires_grad=True) # Project to satisfy all constraints x = linsat_layer( w, A=A, b=b, # Packing: Ax <= b C=C, d=d, # Covering: Cx >= d E=E, f=f, # Equality: Ex = f tau=0.1, max_iter=100, dummy_val=0 ) # Verify constraints print(f"Output: {x}") print(f"Equality (Ex=f): {torch.matmul(E, x)} == {f}") print(f"Packing (Ax<=b): {torch.matmul(A, x)} <= {b}") print(f"Covering (Cx>=d): {torch.matmul(C, x)} >= {d}") ``` -------------------------------- ### Run Experiment with Original StemGNN Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/portfolio_exp/README.md Run the portfolio optimization experiment using the original StemGNN implementation. This command executes the main script without any specific flags. ```python python main.py ``` -------------------------------- ### Portfolio Allocation with LinSATNet Source: https://context7.com/thinklab-sjtu/linsatnet/llms.txt Optimizes portfolio weights subject to minimum and maximum allocation constraints per asset, and ensures the sum of weights equals one. Demonstrates backpropagation through the projected weights. ```python import torch from LinSATNet import linsat_layer def build_portfolio_constraints(n_assets, min_allocation=0.05, max_allocation=0.3): """ Build constraints for portfolio allocation: - Sum of weights = 1 (equality) - Each weight <= max_allocation (packing) - Each weight >= min_allocation (covering) """ # Equality: all weights sum to 1 E = torch.ones(1, n_assets) f = torch.tensor([1.0]) # Packing: each weight <= max_allocation A = torch.eye(n_assets) b = torch.full((n_assets,), max_allocation) # Covering: each weight >= min_allocation C = torch.eye(n_assets) d = torch.full((n_assets,), min_allocation) return A, b, C, d, E, f # 10-asset portfolio n_assets = 10 A, b, C, d, E, f = build_portfolio_constraints(n_assets) # Neural network predicted scores (e.g., expected returns) predicted_scores = torch.randn(n_assets, requires_grad=True) # Project to valid portfolio allocation weights = linsat_layer( predicted_scores, A=A, b=b, # Max allocation per asset C=C, d=d, # Min allocation per asset E=E, f=f, # Sum to 1 tau=0.1, max_iter=100, dummy_val=0 ) print(f"Portfolio weights: {weights}") print(f"Sum of weights: {weights.sum().item():.4f}") print(f"Min weight: {weights.min().item():.4f} (constraint: >= 0.05)") print(f"Max weight: {weights.max().item():.4f} (constraint: <= 0.30)") # Backprop works through the allocation expected_return = torch.tensor([0.05, 0.08, 0.03, 0.12, 0.07, 0.09, 0.04, 0.11, 0.06, 0.10]) portfolio_return = (weights * expected_return).sum() portfolio_return.backward() print(f"\nPortfolio expected return: {portfolio_return.item():.4f}") print(f"Gradients available: {predicted_scores.grad is not None}") ``` -------------------------------- ### Pre-initialize Constraints for Efficiency Source: https://context7.com/thinklab-sjtu/linsatnet/llms.txt Use init_constraints to pre-process constraint matrices for reuse, improving efficiency in training loops. This avoids redundant computation across epochs. ```python import torch from LinSATNet import linsat_layer, init_constraints # Define constraints once E = torch.tensor( [[1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1], [1, 0, 0, 1, 0, 0, 1, 0, 0], [0, 1, 0, 0, 1, 0, 0, 1, 0], [0, 0, 1, 0, 0, 1, 0, 0, 1]], dtype=torch.float32 ) f = torch.tensor([1, 1, 1, 1, 1, 1], dtype=torch.float32) # Pre-initialize constraints (done once) constr_dict = init_constraints(num_var=9, E=E, f=f, grouped=True) # Use cached constraints in training loop (more efficient) for epoch in range(100): w = torch.rand(9, requires_grad=True) x = linsat_layer(w, constr_dict=constr_dict, tau=0.1, max_iter=10, dummy_val=0) # ... training logic ``` -------------------------------- ### Import LinSATNet Layer and Initialization Function Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/README.md Import the necessary components, 'linsat_layer' and 'init_constraints', from the LinSATNet package at the beginning of your Python script. ```python from LinSATNet import linsat_layer, init_constraints ``` -------------------------------- ### Dense vs. Sparse Constraint Matrix Source: https://context7.com/thinklab-sjtu/linsatnet/llms.txt Compares the results of using a dense versus a sparse constraint matrix with the linsat_layer. Sparse matrices offer better performance for large constraint sets. ```python E_dense = torch.tensor( [[1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1], [1, 0, 0, 1, 0, 0, 1, 0, 0], [0, 1, 0, 0, 1, 0, 0, 1, 0], [0, 0, 1, 0, 0, 1, 0, 0, 1]], dtype=torch.float32 ) f = torch.tensor([1, 1, 1, 1, 1, 1], dtype=torch.float32) # Convert to sparse COO format E_sparse = E_dense.to_sparse()) w = torch.rand(9, requires_grad=True) # Dense version x_dense = linsat_layer(w, E=E_dense, f=f, tau=0.1, max_iter=10, dummy_val=0) # Sparse version (same results, better for large matrices) x_sparse = linsat_layer(w, E=E_sparse, f=f, tau=0.1, max_iter=10, dummy_val=0) print(f"Dense result: {x_dense}") print(f"Sparse result: {x_sparse}") print(f"Results match: {torch.allclose(x_dense, x_sparse, atol=1e-5)}") ``` -------------------------------- ### LinSATNet Forward Pass with Sparse E Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/README.md Demonstrates using a sparse representation of the constraint matrix E for improved efficiency, especially with large inputs. The rest of the parameters remain the same. ```python linsat_outp = linsat_layer(w, E=E.to_sparse(), f=f, tau=0.1, max_iter=10, dummy_val=0) ``` -------------------------------- ### Initialize Network Output (w) Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/README.md Randomly initialize the vector 'w', which represents the output of a neural network. This vector is the input to the linsat_layer and requires gradient tracking for optimization. ```python w = torch.rand(9) # w could be the output of neural network w = w.requires_grad_(True) ``` -------------------------------- ### Train TSP-SE Model Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/TSP_exp/README.md Run this command to train the neural solver for the TSP-SE task. Checkpoints and logs are saved in the specified output directory. ```python python run_train.py --task StartEnd ``` -------------------------------- ### Batched Forward Pass on GPU Source: https://context7.com/thinklab-sjtu/linsatnet/llms.txt Performs a batched forward pass of the LinSATNet layer on a GPU. Ensure the device is correctly set. ```python batch_size = 128 w = torch.rand(batch_size, 9, device=device, requires_grad=True) x = linsat_layer(w, constr_dict=constr_dict, tau=0.1, max_iter=10, dummy_val=0) print(f"Output device: {x.device}") print(f"Output shape: {x.shape}") ``` -------------------------------- ### Import linsat_layer Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/README.md Import the linsat_layer function from the LinSATNet library for use in PyTorch models. ```python from LinSATNet import linsat_layer ``` -------------------------------- ### Train TSP-PRI Model Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/TSP_exp/README.md Execute this command to train the neural solver for the TSP-PRI task. The evaluation process is similar to TSP-SE. ```python python run_train.py --task Priority ``` -------------------------------- ### Project Neural Network Output with Equality Constraints Source: https://context7.com/thinklab-sjtu/linsatnet/llms.txt Use linsat_layer to project neural network outputs to satisfy equality constraints (Ex = f). Requires PyTorch and LinSATNet. The tau parameter controls the hardness of the projection. ```python import torch from LinSATNet import linsat_layer, init_constraints # Define a doubly-stochastic constraint for a 3x3 matrix (flattened to 9 variables) # Each row sums to 1, each column sums to 1 E = torch.tensor( [[1, 1, 1, 0, 0, 0, 0, 0, 0], # row 1 sum = 1 [0, 0, 0, 1, 1, 1, 0, 0, 0], # row 2 sum = 1 [0, 0, 0, 0, 0, 0, 1, 1, 1], # row 3 sum = 1 [1, 0, 0, 1, 0, 0, 1, 0, 0], # col 1 sum = 1 [0, 1, 0, 0, 1, 0, 0, 1, 0], # col 2 sum = 1 [0, 0, 1, 0, 0, 1, 0, 0, 1]], # col 3 sum = 1 dtype=torch.float32 ) f = torch.tensor([1, 1, 1, 1, 1, 1], dtype=torch.float32) # Simulate neural network output w = torch.rand(9, requires_grad=True) # Project to satisfy constraints x = linsat_layer( w, E=E, f=f, # Equality constraints: Ex = f tau=0.1, # Temperature: smaller = harder/more discrete max_iter=10, # Sinkhorn iterations dummy_val=0 # Value for dummy variables ) # Verify constraints are satisfied print(f"Output: {x}") print(f"Row sums: {x.reshape(3, 3).sum(dim=1)}") # Should be ~[1, 1, 1] print(f"Col sums: {x.reshape(3, 3).sum(dim=0)}") # Should be ~[1, 1, 1] # Backward pass works seamlessly loss = ((x - torch.eye(3).flatten()) ** 2).sum() loss.backward() print(f"Gradient: {w.grad}") ``` -------------------------------- ### Sparse Constraints for Large-Scale Problems Source: https://context7.com/thinklab-sjtu/linsatnet/llms.txt Utilize sparse constraint matrices with linsat_layer for improved memory and computational efficiency on large-scale problems. This requires importing linsat_layer from LinSATNet. ```python import torch from LinSATNet import linsat_layer ``` -------------------------------- ### Conventional Sinkhorn Formulation (Cuturi 2013) Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/README.md Presents the conventional Sinkhorn formulation for optimal transport as described by Cuturi (2013). This version focuses on the exact mass moved between distributions. ```math Initialize $\Gamma_{i,j}=\frac{s_{i,j}}{\sum_{i=1}^m s_{i,j}}$ $\quad$**repeat**: $\qquad{P}_{i,j}^{\prime} = \frac{P_{i,j}v_{i}}{\sum_{j=1}^n {P}_{i,j}}$; $`\triangleright`$ normalize w.r.t. $\mathbf{v}$ $\qquad{P}_{i,j} = \frac{{P}_{i,j}^{\prime}u_j}{\sum_{i=1}^m {P}_{i,j}^{\prime}}$; $`\triangleright`$ normalize w.r.t. $\mathbf{u}$ $\quad$**until** convergence. ``` -------------------------------- ### Define Doubly-Stochastic Constraints (E and f) Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/README.md Define the matrix E and vector f that represent the doubly-stochastic constraints for a 3x3 matrix, flattened into a vector. These are used in the linsat_layer function. ```python E = torch.tensor( [[1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1], [1, 0, 0, 1, 0, 0, 1, 0, 0], [0, 1, 0, 0, 1, 0, 0, 1, 0], [0, 0, 1, 0, 0, 1, 0, 0, 1]], dtype=torch.float32 ) f = torch.tensor([1, 1, 1, 1, 1, 1], dtype=torch.float32) ``` -------------------------------- ### Extended Sinkhorn Algorithm with Multi-Set Marginals Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/README.md Details the iterative process for the extended Sinkhorn algorithm that handles multiple sets of marginal distributions. It cycles through each set of marginals for normalization. ```math Initialize $\Gamma_{i,j}=\frac{s_{i,j}}{\sum_{i=1}^m s_{i,j}}$ $\quad$**repeat**: $\qquad$**for** $\eta=1$ **to** $k$ **do** $\quad\qquad{\Gamma}_{i,j}^{\prime} = \frac{{\Gamma}_{i,j}v_{\eta,i}}{\sum_{j=1}^n {\Gamma}_{i,j}u_{\eta,j}}$; $`\triangleright`$ normalize w.r.t. $\mathbf{v}_\eta$ $\quad\qquad{\Gamma}_{i,j} = \frac{{\Gamma}_{i,j}^{\prime}u_{\eta,j}}{\sum_{i=1}^m {\Gamma}_{i,j}^{\prime}u_{\eta,j}}$; $`\triangleright`$ normalize w.r.t. $\mathbf{u}_\eta$ $\qquad$**end for** $\quad$**until** convergence. ``` -------------------------------- ### LinSATNet Backward Pass and Loss Calculation Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/README.md Calculate the loss between the LinSATNet output and the ground-truth target, then perform a backward pass to compute gradients. This is a standard PyTorch procedure. ```python loss = ((linsat_outp - x_gt) ** 2).sum() loss.backward() ``` -------------------------------- ### LinSATNet Forward Pass Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/README.md Perform a forward pass using the linsat_layer with the initialized weights 'w' and defined constraints E and f. Specify parameters like tau, max_iter, and dummy_val. ```python linsat_outp = linsat_layer(w, E=E, f=f, tau=0.1, max_iter=10, dummy_val=0) ``` -------------------------------- ### Batch Processing with linsat_layer Source: https://context7.com/thinklab-sjtu/linsatnet/llms.txt Process batches of neural network outputs efficiently using linsat_layer. Constraints are shared across all samples in the batch. ```python import torch from LinSATNet import linsat_layer # Constraints for doubly-stochastic 3x3 matrices E = torch.tensor( [[1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1], [1, 0, 0, 1, 0, 0, 1, 0, 0], [0, 1, 0, 0, 1, 0, 0, 1, 0], [0, 0, 1, 0, 0, 1, 0, 0, 1]], dtype=torch.float32 ) f = torch.tensor([1, 1, 1, 1, 1, 1], dtype=torch.float32) # Batch of 32 neural network outputs batch_size = 32 w = torch.rand(batch_size, 9, requires_grad=True) # Process entire batch at once x = linsat_layer(w, E=E, f=f, tau=0.1, max_iter=10, dummy_val=0) print(f"Input shape: {w.shape}") # torch.Size([32, 9]) print(f"Output shape: {x.shape}") # torch.Size([32, 9]) # Verify all outputs satisfy constraints for i in range(batch_size): row_sums = x[i].reshape(3, 3).sum(dim=1) col_sums = x[i].reshape(3, 3).sum(dim=0) assert torch.allclose(row_sums, torch.ones(3), atol=1e-2) assert torch.allclose(col_sums, torch.ones(3), atol=1e-2) ``` -------------------------------- ### Evaluate Trained TSP-SE Model Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/TSP_exp/README.md Evaluate a trained TSP-SE model on a test dataset. Specify the model dictionary, test epoch, and test dataset path. The results will be saved in the same directory as the model. ```python python run_evaluate.py --model_dict outputs/StartEnd_20_timestamp --test_epoch 50 --test_dataset datasets/tsp20_test_seed1234.pkl ``` -------------------------------- ### LinSAT Layer Function Source: https://github.com/thinklab-sjtu/linsatnet/blob/main/README.md The linsat_layer function enforces positive linear constraints to the input x and projects it with the given constraints. ```APIDOC ## LinSATNet.linsat_layer ### Description Enforces positive linear constraints to the input `x` and projects it with the constraints $$\mathbf{A} \mathbf{x} <= \mathbf{b}, \mathbf{C} \mathbf{x} >= \mathbf{d}, \mathbf{E} \mathbf{x} = \mathbf{f}$$ and all elements in $\mathbf{A}, \mathbf{b}, \mathbf{C}, \mathbf{d}, \mathbf{E}, \mathbf{f}$ must be non-negative. ### Method `linsat_layer` ### Parameters * ``x`` (PyTorch tensor) - Input tensor of size ($n_v$) or ($b \times n_v$). * ``A``, ``C``, ``E`` (PyTorch tensor) - Constraint matrix of size ($n_c \times n_v$). * ``b``, ``d``, ``f`` (PyTorch tensor) - Constraint vector of size ($n_c$). * ``constr_dict`` (dict) - Dictionary with initialized constraint information (output of `LinSATNet.init_constraints`). * ``tau`` (float) - Default: 0.05. Parameter to control the discreteness of the projection. * ``max_iter`` (int) - Default: 100. Maximum number of iterations. * ``dummy_val`` (float) - Default: 0. Value of dummy variables appended to the input vector. * ``mode`` (str) - Default: 'v2'. LinSAT kernel implementation ('v1' or 'v2'). * ``grouped`` (bool) - Default: True. Group non-overlapping constraints for efficiency. * ``no_warning`` (bool) - Default: False. Turn off warning messages. ### Return PyTorch tensor of size ($n_v$) or ($b \times n_v$), the projected variables. ### Practical Notes 1. Ensure input constraints have a non-empty feasible space. 2. `x` is typically in the range [0, 1]; a multiplier can be used for scaling. 3. Tune `tau` (e.g., from 1e-4 to 100) for desired output smoothness. 4. Be mindful of numerical precision; e.g., `A x <= 0.999` might work when `A x <= 1` does not. 5. Constraints cannot have a batch dimension; they must be consistent across a batch. 6. Use sparse tensors for constraints (`A`, `C`, `E`) to save GPU memory when applicable. ### How it works? Extends the Sinkhorn algorithm to multiple sets of marginals, transforming constraints into marginals to enforce them. Refer to the paper for details. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.