maj tig_testnet
Some checks are pending
Test Workspace / Test Workspace (push) Waiting to run

This commit is contained in:
xnico31 2025-03-31 14:21:55 +02:00
parent d79e03daac
commit f4cda56d80
213 changed files with 1111 additions and 29458 deletions

Binary file not shown.

View File

@ -1,5 +0,0 @@
{
"opRetro": {
"projectId": "0xb0898866c2c537c61b37d04916e3879ef78fed630181c1ffaf492499d174f0bf"
}
}

View File

@ -5,7 +5,7 @@ BLOCK_ID=$(curl -s https://mainnet-api.tig.foundation/get-block | jq -r '.block.
RESP=$(curl -s "https://mainnet-api.tig.foundation/get-algorithms?block_id=$BLOCK_ID")
ALGORITHMS=$(echo $RESP | jq -c '.algorithms[]' | jq -s 'sort_by(.id)')
WASMS_DICT=$(echo $RESP | jq -c '[.wasms[] | {key: .algorithm_id, value: .}] | from_entries')
WASMS_DICT=$(echo $RESP | jq -c '[.binarys[] | {key: .algorithm_id, value: .}] | from_entries')
for ALGO in $(echo $ALGORITHMS | jq -c '.[]'); do
ID=$(echo $ALGO | jq -r '.id')

View File

@ -1,3 +1,3 @@
#!/bin/bash
set -e
curl -s https://mainnet-api.tig.foundation/get-block?include_data | jq -r '.block.data.active_benchmark_ids[]' | nl
curl -s https://mainnet-api.tig.foundation/get-block?include_data | jq -r '.block.data.active_ids.benchmark[]' | nl

View File

@ -2,13 +2,12 @@
set -e
BLOCK_ID=$(curl -s https://mainnet-api.tig.foundation/get-block | jq -r '.block.id')
RESP=$(curl -s "https://mainnet-api.tig.foundation/get-players?player_type=benchmarker&block_id=$BLOCK_ID")
RESP=$(curl -s "https://mainnet-api.tig.foundation/get-opow?block_id=$BLOCK_ID")
PLAYERS=$(echo $RESP | jq -c '[.players[] | .block_data.reward = (if .block_data.reward == null then 0 else (.block_data.reward | tonumber) end)] | sort_by(.block_data.reward) | reverse')
PLAYERS=$(echo $RESP | jq -c '[.opow[] | .block_data.reward = (if .block_data.reward == null then 0 else (.block_data.reward | tonumber) end)] | sort_by(.block_data.reward) | reverse')
for PLAYER in $(echo $PLAYERS | jq -c '.[]'); do
ID=$(echo $PLAYER | jq -r '.id')
ROUND_EARNINGS=$(echo $PLAYER | jq -r '.block_data.round_earnings | tonumber / 1e18')
ID=$(echo $PLAYER | jq -r '.player_id')
REWARD=$(echo $PLAYER | jq -r '.block_data.reward | if . == null then "null" else tonumber / 1e18 end')
printf "Player ID: %-25s Round Earnings: %-20s Reward: %-20s\n" "$ID" "$ROUND_EARNINGS" "$REWARD"
printf "Player ID: %-25s Reward: %-20s\n" "$ID" "$REWARD"
done

View File

@ -77,7 +77,7 @@ if ! is_positive_integer "$num_workers"; then
exit 1
fi
read -p "Enter max fuel (default is 10000000000): " max_fuel
max_fuel=${max_fuel:-1}
max_fuel=${max_fuel:-10000000000}
if ! is_positive_integer "$max_fuel"; then
echo "Error: Max fuel must be a positive integer."
exit 1

View File

@ -153,6 +153,31 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/GetBlockResponse'
/get-delegators:
get:
tags:
- GET
summary: Get latest delegators data
description: |-
# Notes
* Query parameter `<block_id>` must be the latest block. Use `/get-block` endpoint
* All players who have a deposit are included in the response
parameters:
- name: block_id
in: query
required: true
schema:
$ref: '#/components/schemas/MD5'
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/GetDelegatorsResponse'
/get-difficulty-data:
get:
tags:
@ -271,8 +296,19 @@ paths:
description: |-
# Notes
* `algorithms` is a map of `<algorithm_id>` to `uint256`
* `opow` is a map of `<player_id>` to `uint256`
* `players` is a map of `<player_id>` to dict of reward types (algorithm, benchmark, breakthroughs, delegator)
* `breakthroughs` is a map of `<breakthrough_id>` to `uint256`
* `opow` is a map of `<player_id>` to a dict:
* `total` is the total reward earned by the Benchmarker this round before any sharing is deducted
* `shared` is the total reward shared by the Benchmarker with delegators this round
* `coinbase` is the total reward distributed by the Benchmarker with pool members this round
* `players` is a map of `<player_id>` to a dict of reward types (algorithm, benchmark, breakthroughs, delegator)
* `names` is a map of `<player_id>` to ENS name (only if one exists)
parameters:
- name: round
@ -313,6 +349,38 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/RequestApiKeyResponse'
/set-coinbase:
post:
tags:
- POST
summary: Set distribution of your reward amongst pool members
description: |-
# Notes
* Can only be updated once every `block.config.opow.coinbase_update_period` blocks
* Header `X-Api-Key` is required. Use `/request-api-key` endpoint.
* If `<api_key>` is invalid, a `401` error will be returned
* `<coinbase>` is a map of `<player_id>` to `float`, where the floats must sum to at most `1.0`
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/SetCoinbaseRequest'
parameters:
- in: header
name: X-Api-Key
description: <api_key> from /request-api-key endpoint
schema:
$ref: '#/components/schemas/MD5'
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/SetCoinbaseResponse'
/set-delegatees:
post:
tags:
@ -376,6 +444,42 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/SetRewardShareResponse'
/set-vote:
post:
tags:
- POST
summary: Cast vote on breakthrough
description: |-
# Notes
* Votes are immutable. Once set, cannot change
* Header `X-Api-Key` is required. Use `/request-api-key` endpoint.
* If `<api_key>` is invalid, a `401` error will be returned
* Signature must be from signing the following message:
* If voting yes: `I hereby confirm my vote that '<breakthrough_name>' IS A BREAKTHROUGH`
* If voting no: `I hereby confirm my vote that '<breakthrough_name>' IS INELIGIBLE AS A BREAKTHROUGH`
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/SetVoteRequest'
parameters:
- in: header
name: X-Api-Key
description: <api_key> from /request-api-key endpoint
schema:
$ref: '#/components/schemas/MD5'
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/SetVoteResponse'
/submit-algorithm:
post:
tags:
@ -386,9 +490,7 @@ paths:
* This endpoint can only be invoked once every few seconds
* If an algorithm submission has failed to compile (`wasm.state.compiled_success = false`), you can re-use the same algorithm name.
* `<tx_hash>` is the id of the transaction that has burnt the required `block.config.algorithm_submissions.submission_fee` TIG to the `block.config.erc20.burn_address`
* If an algorithm submission has failed to compile (`binary.state.compiled_success = false`), you can re-use the same algorithm name.
* Header `X-Api-Key` is required. Use `/request-api-key` endpoint.
@ -446,38 +548,6 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/SubmitBenchmarkResponse'
/submit-deposit:
post:
tags:
- POST
summary: Submit a deposit
description: |-
# Notes
* `<tx_hash>` is the id of the transaction that has sent at least `block.config.deposits.min_lock_amount` TIG to `block.config.deposits.lock_address`. Additionally:
* Must be non-cancellable
* Must be non-transferrable
* Minimum lock duration must be at least 1 week (604800 seconds)
* `<log_idx>` is the log index of the CreateLockupLinearStream event
* If `<log_idx>` is null, then the first CreateLockupLinearStream event will be used
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/SubmitDepositRequest'
parameters:
- in: header
name: X-Api-Key
description: <api_key> from /request-api-key endpoint
schema:
$ref: '#/components/schemas/MD5'
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/SubmitDepositResponse'
/submit-precommit:
post:
tags:
@ -536,36 +606,6 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/SubmitProofResponse'
/submit-topup:
post:
tags:
- POST
summary: Submit a topup transaction
description: |-
# Notes
* `<tx_hash>` is the id of the transaction that has sent at least `block.config.topups.topup_amount` TIG to the `block.config.topups.topup_address`
* `<log_idx>` is the log index of the CreateLockupLinearStream event
* If `<log_idx>` is null, then the first CreateLockupLinearStream event will be used
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/SubmitTopupRequest'
parameters:
- in: header
name: X-Api-Key
description: <api_key> from /request-api-key endpoint
schema:
$ref: '#/components/schemas/MD5'
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/SubmitTopupResponse'
components:
schemas:
Address:
@ -919,6 +959,12 @@ components:
round_pushed:
type: integer
format: uint32
round_voting_starts:
type: integer
format: uint32
round_votes_tallied:
type: integer
format: uint32
round_active:
type: integer
format: uint32
@ -949,6 +995,9 @@ components:
num_qualifiers:
type: integer
format: uint32
average_solution_ratio:
type: number
format: double
qualifier_difficulties:
type: array
items:
@ -1021,6 +1070,8 @@ components:
DifficultyData:
type: object
properties:
algorithm_id:
$ref: '#/components/schemas/AlgorithmId'
num_nonces:
type: integer
format: uint64
@ -1083,18 +1134,29 @@ components:
type: integer
format: uint32
example: {"c001": 5, "c002": 3}
solution_ratio_by_challenge:
type: object
additionalProperties:
type: double
format: number
example: {"c001": 0.001, "c002": 0.5}
cutoff:
type: integer
format: uint32
associated_deposit:
self_deposit:
$ref: '#/components/schemas/PreciseNumber'
delegated_weighted_deposit:
$ref: '#/components/schemas/PreciseNumber'
delegators:
type: array
items:
$ref: '#/components/schemas/Address'
coinbase:
type: object
additionalProperties:
$ref: '#/components/schemas/PreciseNumber'
reward_share:
type: number
format: double
$ref: '#/components/schemas/PreciseNumber'
imbalance:
$ref: '#/components/schemas/PreciseNumber'
influence:
@ -1348,6 +1410,25 @@ components:
type: array
items:
$ref: '#/components/schemas/Challenge'
GetDelegatorsResponse:
type: object
properties:
delegators:
type: array
items:
type: object
properties:
player_id:
$ref: '#/components/schemas/Address'
deposit:
$ref: '#/components/schemas/PreciseNumber'
delegatees:
type: object
additionalProperties:
type: number
format: double
reward:
$ref: '#/components/schemas/PreciseNumber'
GetDifficultyDataResponse:
type: object
properties:
@ -1386,10 +1467,23 @@ components:
type: object
additionalProperties:
$ref: '#/components/schemas/PreciseNumber'
opow:
breakthroughs:
type: object
additionalProperties:
$ref: '#/components/schemas/PreciseNumber'
opow:
type: object
additionalProperties:
type: object
properties:
total:
$ref: '#/components/schemas/PreciseNumber'
shared:
$ref: '#/components/schemas/PreciseNumber'
coinbase:
type: object
additionalProperties:
$ref: '#/components/schemas/PreciseNumber'
players:
type: object
additionalProperties:
@ -1422,13 +1516,25 @@ components:
$ref: '#/components/schemas/MD5'
name:
type: string
SetCoinbaseRequest:
type: object
properties:
coinbase:
type: number
format: double
SetCoinbaseResponse:
type: object
properties:
ok:
type: boolean
SetDelegateesRequest:
type: object
properties:
delegatees:
type: object
additionalProperties:
type: float
type: number
format: double
SetDelegateeResponse:
type: object
properties:
@ -1445,6 +1551,20 @@ components:
properties:
ok:
type: boolean
SetVoteRequest:
type: object
properties:
breakthrough_id:
type: string
yes:
type: boolean
signature:
$ref: '#/components/schemas/Signature'
SetVoteResponse:
type: object
properties:
ok:
type: boolean
SubmitAlgorithmRequest:
type: object
properties:
@ -1476,19 +1596,6 @@ components:
properties:
ok:
type: boolean
SubmitDepositRequest:
type: object
properties:
tx_hash:
$ref: '#/components/schemas/TxHash'
log_idx:
type: integer
format: uint32
SubmitDepositResponse:
type: object
properties:
deposit_id:
$ref: '#/components/schemas/MD5'
SubmitPrecommitRequest:
type: object
properties:
@ -1515,17 +1622,4 @@ components:
type: object
properties:
verified:
type: string
SubmitTopupRequest:
type: object
properties:
tx_hash:
$ref: '#/components/schemas/TxHash'
log_idx:
type: integer
format: uint32
SubmitTopupResponse:
type: object
properties:
topup_id:
$ref: '#/components/schemas/MD5'
type: string

View File

@ -12,7 +12,10 @@ cudarc = { version = "0.12.0", features = [
"cuda-version-from-build-system",
], optional = true }
ndarray = "0.15.6"
rand = { version = "0.8.5", default-features = false, features = ["std_rng"] }
rand = { version = "0.8.5", default-features = false, features = [
"std_rng",
"small_rng",
] }
tig-challenges = { path = "../tig-challenges" }
[lib]

View File

@ -1,167 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Benchmarker Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use anyhow::Result;
use tig_challenges::knapsack::{Challenge, Solution};
pub fn solve_challenge(challenge: &Challenge) -> Result<Option<Solution>> {
let vertex_count = challenge.weights.len();
let mut edge_costs: Vec<(usize, f32)> = (0..vertex_count)
.map(|flow_index| {
let total_flow = challenge.values[flow_index] as i32 +
challenge.interaction_values[flow_index].iter().sum::<i32>();
let cost = total_flow as f32 / challenge.weights[flow_index] as f32;
(flow_index, cost)
})
.collect();
edge_costs.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut coloring = Vec::with_capacity(vertex_count);
let mut uncolored = Vec::with_capacity(vertex_count);
let mut current_entropy = 0;
let mut current_temperature = 0;
for &(flow_index, _) in &edge_costs {
if current_entropy + challenge.weights[flow_index] <= challenge.max_weight {
current_entropy += challenge.weights[flow_index];
current_temperature += challenge.values[flow_index] as i32;
for &colored in &coloring {
current_temperature += challenge.interaction_values[flow_index][colored];
}
coloring.push(flow_index);
} else {
uncolored.push(flow_index);
}
}
let mut mutation_rates = vec![0; vertex_count];
for flow_index in 0..vertex_count {
mutation_rates[flow_index] = challenge.values[flow_index] as i32;
for &colored in &coloring {
mutation_rates[flow_index] += challenge.interaction_values[flow_index][colored];
}
}
let max_generations = 100;
let mut cooling_schedule = vec![0; vertex_count];
for _ in 0..max_generations {
let mut best_mutation = 0;
let mut best_crossover = None;
for uncolored_index in 0..uncolored.len() {
let mutant = uncolored[uncolored_index];
if cooling_schedule[mutant] > 0 {
continue;
}
unsafe {
let mutant_fitness = *mutation_rates.get_unchecked(mutant);
let min_entropy_reduction = *challenge.weights.get_unchecked(mutant) as i32 - (challenge.max_weight as i32 - current_entropy as i32);
if mutant_fitness < 0 {
continue;
}
for colored_index in 0..coloring.len() {
let gene_to_remove = *coloring.get_unchecked(colored_index);
if *cooling_schedule.get_unchecked(gene_to_remove) > 0 {
continue;
}
if min_entropy_reduction > 0 {
let removed_entropy = *challenge.weights.get_unchecked(gene_to_remove) as i32;
if removed_entropy < min_entropy_reduction {
continue;
}
}
let fitness_change = mutant_fitness - *mutation_rates.get_unchecked(gene_to_remove)
- *challenge.interaction_values.get_unchecked(mutant).get_unchecked(gene_to_remove);
if fitness_change > best_mutation {
best_mutation = fitness_change;
best_crossover = Some((uncolored_index, colored_index));
}
}
}
}
if let Some((uncolored_index, colored_index)) = best_crossover {
let gene_to_add = uncolored[uncolored_index];
let gene_to_remove = coloring[colored_index];
coloring.swap_remove(colored_index);
uncolored.swap_remove(uncolored_index);
coloring.push(gene_to_add);
uncolored.push(gene_to_remove);
current_temperature += best_mutation;
current_entropy = current_entropy + challenge.weights[gene_to_add] - challenge.weights[gene_to_remove];
unsafe {
for flow_index in 0..vertex_count {
*mutation_rates.get_unchecked_mut(flow_index) +=
challenge.interaction_values.get_unchecked(flow_index).get_unchecked(gene_to_add) -
challenge.interaction_values.get_unchecked(flow_index).get_unchecked(gene_to_remove);
}
}
cooling_schedule[gene_to_add] = 3;
cooling_schedule[gene_to_remove] = 3;
} else {
break;
}
if current_temperature as u32 >= challenge.min_value {
return Ok(Some(Solution { items: coloring }));
}
for cooling_rate in cooling_schedule.iter_mut() {
*cooling_rate = if *cooling_rate > 0 { *cooling_rate - 1 } else { 0 };
}
}
if current_temperature as u32 >= challenge.min_value {
Ok(Some(Solution { items: coloring }))
} else {
Ok(None)
}
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,167 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Commercial License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use anyhow::Result;
use tig_challenges::knapsack::{Challenge, Solution};
pub fn solve_challenge(challenge: &Challenge) -> Result<Option<Solution>> {
let vertex_count = challenge.weights.len();
let mut edge_costs: Vec<(usize, f32)> = (0..vertex_count)
.map(|flow_index| {
let total_flow = challenge.values[flow_index] as i32 +
challenge.interaction_values[flow_index].iter().sum::<i32>();
let cost = total_flow as f32 / challenge.weights[flow_index] as f32;
(flow_index, cost)
})
.collect();
edge_costs.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut coloring = Vec::with_capacity(vertex_count);
let mut uncolored = Vec::with_capacity(vertex_count);
let mut current_entropy = 0;
let mut current_temperature = 0;
for &(flow_index, _) in &edge_costs {
if current_entropy + challenge.weights[flow_index] <= challenge.max_weight {
current_entropy += challenge.weights[flow_index];
current_temperature += challenge.values[flow_index] as i32;
for &colored in &coloring {
current_temperature += challenge.interaction_values[flow_index][colored];
}
coloring.push(flow_index);
} else {
uncolored.push(flow_index);
}
}
let mut mutation_rates = vec![0; vertex_count];
for flow_index in 0..vertex_count {
mutation_rates[flow_index] = challenge.values[flow_index] as i32;
for &colored in &coloring {
mutation_rates[flow_index] += challenge.interaction_values[flow_index][colored];
}
}
let max_generations = 100;
let mut cooling_schedule = vec![0; vertex_count];
for _ in 0..max_generations {
let mut best_mutation = 0;
let mut best_crossover = None;
for uncolored_index in 0..uncolored.len() {
let mutant = uncolored[uncolored_index];
if cooling_schedule[mutant] > 0 {
continue;
}
unsafe {
let mutant_fitness = *mutation_rates.get_unchecked(mutant);
let min_entropy_reduction = *challenge.weights.get_unchecked(mutant) as i32 - (challenge.max_weight as i32 - current_entropy as i32);
if mutant_fitness < 0 {
continue;
}
for colored_index in 0..coloring.len() {
let gene_to_remove = *coloring.get_unchecked(colored_index);
if *cooling_schedule.get_unchecked(gene_to_remove) > 0 {
continue;
}
if min_entropy_reduction > 0 {
let removed_entropy = *challenge.weights.get_unchecked(gene_to_remove) as i32;
if removed_entropy < min_entropy_reduction {
continue;
}
}
let fitness_change = mutant_fitness - *mutation_rates.get_unchecked(gene_to_remove)
- *challenge.interaction_values.get_unchecked(mutant).get_unchecked(gene_to_remove);
if fitness_change > best_mutation {
best_mutation = fitness_change;
best_crossover = Some((uncolored_index, colored_index));
}
}
}
}
if let Some((uncolored_index, colored_index)) = best_crossover {
let gene_to_add = uncolored[uncolored_index];
let gene_to_remove = coloring[colored_index];
coloring.swap_remove(colored_index);
uncolored.swap_remove(uncolored_index);
coloring.push(gene_to_add);
uncolored.push(gene_to_remove);
current_temperature += best_mutation;
current_entropy = current_entropy + challenge.weights[gene_to_add] - challenge.weights[gene_to_remove];
unsafe {
for flow_index in 0..vertex_count {
*mutation_rates.get_unchecked_mut(flow_index) +=
challenge.interaction_values.get_unchecked(flow_index).get_unchecked(gene_to_add) -
challenge.interaction_values.get_unchecked(flow_index).get_unchecked(gene_to_remove);
}
}
cooling_schedule[gene_to_add] = 3;
cooling_schedule[gene_to_remove] = 3;
} else {
break;
}
if current_temperature as u32 >= challenge.min_value {
return Ok(Some(Solution { items: coloring }));
}
for cooling_rate in cooling_schedule.iter_mut() {
*cooling_rate = if *cooling_rate > 0 { *cooling_rate - 1 } else { 0 };
}
}
if current_temperature as u32 >= challenge.min_value {
Ok(Some(Solution { items: coloring }))
} else {
Ok(None)
}
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,167 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use anyhow::Result;
use tig_challenges::knapsack::{Challenge, Solution};
pub fn solve_challenge(challenge: &Challenge) -> Result<Option<Solution>> {
let vertex_count = challenge.weights.len();
let mut edge_costs: Vec<(usize, f32)> = (0..vertex_count)
.map(|flow_index| {
let total_flow = challenge.values[flow_index] as i32 +
challenge.interaction_values[flow_index].iter().sum::<i32>();
let cost = total_flow as f32 / challenge.weights[flow_index] as f32;
(flow_index, cost)
})
.collect();
edge_costs.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut coloring = Vec::with_capacity(vertex_count);
let mut uncolored = Vec::with_capacity(vertex_count);
let mut current_entropy = 0;
let mut current_temperature = 0;
for &(flow_index, _) in &edge_costs {
if current_entropy + challenge.weights[flow_index] <= challenge.max_weight {
current_entropy += challenge.weights[flow_index];
current_temperature += challenge.values[flow_index] as i32;
for &colored in &coloring {
current_temperature += challenge.interaction_values[flow_index][colored];
}
coloring.push(flow_index);
} else {
uncolored.push(flow_index);
}
}
let mut mutation_rates = vec![0; vertex_count];
for flow_index in 0..vertex_count {
mutation_rates[flow_index] = challenge.values[flow_index] as i32;
for &colored in &coloring {
mutation_rates[flow_index] += challenge.interaction_values[flow_index][colored];
}
}
let max_generations = 100;
let mut cooling_schedule = vec![0; vertex_count];
for _ in 0..max_generations {
let mut best_mutation = 0;
let mut best_crossover = None;
for uncolored_index in 0..uncolored.len() {
let mutant = uncolored[uncolored_index];
if cooling_schedule[mutant] > 0 {
continue;
}
unsafe {
let mutant_fitness = *mutation_rates.get_unchecked(mutant);
let min_entropy_reduction = *challenge.weights.get_unchecked(mutant) as i32 - (challenge.max_weight as i32 - current_entropy as i32);
if mutant_fitness < 0 {
continue;
}
for colored_index in 0..coloring.len() {
let gene_to_remove = *coloring.get_unchecked(colored_index);
if *cooling_schedule.get_unchecked(gene_to_remove) > 0 {
continue;
}
if min_entropy_reduction > 0 {
let removed_entropy = *challenge.weights.get_unchecked(gene_to_remove) as i32;
if removed_entropy < min_entropy_reduction {
continue;
}
}
let fitness_change = mutant_fitness - *mutation_rates.get_unchecked(gene_to_remove)
- *challenge.interaction_values.get_unchecked(mutant).get_unchecked(gene_to_remove);
if fitness_change > best_mutation {
best_mutation = fitness_change;
best_crossover = Some((uncolored_index, colored_index));
}
}
}
}
if let Some((uncolored_index, colored_index)) = best_crossover {
let gene_to_add = uncolored[uncolored_index];
let gene_to_remove = coloring[colored_index];
coloring.swap_remove(colored_index);
uncolored.swap_remove(uncolored_index);
coloring.push(gene_to_add);
uncolored.push(gene_to_remove);
current_temperature += best_mutation;
current_entropy = current_entropy + challenge.weights[gene_to_add] - challenge.weights[gene_to_remove];
unsafe {
for flow_index in 0..vertex_count {
*mutation_rates.get_unchecked_mut(flow_index) +=
challenge.interaction_values.get_unchecked(flow_index).get_unchecked(gene_to_add) -
challenge.interaction_values.get_unchecked(flow_index).get_unchecked(gene_to_remove);
}
}
cooling_schedule[gene_to_add] = 3;
cooling_schedule[gene_to_remove] = 3;
} else {
break;
}
if current_temperature as u32 >= challenge.min_value {
return Ok(Some(Solution { items: coloring }));
}
for cooling_rate in cooling_schedule.iter_mut() {
*cooling_rate = if *cooling_rate > 0 { *cooling_rate - 1 } else { 0 };
}
}
if current_temperature as u32 >= challenge.min_value {
Ok(Some(Solution { items: coloring }))
} else {
Ok(None)
}
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,167 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Innovator Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use anyhow::Result;
use tig_challenges::knapsack::{Challenge, Solution};
pub fn solve_challenge(challenge: &Challenge) -> Result<Option<Solution>> {
let vertex_count = challenge.weights.len();
let mut edge_costs: Vec<(usize, f32)> = (0..vertex_count)
.map(|flow_index| {
let total_flow = challenge.values[flow_index] as i32 +
challenge.interaction_values[flow_index].iter().sum::<i32>();
let cost = total_flow as f32 / challenge.weights[flow_index] as f32;
(flow_index, cost)
})
.collect();
edge_costs.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut coloring = Vec::with_capacity(vertex_count);
let mut uncolored = Vec::with_capacity(vertex_count);
let mut current_entropy = 0;
let mut current_temperature = 0;
for &(flow_index, _) in &edge_costs {
if current_entropy + challenge.weights[flow_index] <= challenge.max_weight {
current_entropy += challenge.weights[flow_index];
current_temperature += challenge.values[flow_index] as i32;
for &colored in &coloring {
current_temperature += challenge.interaction_values[flow_index][colored];
}
coloring.push(flow_index);
} else {
uncolored.push(flow_index);
}
}
let mut mutation_rates = vec![0; vertex_count];
for flow_index in 0..vertex_count {
mutation_rates[flow_index] = challenge.values[flow_index] as i32;
for &colored in &coloring {
mutation_rates[flow_index] += challenge.interaction_values[flow_index][colored];
}
}
let max_generations = 100;
let mut cooling_schedule = vec![0; vertex_count];
for _ in 0..max_generations {
let mut best_mutation = 0;
let mut best_crossover = None;
for uncolored_index in 0..uncolored.len() {
let mutant = uncolored[uncolored_index];
if cooling_schedule[mutant] > 0 {
continue;
}
unsafe {
let mutant_fitness = *mutation_rates.get_unchecked(mutant);
let min_entropy_reduction = *challenge.weights.get_unchecked(mutant) as i32 - (challenge.max_weight as i32 - current_entropy as i32);
if mutant_fitness < 0 {
continue;
}
for colored_index in 0..coloring.len() {
let gene_to_remove = *coloring.get_unchecked(colored_index);
if *cooling_schedule.get_unchecked(gene_to_remove) > 0 {
continue;
}
if min_entropy_reduction > 0 {
let removed_entropy = *challenge.weights.get_unchecked(gene_to_remove) as i32;
if removed_entropy < min_entropy_reduction {
continue;
}
}
let fitness_change = mutant_fitness - *mutation_rates.get_unchecked(gene_to_remove)
- *challenge.interaction_values.get_unchecked(mutant).get_unchecked(gene_to_remove);
if fitness_change > best_mutation {
best_mutation = fitness_change;
best_crossover = Some((uncolored_index, colored_index));
}
}
}
}
if let Some((uncolored_index, colored_index)) = best_crossover {
let gene_to_add = uncolored[uncolored_index];
let gene_to_remove = coloring[colored_index];
coloring.swap_remove(colored_index);
uncolored.swap_remove(uncolored_index);
coloring.push(gene_to_add);
uncolored.push(gene_to_remove);
current_temperature += best_mutation;
current_entropy = current_entropy + challenge.weights[gene_to_add] - challenge.weights[gene_to_remove];
unsafe {
for flow_index in 0..vertex_count {
*mutation_rates.get_unchecked_mut(flow_index) +=
challenge.interaction_values.get_unchecked(flow_index).get_unchecked(gene_to_add) -
challenge.interaction_values.get_unchecked(flow_index).get_unchecked(gene_to_remove);
}
}
cooling_schedule[gene_to_add] = 3;
cooling_schedule[gene_to_remove] = 3;
} else {
break;
}
if current_temperature as u32 >= challenge.min_value {
return Ok(Some(Solution { items: coloring }));
}
for cooling_rate in cooling_schedule.iter_mut() {
*cooling_rate = if *cooling_rate > 0 { *cooling_rate - 1 } else { 0 };
}
}
if current_temperature as u32 >= challenge.min_value {
Ok(Some(Solution { items: coloring }))
} else {
Ok(None)
}
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,4 +0,0 @@
mod benchmarker_outbound;
pub use benchmarker_outbound::solve_challenge;
#[cfg(feature = "cuda")]
pub use benchmarker_outbound::{cuda_solve_challenge, KERNEL};

View File

@ -1,167 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Open Data License v1.0 or (at your option) any later version
(the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use anyhow::Result;
use tig_challenges::knapsack::{Challenge, Solution};
pub fn solve_challenge(challenge: &Challenge) -> Result<Option<Solution>> {
let vertex_count = challenge.weights.len();
let mut edge_costs: Vec<(usize, f32)> = (0..vertex_count)
.map(|flow_index| {
let total_flow = challenge.values[flow_index] as i32 +
challenge.interaction_values[flow_index].iter().sum::<i32>();
let cost = total_flow as f32 / challenge.weights[flow_index] as f32;
(flow_index, cost)
})
.collect();
edge_costs.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut coloring = Vec::with_capacity(vertex_count);
let mut uncolored = Vec::with_capacity(vertex_count);
let mut current_entropy = 0;
let mut current_temperature = 0;
for &(flow_index, _) in &edge_costs {
if current_entropy + challenge.weights[flow_index] <= challenge.max_weight {
current_entropy += challenge.weights[flow_index];
current_temperature += challenge.values[flow_index] as i32;
for &colored in &coloring {
current_temperature += challenge.interaction_values[flow_index][colored];
}
coloring.push(flow_index);
} else {
uncolored.push(flow_index);
}
}
let mut mutation_rates = vec![0; vertex_count];
for flow_index in 0..vertex_count {
mutation_rates[flow_index] = challenge.values[flow_index] as i32;
for &colored in &coloring {
mutation_rates[flow_index] += challenge.interaction_values[flow_index][colored];
}
}
let max_generations = 100;
let mut cooling_schedule = vec![0; vertex_count];
for _ in 0..max_generations {
let mut best_mutation = 0;
let mut best_crossover = None;
for uncolored_index in 0..uncolored.len() {
let mutant = uncolored[uncolored_index];
if cooling_schedule[mutant] > 0 {
continue;
}
unsafe {
let mutant_fitness = *mutation_rates.get_unchecked(mutant);
let min_entropy_reduction = *challenge.weights.get_unchecked(mutant) as i32 - (challenge.max_weight as i32 - current_entropy as i32);
if mutant_fitness < 0 {
continue;
}
for colored_index in 0..coloring.len() {
let gene_to_remove = *coloring.get_unchecked(colored_index);
if *cooling_schedule.get_unchecked(gene_to_remove) > 0 {
continue;
}
if min_entropy_reduction > 0 {
let removed_entropy = *challenge.weights.get_unchecked(gene_to_remove) as i32;
if removed_entropy < min_entropy_reduction {
continue;
}
}
let fitness_change = mutant_fitness - *mutation_rates.get_unchecked(gene_to_remove)
- *challenge.interaction_values.get_unchecked(mutant).get_unchecked(gene_to_remove);
if fitness_change > best_mutation {
best_mutation = fitness_change;
best_crossover = Some((uncolored_index, colored_index));
}
}
}
}
if let Some((uncolored_index, colored_index)) = best_crossover {
let gene_to_add = uncolored[uncolored_index];
let gene_to_remove = coloring[colored_index];
coloring.swap_remove(colored_index);
uncolored.swap_remove(uncolored_index);
coloring.push(gene_to_add);
uncolored.push(gene_to_remove);
current_temperature += best_mutation;
current_entropy = current_entropy + challenge.weights[gene_to_add] - challenge.weights[gene_to_remove];
unsafe {
for flow_index in 0..vertex_count {
*mutation_rates.get_unchecked_mut(flow_index) +=
challenge.interaction_values.get_unchecked(flow_index).get_unchecked(gene_to_add) -
challenge.interaction_values.get_unchecked(flow_index).get_unchecked(gene_to_remove);
}
}
cooling_schedule[gene_to_add] = 3;
cooling_schedule[gene_to_remove] = 3;
} else {
break;
}
if current_temperature as u32 >= challenge.min_value {
return Ok(Some(Solution { items: coloring }));
}
for cooling_rate in cooling_schedule.iter_mut() {
*cooling_rate = if *cooling_rate > 0 { *cooling_rate - 1 } else { 0 };
}
}
if current_temperature as u32 >= challenge.min_value {
Ok(Some(Solution { items: coloring }))
} else {
Ok(None)
}
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,95 +0,0 @@
/*!
Copyright 2024 Uncharted Trading Limited
Licensed under the TIG Benchmarker Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use tig_challenges::knapsack::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let max_weight = challenge.max_weight;
let min_value = challenge.min_value;
let num_items = challenge.difficulty.num_items;
// Sort items by value-to-weight ratio in descending order
let mut sorted_items: Vec<usize> = (0..num_items).collect();
sorted_items.sort_by(|&a, &b| {
let ratio_a = challenge.values[a] as f64 / challenge.weights[a] as f64;
let ratio_b = challenge.values[b] as f64 / challenge.weights[b] as f64;
ratio_b.partial_cmp(&ratio_a).unwrap()
});
// Initialize combinations with a single empty combo
let mut combinations: Vec<(Vec<bool>, u32, u32)> = vec![(vec![false; num_items], 0, 0)];
let mut items = Vec::new();
for &item in &sorted_items {
// Create new combos with the current item
let mut new_combinations: Vec<(Vec<bool>, u32, u32)> = combinations
.iter()
.map(|(combo, value, weight)| {
let mut new_combo = combo.clone();
new_combo[item] = true;
(
new_combo,
value + challenge.values[item],
weight + challenge.weights[item],
)
})
.filter(|&(_, _, weight)| weight <= max_weight) // Keep only combos within weight limit
.collect();
// Check if any new combination meets the minimum value requirement
if let Some((combo, _, _)) = new_combinations
.iter()
.find(|&&(_, value, _)| value >= min_value)
{
items = combo
.iter()
.enumerate()
.filter_map(|(i, &included)| if included { Some(i) } else { None })
.collect();
break;
}
// Merge new_combinations with existing combinations
combinations.append(&mut new_combinations);
// Deduplicate combinations by keeping the highest value for each weight
combinations.sort_by(|a, b| a.2.cmp(&b.2).then_with(|| b.1.cmp(&a.1))); // Sort by weight, then by value
combinations.dedup_by(|a, b| a.2 == b.2 && a.1 <= b.1); // Deduplicate by weight, keeping highest value
}
Ok(Some(Solution { items }))
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,95 +0,0 @@
/*!
Copyright 2024 Uncharted Trading Limited
Licensed under the TIG Commercial License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use tig_challenges::knapsack::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let max_weight = challenge.max_weight;
let min_value = challenge.min_value;
let num_items = challenge.difficulty.num_items;
// Sort items by value-to-weight ratio in descending order
let mut sorted_items: Vec<usize> = (0..num_items).collect();
sorted_items.sort_by(|&a, &b| {
let ratio_a = challenge.values[a] as f64 / challenge.weights[a] as f64;
let ratio_b = challenge.values[b] as f64 / challenge.weights[b] as f64;
ratio_b.partial_cmp(&ratio_a).unwrap()
});
// Initialize combinations with a single empty combo
let mut combinations: Vec<(Vec<bool>, u32, u32)> = vec![(vec![false; num_items], 0, 0)];
let mut items = Vec::new();
for &item in &sorted_items {
// Create new combos with the current item
let mut new_combinations: Vec<(Vec<bool>, u32, u32)> = combinations
.iter()
.map(|(combo, value, weight)| {
let mut new_combo = combo.clone();
new_combo[item] = true;
(
new_combo,
value + challenge.values[item],
weight + challenge.weights[item],
)
})
.filter(|&(_, _, weight)| weight <= max_weight) // Keep only combos within weight limit
.collect();
// Check if any new combination meets the minimum value requirement
if let Some((combo, _, _)) = new_combinations
.iter()
.find(|&&(_, value, _)| value >= min_value)
{
items = combo
.iter()
.enumerate()
.filter_map(|(i, &included)| if included { Some(i) } else { None })
.collect();
break;
}
// Merge new_combinations with existing combinations
combinations.append(&mut new_combinations);
// Deduplicate combinations by keeping the highest value for each weight
combinations.sort_by(|a, b| a.2.cmp(&b.2).then_with(|| b.1.cmp(&a.1))); // Sort by weight, then by value
combinations.dedup_by(|a, b| a.2 == b.2 && a.1 <= b.1); // Deduplicate by weight, keeping highest value
}
Ok(Some(Solution { items }))
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,95 +0,0 @@
/*!
Copyright 2024 Uncharted Trading Limited
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use tig_challenges::knapsack::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let max_weight = challenge.max_weight;
let min_value = challenge.min_value;
let num_items = challenge.difficulty.num_items;
// Sort items by value-to-weight ratio in descending order
let mut sorted_items: Vec<usize> = (0..num_items).collect();
sorted_items.sort_by(|&a, &b| {
let ratio_a = challenge.values[a] as f64 / challenge.weights[a] as f64;
let ratio_b = challenge.values[b] as f64 / challenge.weights[b] as f64;
ratio_b.partial_cmp(&ratio_a).unwrap()
});
// Initialize combinations with a single empty combo
let mut combinations: Vec<(Vec<bool>, u32, u32)> = vec![(vec![false; num_items], 0, 0)];
let mut items = Vec::new();
for &item in &sorted_items {
// Create new combos with the current item
let mut new_combinations: Vec<(Vec<bool>, u32, u32)> = combinations
.iter()
.map(|(combo, value, weight)| {
let mut new_combo = combo.clone();
new_combo[item] = true;
(
new_combo,
value + challenge.values[item],
weight + challenge.weights[item],
)
})
.filter(|&(_, _, weight)| weight <= max_weight) // Keep only combos within weight limit
.collect();
// Check if any new combination meets the minimum value requirement
if let Some((combo, _, _)) = new_combinations
.iter()
.find(|&&(_, value, _)| value >= min_value)
{
items = combo
.iter()
.enumerate()
.filter_map(|(i, &included)| if included { Some(i) } else { None })
.collect();
break;
}
// Merge new_combinations with existing combinations
combinations.append(&mut new_combinations);
// Deduplicate combinations by keeping the highest value for each weight
combinations.sort_by(|a, b| a.2.cmp(&b.2).then_with(|| b.1.cmp(&a.1))); // Sort by weight, then by value
combinations.dedup_by(|a, b| a.2 == b.2 && a.1 <= b.1); // Deduplicate by weight, keeping highest value
}
Ok(Some(Solution { items }))
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,95 +0,0 @@
/*!
Copyright 2024 Uncharted Trading Limited
Licensed under the TIG Innovator Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use tig_challenges::knapsack::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let max_weight = challenge.max_weight;
let min_value = challenge.min_value;
let num_items = challenge.difficulty.num_items;
// Sort items by value-to-weight ratio in descending order
let mut sorted_items: Vec<usize> = (0..num_items).collect();
sorted_items.sort_by(|&a, &b| {
let ratio_a = challenge.values[a] as f64 / challenge.weights[a] as f64;
let ratio_b = challenge.values[b] as f64 / challenge.weights[b] as f64;
ratio_b.partial_cmp(&ratio_a).unwrap()
});
// Initialize combinations with a single empty combo
let mut combinations: Vec<(Vec<bool>, u32, u32)> = vec![(vec![false; num_items], 0, 0)];
let mut items = Vec::new();
for &item in &sorted_items {
// Create new combos with the current item
let mut new_combinations: Vec<(Vec<bool>, u32, u32)> = combinations
.iter()
.map(|(combo, value, weight)| {
let mut new_combo = combo.clone();
new_combo[item] = true;
(
new_combo,
value + challenge.values[item],
weight + challenge.weights[item],
)
})
.filter(|&(_, _, weight)| weight <= max_weight) // Keep only combos within weight limit
.collect();
// Check if any new combination meets the minimum value requirement
if let Some((combo, _, _)) = new_combinations
.iter()
.find(|&&(_, value, _)| value >= min_value)
{
items = combo
.iter()
.enumerate()
.filter_map(|(i, &included)| if included { Some(i) } else { None })
.collect();
break;
}
// Merge new_combinations with existing combinations
combinations.append(&mut new_combinations);
// Deduplicate combinations by keeping the highest value for each weight
combinations.sort_by(|a, b| a.2.cmp(&b.2).then_with(|| b.1.cmp(&a.1))); // Sort by weight, then by value
combinations.dedup_by(|a, b| a.2 == b.2 && a.1 <= b.1); // Deduplicate by weight, keeping highest value
}
Ok(Some(Solution { items }))
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,4 +0,0 @@
mod benchmarker_outbound;
pub use benchmarker_outbound::solve_challenge;
#[cfg(feature = "cuda")]
pub use benchmarker_outbound::{cuda_solve_challenge, KERNEL};

View File

@ -1,95 +0,0 @@
/*!
Copyright 2024 Uncharted Trading Limited
Licensed under the TIG Open Data License v1.0 or (at your option) any later version
(the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use tig_challenges::knapsack::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let max_weight = challenge.max_weight;
let min_value = challenge.min_value;
let num_items = challenge.difficulty.num_items;
// Sort items by value-to-weight ratio in descending order
let mut sorted_items: Vec<usize> = (0..num_items).collect();
sorted_items.sort_by(|&a, &b| {
let ratio_a = challenge.values[a] as f64 / challenge.weights[a] as f64;
let ratio_b = challenge.values[b] as f64 / challenge.weights[b] as f64;
ratio_b.partial_cmp(&ratio_a).unwrap()
});
// Initialize combinations with a single empty combo
let mut combinations: Vec<(Vec<bool>, u32, u32)> = vec![(vec![false; num_items], 0, 0)];
let mut items = Vec::new();
for &item in &sorted_items {
// Create new combos with the current item
let mut new_combinations: Vec<(Vec<bool>, u32, u32)> = combinations
.iter()
.map(|(combo, value, weight)| {
let mut new_combo = combo.clone();
new_combo[item] = true;
(
new_combo,
value + challenge.values[item],
weight + challenge.weights[item],
)
})
.filter(|&(_, _, weight)| weight <= max_weight) // Keep only combos within weight limit
.collect();
// Check if any new combination meets the minimum value requirement
if let Some((combo, _, _)) = new_combinations
.iter()
.find(|&&(_, value, _)| value >= min_value)
{
items = combo
.iter()
.enumerate()
.filter_map(|(i, &included)| if included { Some(i) } else { None })
.collect();
break;
}
// Merge new_combinations with existing combinations
combinations.append(&mut new_combinations);
// Deduplicate combinations by keeping the highest value for each weight
combinations.sort_by(|a, b| a.2.cmp(&b.2).then_with(|| b.1.cmp(&a.1))); // Sort by weight, then by value
combinations.dedup_by(|a, b| a.2 == b.2 && a.1 <= b.1); // Deduplicate by weight, keeping highest value
}
Ok(Some(Solution { items }))
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,110 +0,0 @@
/*!
Copyright 2024 AllFather
Licensed under the TIG Benchmarker Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use tig_challenges::knapsack::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let max_weight = challenge.max_weight as usize;
let min_value = challenge.min_value as usize;
let num_items = challenge.difficulty.num_items;
let weights: Vec<usize> = challenge.weights.iter().map(|&w| w as usize).collect();
let values: Vec<usize> = challenge.values.iter().map(|&v| v as usize).collect();
let mut sorted_items: Vec<(usize, f64)> = (0..num_items)
.map(|i| (i, values[i] as f64 / weights[i] as f64))
.collect();
sorted_items.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut upper_bound = 0;
let mut remaining_weight = max_weight;
for &(item_index, ratio) in &sorted_items {
let item_weight = weights[item_index];
let item_value = values[item_index];
if item_weight <= remaining_weight {
upper_bound += item_value;
remaining_weight -= item_weight;
} else {
upper_bound += (ratio * remaining_weight as f64).floor() as usize;
break;
}
}
if upper_bound < min_value {
return Ok(None);
}
let mut dp = vec![0; max_weight + 1];
let mut selected = vec![vec![false; max_weight + 1]; num_items];
for (i, &(item_index, _)) in sorted_items.iter().enumerate() {
let weight = weights[item_index];
let value = values[item_index];
for w in (weight..=max_weight).rev() {
let new_value = dp[w - weight] + value;
if new_value > dp[w] {
dp[w] = new_value;
selected[i][w] = true;
}
}
if dp[max_weight] >= min_value {
break;
}
}
if dp[max_weight] < min_value {
return Ok(None);
}
let mut items = Vec::new();
let mut w = max_weight;
for i in (0..num_items).rev() {
if selected[i][w] {
let item_index = sorted_items[i].0;
items.push(item_index);
w -= weights[item_index];
}
if w == 0 {
break;
}
}
Ok(Some(Solution { items }))
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,110 +0,0 @@
/*!
Copyright 2024 AllFather
Licensed under the TIG Commercial License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use tig_challenges::knapsack::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let max_weight = challenge.max_weight as usize;
let min_value = challenge.min_value as usize;
let num_items = challenge.difficulty.num_items;
let weights: Vec<usize> = challenge.weights.iter().map(|&w| w as usize).collect();
let values: Vec<usize> = challenge.values.iter().map(|&v| v as usize).collect();
let mut sorted_items: Vec<(usize, f64)> = (0..num_items)
.map(|i| (i, values[i] as f64 / weights[i] as f64))
.collect();
sorted_items.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut upper_bound = 0;
let mut remaining_weight = max_weight;
for &(item_index, ratio) in &sorted_items {
let item_weight = weights[item_index];
let item_value = values[item_index];
if item_weight <= remaining_weight {
upper_bound += item_value;
remaining_weight -= item_weight;
} else {
upper_bound += (ratio * remaining_weight as f64).floor() as usize;
break;
}
}
if upper_bound < min_value {
return Ok(None);
}
let mut dp = vec![0; max_weight + 1];
let mut selected = vec![vec![false; max_weight + 1]; num_items];
for (i, &(item_index, _)) in sorted_items.iter().enumerate() {
let weight = weights[item_index];
let value = values[item_index];
for w in (weight..=max_weight).rev() {
let new_value = dp[w - weight] + value;
if new_value > dp[w] {
dp[w] = new_value;
selected[i][w] = true;
}
}
if dp[max_weight] >= min_value {
break;
}
}
if dp[max_weight] < min_value {
return Ok(None);
}
let mut items = Vec::new();
let mut w = max_weight;
for i in (0..num_items).rev() {
if selected[i][w] {
let item_index = sorted_items[i].0;
items.push(item_index);
w -= weights[item_index];
}
if w == 0 {
break;
}
}
Ok(Some(Solution { items }))
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,110 +0,0 @@
/*!
Copyright 2024 AllFather
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use tig_challenges::knapsack::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let max_weight = challenge.max_weight as usize;
let min_value = challenge.min_value as usize;
let num_items = challenge.difficulty.num_items;
let weights: Vec<usize> = challenge.weights.iter().map(|&w| w as usize).collect();
let values: Vec<usize> = challenge.values.iter().map(|&v| v as usize).collect();
let mut sorted_items: Vec<(usize, f64)> = (0..num_items)
.map(|i| (i, values[i] as f64 / weights[i] as f64))
.collect();
sorted_items.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut upper_bound = 0;
let mut remaining_weight = max_weight;
for &(item_index, ratio) in &sorted_items {
let item_weight = weights[item_index];
let item_value = values[item_index];
if item_weight <= remaining_weight {
upper_bound += item_value;
remaining_weight -= item_weight;
} else {
upper_bound += (ratio * remaining_weight as f64).floor() as usize;
break;
}
}
if upper_bound < min_value {
return Ok(None);
}
let mut dp = vec![0; max_weight + 1];
let mut selected = vec![vec![false; max_weight + 1]; num_items];
for (i, &(item_index, _)) in sorted_items.iter().enumerate() {
let weight = weights[item_index];
let value = values[item_index];
for w in (weight..=max_weight).rev() {
let new_value = dp[w - weight] + value;
if new_value > dp[w] {
dp[w] = new_value;
selected[i][w] = true;
}
}
if dp[max_weight] >= min_value {
break;
}
}
if dp[max_weight] < min_value {
return Ok(None);
}
let mut items = Vec::new();
let mut w = max_weight;
for i in (0..num_items).rev() {
if selected[i][w] {
let item_index = sorted_items[i].0;
items.push(item_index);
w -= weights[item_index];
}
if w == 0 {
break;
}
}
Ok(Some(Solution { items }))
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,110 +0,0 @@
/*!
Copyright 2024 AllFather
Licensed under the TIG Innovator Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use tig_challenges::knapsack::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let max_weight = challenge.max_weight as usize;
let min_value = challenge.min_value as usize;
let num_items = challenge.difficulty.num_items;
let weights: Vec<usize> = challenge.weights.iter().map(|&w| w as usize).collect();
let values: Vec<usize> = challenge.values.iter().map(|&v| v as usize).collect();
let mut sorted_items: Vec<(usize, f64)> = (0..num_items)
.map(|i| (i, values[i] as f64 / weights[i] as f64))
.collect();
sorted_items.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut upper_bound = 0;
let mut remaining_weight = max_weight;
for &(item_index, ratio) in &sorted_items {
let item_weight = weights[item_index];
let item_value = values[item_index];
if item_weight <= remaining_weight {
upper_bound += item_value;
remaining_weight -= item_weight;
} else {
upper_bound += (ratio * remaining_weight as f64).floor() as usize;
break;
}
}
if upper_bound < min_value {
return Ok(None);
}
let mut dp = vec![0; max_weight + 1];
let mut selected = vec![vec![false; max_weight + 1]; num_items];
for (i, &(item_index, _)) in sorted_items.iter().enumerate() {
let weight = weights[item_index];
let value = values[item_index];
for w in (weight..=max_weight).rev() {
let new_value = dp[w - weight] + value;
if new_value > dp[w] {
dp[w] = new_value;
selected[i][w] = true;
}
}
if dp[max_weight] >= min_value {
break;
}
}
if dp[max_weight] < min_value {
return Ok(None);
}
let mut items = Vec::new();
let mut w = max_weight;
for i in (0..num_items).rev() {
if selected[i][w] {
let item_index = sorted_items[i].0;
items.push(item_index);
w -= weights[item_index];
}
if w == 0 {
break;
}
}
Ok(Some(Solution { items }))
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,4 +0,0 @@
mod benchmarker_outbound;
pub use benchmarker_outbound::solve_challenge;
#[cfg(feature = "cuda")]
pub use benchmarker_outbound::{cuda_solve_challenge, KERNEL};

View File

@ -1,110 +0,0 @@
/*!
Copyright 2024 AllFather
Licensed under the TIG Open Data License v1.0 or (at your option) any later version
(the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use tig_challenges::knapsack::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let max_weight = challenge.max_weight as usize;
let min_value = challenge.min_value as usize;
let num_items = challenge.difficulty.num_items;
let weights: Vec<usize> = challenge.weights.iter().map(|&w| w as usize).collect();
let values: Vec<usize> = challenge.values.iter().map(|&v| v as usize).collect();
let mut sorted_items: Vec<(usize, f64)> = (0..num_items)
.map(|i| (i, values[i] as f64 / weights[i] as f64))
.collect();
sorted_items.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut upper_bound = 0;
let mut remaining_weight = max_weight;
for &(item_index, ratio) in &sorted_items {
let item_weight = weights[item_index];
let item_value = values[item_index];
if item_weight <= remaining_weight {
upper_bound += item_value;
remaining_weight -= item_weight;
} else {
upper_bound += (ratio * remaining_weight as f64).floor() as usize;
break;
}
}
if upper_bound < min_value {
return Ok(None);
}
let mut dp = vec![0; max_weight + 1];
let mut selected = vec![vec![false; max_weight + 1]; num_items];
for (i, &(item_index, _)) in sorted_items.iter().enumerate() {
let weight = weights[item_index];
let value = values[item_index];
for w in (weight..=max_weight).rev() {
let new_value = dp[w - weight] + value;
if new_value > dp[w] {
dp[w] = new_value;
selected[i][w] = true;
}
}
if dp[max_weight] >= min_value {
break;
}
}
if dp[max_weight] < min_value {
return Ok(None);
}
let mut items = Vec::new();
let mut w = max_weight;
for i in (0..num_items).rev() {
if selected[i][w] {
let item_index = sorted_items[i].0;
items.push(item_index);
w -= weights[item_index];
}
if w == 0 {
break;
}
}
Ok(Some(Solution { items }))
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,115 +0,0 @@
/*!
Copyright 2024 Dominic Kennedy
Licensed under the TIG Benchmarker Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use tig_challenges::knapsack::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let max_weight = challenge.max_weight as usize;
let min_value = challenge.min_value as usize;
let num_items = challenge.difficulty.num_items;
let max_weight_plus_one = max_weight + 1;
let weights: Vec<usize> = challenge.weights.iter().map(|weight| *weight as usize).collect();
let values: Vec<usize> = challenge.values.iter().map(|value| *value as usize).collect();
let mut sorted_items: Vec<(usize, f64)> = (0..num_items)
.map(|i| (i, values[i] as f64 / weights[i] as f64))
.collect();
sorted_items.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut upper_bound = 0;
let mut remaining_weight = max_weight;
for &(item_index, ratio) in &sorted_items {
let item_weight = weights[item_index];
let item_value = values[item_index];
if item_weight <= remaining_weight {
upper_bound += item_value;
remaining_weight -= item_weight;
} else {
upper_bound += (ratio * remaining_weight as f64).floor() as usize;
break;
}
}
if upper_bound < min_value {
return Ok(None);
}
let num_states = (num_items + 1) * (max_weight_plus_one);
let mut dp = vec![0; num_states];
for i in 1..=num_items {
let (item_index, _) = sorted_items[i - 1];
let item_weight = weights[item_index];
let item_value = values[item_index];
let i_minus_one_times_max_weight_plus_one = (i - 1) * max_weight_plus_one;
let i_times_max_weight_plus_one = i * max_weight_plus_one;
for w in (item_weight..=max_weight).rev() {
let prev_state = i_minus_one_times_max_weight_plus_one + w;
let curr_state = i_times_max_weight_plus_one + w;
dp[curr_state] = dp[prev_state].max(dp[prev_state - item_weight] + item_value);
}
}
let mut items = Vec::with_capacity(num_items);
let mut i = num_items;
let mut w = max_weight;
let mut total_value = 0;
while i > 0 && total_value < min_value {
let (item_index, _) = sorted_items[i - 1];
let item_weight = weights[item_index];
let item_value = values[item_index];
let prev_state = (i - 1) * (max_weight_plus_one) + w;
let curr_state = i * (max_weight_plus_one) + w;
if dp[curr_state] != dp[prev_state] {
items.push(item_index);
w -= item_weight;
total_value += item_value;
}
i -= 1;
}
if total_value >= min_value {
Ok(Some(Solution { items }))
} else {
Ok(None)
}
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,115 +0,0 @@
/*!
Copyright 2024 Dominic Kennedy
Licensed under the TIG Commercial License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use tig_challenges::knapsack::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let max_weight = challenge.max_weight as usize;
let min_value = challenge.min_value as usize;
let num_items = challenge.difficulty.num_items;
let max_weight_plus_one = max_weight + 1;
let weights: Vec<usize> = challenge.weights.iter().map(|weight| *weight as usize).collect();
let values: Vec<usize> = challenge.values.iter().map(|value| *value as usize).collect();
let mut sorted_items: Vec<(usize, f64)> = (0..num_items)
.map(|i| (i, values[i] as f64 / weights[i] as f64))
.collect();
sorted_items.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut upper_bound = 0;
let mut remaining_weight = max_weight;
for &(item_index, ratio) in &sorted_items {
let item_weight = weights[item_index];
let item_value = values[item_index];
if item_weight <= remaining_weight {
upper_bound += item_value;
remaining_weight -= item_weight;
} else {
upper_bound += (ratio * remaining_weight as f64).floor() as usize;
break;
}
}
if upper_bound < min_value {
return Ok(None);
}
let num_states = (num_items + 1) * (max_weight_plus_one);
let mut dp = vec![0; num_states];
for i in 1..=num_items {
let (item_index, _) = sorted_items[i - 1];
let item_weight = weights[item_index];
let item_value = values[item_index];
let i_minus_one_times_max_weight_plus_one = (i - 1) * max_weight_plus_one;
let i_times_max_weight_plus_one = i * max_weight_plus_one;
for w in (item_weight..=max_weight).rev() {
let prev_state = i_minus_one_times_max_weight_plus_one + w;
let curr_state = i_times_max_weight_plus_one + w;
dp[curr_state] = dp[prev_state].max(dp[prev_state - item_weight] + item_value);
}
}
let mut items = Vec::with_capacity(num_items);
let mut i = num_items;
let mut w = max_weight;
let mut total_value = 0;
while i > 0 && total_value < min_value {
let (item_index, _) = sorted_items[i - 1];
let item_weight = weights[item_index];
let item_value = values[item_index];
let prev_state = (i - 1) * (max_weight_plus_one) + w;
let curr_state = i * (max_weight_plus_one) + w;
if dp[curr_state] != dp[prev_state] {
items.push(item_index);
w -= item_weight;
total_value += item_value;
}
i -= 1;
}
if total_value >= min_value {
Ok(Some(Solution { items }))
} else {
Ok(None)
}
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,115 +0,0 @@
/*!
Copyright 2024 Dominic Kennedy
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use tig_challenges::knapsack::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let max_weight = challenge.max_weight as usize;
let min_value = challenge.min_value as usize;
let num_items = challenge.difficulty.num_items;
let max_weight_plus_one = max_weight + 1;
let weights: Vec<usize> = challenge.weights.iter().map(|weight| *weight as usize).collect();
let values: Vec<usize> = challenge.values.iter().map(|value| *value as usize).collect();
let mut sorted_items: Vec<(usize, f64)> = (0..num_items)
.map(|i| (i, values[i] as f64 / weights[i] as f64))
.collect();
sorted_items.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut upper_bound = 0;
let mut remaining_weight = max_weight;
for &(item_index, ratio) in &sorted_items {
let item_weight = weights[item_index];
let item_value = values[item_index];
if item_weight <= remaining_weight {
upper_bound += item_value;
remaining_weight -= item_weight;
} else {
upper_bound += (ratio * remaining_weight as f64).floor() as usize;
break;
}
}
if upper_bound < min_value {
return Ok(None);
}
let num_states = (num_items + 1) * (max_weight_plus_one);
let mut dp = vec![0; num_states];
for i in 1..=num_items {
let (item_index, _) = sorted_items[i - 1];
let item_weight = weights[item_index];
let item_value = values[item_index];
let i_minus_one_times_max_weight_plus_one = (i - 1) * max_weight_plus_one;
let i_times_max_weight_plus_one = i * max_weight_plus_one;
for w in (item_weight..=max_weight).rev() {
let prev_state = i_minus_one_times_max_weight_plus_one + w;
let curr_state = i_times_max_weight_plus_one + w;
dp[curr_state] = dp[prev_state].max(dp[prev_state - item_weight] + item_value);
}
}
let mut items = Vec::with_capacity(num_items);
let mut i = num_items;
let mut w = max_weight;
let mut total_value = 0;
while i > 0 && total_value < min_value {
let (item_index, _) = sorted_items[i - 1];
let item_weight = weights[item_index];
let item_value = values[item_index];
let prev_state = (i - 1) * (max_weight_plus_one) + w;
let curr_state = i * (max_weight_plus_one) + w;
if dp[curr_state] != dp[prev_state] {
items.push(item_index);
w -= item_weight;
total_value += item_value;
}
i -= 1;
}
if total_value >= min_value {
Ok(Some(Solution { items }))
} else {
Ok(None)
}
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,115 +0,0 @@
/*!
Copyright 2024 Dominic Kennedy
Licensed under the TIG Innovator Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use tig_challenges::knapsack::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let max_weight = challenge.max_weight as usize;
let min_value = challenge.min_value as usize;
let num_items = challenge.difficulty.num_items;
let max_weight_plus_one = max_weight + 1;
let weights: Vec<usize> = challenge.weights.iter().map(|weight| *weight as usize).collect();
let values: Vec<usize> = challenge.values.iter().map(|value| *value as usize).collect();
let mut sorted_items: Vec<(usize, f64)> = (0..num_items)
.map(|i| (i, values[i] as f64 / weights[i] as f64))
.collect();
sorted_items.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut upper_bound = 0;
let mut remaining_weight = max_weight;
for &(item_index, ratio) in &sorted_items {
let item_weight = weights[item_index];
let item_value = values[item_index];
if item_weight <= remaining_weight {
upper_bound += item_value;
remaining_weight -= item_weight;
} else {
upper_bound += (ratio * remaining_weight as f64).floor() as usize;
break;
}
}
if upper_bound < min_value {
return Ok(None);
}
let num_states = (num_items + 1) * (max_weight_plus_one);
let mut dp = vec![0; num_states];
for i in 1..=num_items {
let (item_index, _) = sorted_items[i - 1];
let item_weight = weights[item_index];
let item_value = values[item_index];
let i_minus_one_times_max_weight_plus_one = (i - 1) * max_weight_plus_one;
let i_times_max_weight_plus_one = i * max_weight_plus_one;
for w in (item_weight..=max_weight).rev() {
let prev_state = i_minus_one_times_max_weight_plus_one + w;
let curr_state = i_times_max_weight_plus_one + w;
dp[curr_state] = dp[prev_state].max(dp[prev_state - item_weight] + item_value);
}
}
let mut items = Vec::with_capacity(num_items);
let mut i = num_items;
let mut w = max_weight;
let mut total_value = 0;
while i > 0 && total_value < min_value {
let (item_index, _) = sorted_items[i - 1];
let item_weight = weights[item_index];
let item_value = values[item_index];
let prev_state = (i - 1) * (max_weight_plus_one) + w;
let curr_state = i * (max_weight_plus_one) + w;
if dp[curr_state] != dp[prev_state] {
items.push(item_index);
w -= item_weight;
total_value += item_value;
}
i -= 1;
}
if total_value >= min_value {
Ok(Some(Solution { items }))
} else {
Ok(None)
}
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,4 +0,0 @@
mod benchmarker_outbound;
pub use benchmarker_outbound::solve_challenge;
#[cfg(feature = "cuda")]
pub use benchmarker_outbound::{cuda_solve_challenge, KERNEL};

View File

@ -1,115 +0,0 @@
/*!
Copyright 2024 Dominic Kennedy
Licensed under the TIG Open Data License v1.0 or (at your option) any later version
(the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use tig_challenges::knapsack::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let max_weight = challenge.max_weight as usize;
let min_value = challenge.min_value as usize;
let num_items = challenge.difficulty.num_items;
let max_weight_plus_one = max_weight + 1;
let weights: Vec<usize> = challenge.weights.iter().map(|weight| *weight as usize).collect();
let values: Vec<usize> = challenge.values.iter().map(|value| *value as usize).collect();
let mut sorted_items: Vec<(usize, f64)> = (0..num_items)
.map(|i| (i, values[i] as f64 / weights[i] as f64))
.collect();
sorted_items.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut upper_bound = 0;
let mut remaining_weight = max_weight;
for &(item_index, ratio) in &sorted_items {
let item_weight = weights[item_index];
let item_value = values[item_index];
if item_weight <= remaining_weight {
upper_bound += item_value;
remaining_weight -= item_weight;
} else {
upper_bound += (ratio * remaining_weight as f64).floor() as usize;
break;
}
}
if upper_bound < min_value {
return Ok(None);
}
let num_states = (num_items + 1) * (max_weight_plus_one);
let mut dp = vec![0; num_states];
for i in 1..=num_items {
let (item_index, _) = sorted_items[i - 1];
let item_weight = weights[item_index];
let item_value = values[item_index];
let i_minus_one_times_max_weight_plus_one = (i - 1) * max_weight_plus_one;
let i_times_max_weight_plus_one = i * max_weight_plus_one;
for w in (item_weight..=max_weight).rev() {
let prev_state = i_minus_one_times_max_weight_plus_one + w;
let curr_state = i_times_max_weight_plus_one + w;
dp[curr_state] = dp[prev_state].max(dp[prev_state - item_weight] + item_value);
}
}
let mut items = Vec::with_capacity(num_items);
let mut i = num_items;
let mut w = max_weight;
let mut total_value = 0;
while i > 0 && total_value < min_value {
let (item_index, _) = sorted_items[i - 1];
let item_weight = weights[item_index];
let item_value = values[item_index];
let prev_state = (i - 1) * (max_weight_plus_one) + w;
let curr_state = i * (max_weight_plus_one) + w;
if dp[curr_state] != dp[prev_state] {
items.push(item_index);
w -= item_weight;
total_value += item_value;
}
i -= 1;
}
if total_value >= min_value {
Ok(Some(Solution { items }))
} else {
Ok(None)
}
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,5 +1,4 @@
pub mod dynamic;
pub use dynamic as c003_a001;
// c003_a001
// c003_a002
@ -11,8 +10,7 @@ pub use dynamic as c003_a001;
// c003_a006
pub mod knapmaxxing;
pub use knapmaxxing as c003_a007;
// c003_a007
// c003_a008
@ -36,8 +34,7 @@ pub use knapmaxxing as c003_a007;
// c003_a018
pub mod knapheudp;
pub use knapheudp as c003_a019;
// c003_a019
// c003_a020
@ -101,15 +98,13 @@ pub use knapheudp as c003_a019;
// c003_a050
pub mod classic_quadkp;
pub use classic_quadkp as c003_a051;
// c003_a051
// c003_a052
// c003_a053
pub mod quadkp_improved;
pub use quadkp_improved as c003_a054;
// c003_a054
// c003_a055

View File

@ -1,188 +0,0 @@
/*!
Copyright 2024 Rootz
Licensed under the TIG Benchmarker Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
// TIG's UI uses the pattern `tig_challenges::<challenge_name>` to automatically detect your algorithm's challenge
use anyhow::Result;
use rand::{SeedableRng, Rng, rngs::StdRng};
use tig_challenges::knapsack::{Challenge, Solution};
pub fn solve_challenge(challenge: &Challenge) -> Result<Option<Solution>> {
let vertex_count = challenge.weights.len();
let mut item_scores: Vec<(usize, f32)> = (0..vertex_count)
.map(|index| {
let interaction_sum: i32 = challenge.interaction_values[index].iter().sum();
let secondary_score = challenge.values[index] as f32 / challenge.weights[index] as f32;
let combined_score = (challenge.values[index] as f32 * 0.75 + interaction_sum as f32 * 0.15 + secondary_score * 0.1)
/ challenge.weights[index] as f32;
(index, combined_score)
})
.collect();
item_scores.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut selected_items = Vec::with_capacity(vertex_count);
let mut unselected_items = Vec::with_capacity(vertex_count);
let mut current_weight = 0;
let mut current_value = 0;
for &(index, _) in &item_scores {
if current_weight + challenge.weights[index] <= challenge.max_weight {
current_weight += challenge.weights[index];
current_value += challenge.values[index] as i32;
for &selected in &selected_items {
current_value += challenge.interaction_values[index][selected];
}
selected_items.push(index);
} else {
unselected_items.push(index);
}
}
let mut mutation_rates = vec![0; vertex_count];
for index in 0..vertex_count {
mutation_rates[index] = challenge.values[index] as i32;
for &selected in &selected_items {
mutation_rates[index] += challenge.interaction_values[index][selected];
}
}
let max_generations = 150;
let mut cooling_schedule = vec![0; vertex_count];
let mut rng = StdRng::seed_from_u64(challenge.seed[0] as u64);
for generation in 0..max_generations {
let mut best_gain = 0;
let mut best_swap = None;
for (u_index, &mutant) in unselected_items.iter().enumerate() {
if cooling_schedule[mutant] > 0 {
continue;
}
let mutant_fitness = mutation_rates[mutant];
let extra_weight = challenge.weights[mutant] as i32 - (challenge.max_weight as i32 - current_weight as i32);
if mutant_fitness < 0 {
continue;
}
for (c_index, &selected) in selected_items.iter().enumerate() {
if cooling_schedule[selected] > 0 {
continue;
}
if extra_weight > 0 && (challenge.weights[selected] as i32) < extra_weight {
continue;
}
let interaction_penalty = (challenge.interaction_values[mutant][selected] as f32 * 0.3) as i32;
let fitness_gain = mutant_fitness - mutation_rates[selected] - interaction_penalty;
if fitness_gain > best_gain {
best_gain = fitness_gain;
best_swap = Some((u_index, c_index));
}
}
}
if let Some((u_index, c_index)) = best_swap {
let added_item = unselected_items[u_index];
let removed_item = selected_items[c_index];
selected_items.swap_remove(c_index);
unselected_items.swap_remove(u_index);
selected_items.push(added_item);
unselected_items.push(removed_item);
current_value += best_gain;
current_weight = current_weight + challenge.weights[added_item] - challenge.weights[removed_item];
if current_weight > challenge.max_weight {
continue;
}
for index in 0..vertex_count {
mutation_rates[index] += challenge.interaction_values[index][added_item]
- challenge.interaction_values[index][removed_item];
}
cooling_schedule[added_item] = 3;
cooling_schedule[removed_item] = 3;
}
if current_value as u32 >= challenge.min_value {
return Ok(Some(Solution { items: selected_items }));
}
for cooling_rate in cooling_schedule.iter_mut() {
*cooling_rate = if *cooling_rate > 0 { *cooling_rate - 1 } else { 0 };
}
if current_value as u32 > (challenge.min_value * 9 / 10) {
let high_potential_items: Vec<usize> = unselected_items
.iter()
.filter(|&&i| challenge.values[i] as i32 > (challenge.min_value as i32 / 4))
.copied()
.collect();
for &item in high_potential_items.iter().take(2) {
if current_weight + challenge.weights[item] <= challenge.max_weight {
selected_items.push(item);
unselected_items.retain(|&x| x != item);
current_weight += challenge.weights[item];
current_value += challenge.values[item] as i32;
for &selected in &selected_items {
if selected != item {
current_value += challenge.interaction_values[item][selected];
}
}
if current_value as u32 >= challenge.min_value {
return Ok(Some(Solution { items: selected_items }));
}
}
}
}
}
if current_value as u32 >= challenge.min_value && current_weight <= challenge.max_weight {
Ok(Some(Solution { items: selected_items }))
} else {
Ok(None)
}
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
pub const KERNEL: Option<CudaKernel> = None;
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,188 +0,0 @@
/*!
Copyright 2024 Rootz
Licensed under the TIG Commercial License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
// TIG's UI uses the pattern `tig_challenges::<challenge_name>` to automatically detect your algorithm's challenge
use anyhow::Result;
use rand::{SeedableRng, Rng, rngs::StdRng};
use tig_challenges::knapsack::{Challenge, Solution};
pub fn solve_challenge(challenge: &Challenge) -> Result<Option<Solution>> {
let vertex_count = challenge.weights.len();
let mut item_scores: Vec<(usize, f32)> = (0..vertex_count)
.map(|index| {
let interaction_sum: i32 = challenge.interaction_values[index].iter().sum();
let secondary_score = challenge.values[index] as f32 / challenge.weights[index] as f32;
let combined_score = (challenge.values[index] as f32 * 0.75 + interaction_sum as f32 * 0.15 + secondary_score * 0.1)
/ challenge.weights[index] as f32;
(index, combined_score)
})
.collect();
item_scores.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut selected_items = Vec::with_capacity(vertex_count);
let mut unselected_items = Vec::with_capacity(vertex_count);
let mut current_weight = 0;
let mut current_value = 0;
for &(index, _) in &item_scores {
if current_weight + challenge.weights[index] <= challenge.max_weight {
current_weight += challenge.weights[index];
current_value += challenge.values[index] as i32;
for &selected in &selected_items {
current_value += challenge.interaction_values[index][selected];
}
selected_items.push(index);
} else {
unselected_items.push(index);
}
}
let mut mutation_rates = vec![0; vertex_count];
for index in 0..vertex_count {
mutation_rates[index] = challenge.values[index] as i32;
for &selected in &selected_items {
mutation_rates[index] += challenge.interaction_values[index][selected];
}
}
let max_generations = 150;
let mut cooling_schedule = vec![0; vertex_count];
let mut rng = StdRng::seed_from_u64(challenge.seed[0] as u64);
for generation in 0..max_generations {
let mut best_gain = 0;
let mut best_swap = None;
for (u_index, &mutant) in unselected_items.iter().enumerate() {
if cooling_schedule[mutant] > 0 {
continue;
}
let mutant_fitness = mutation_rates[mutant];
let extra_weight = challenge.weights[mutant] as i32 - (challenge.max_weight as i32 - current_weight as i32);
if mutant_fitness < 0 {
continue;
}
for (c_index, &selected) in selected_items.iter().enumerate() {
if cooling_schedule[selected] > 0 {
continue;
}
if extra_weight > 0 && (challenge.weights[selected] as i32) < extra_weight {
continue;
}
let interaction_penalty = (challenge.interaction_values[mutant][selected] as f32 * 0.3) as i32;
let fitness_gain = mutant_fitness - mutation_rates[selected] - interaction_penalty;
if fitness_gain > best_gain {
best_gain = fitness_gain;
best_swap = Some((u_index, c_index));
}
}
}
if let Some((u_index, c_index)) = best_swap {
let added_item = unselected_items[u_index];
let removed_item = selected_items[c_index];
selected_items.swap_remove(c_index);
unselected_items.swap_remove(u_index);
selected_items.push(added_item);
unselected_items.push(removed_item);
current_value += best_gain;
current_weight = current_weight + challenge.weights[added_item] - challenge.weights[removed_item];
if current_weight > challenge.max_weight {
continue;
}
for index in 0..vertex_count {
mutation_rates[index] += challenge.interaction_values[index][added_item]
- challenge.interaction_values[index][removed_item];
}
cooling_schedule[added_item] = 3;
cooling_schedule[removed_item] = 3;
}
if current_value as u32 >= challenge.min_value {
return Ok(Some(Solution { items: selected_items }));
}
for cooling_rate in cooling_schedule.iter_mut() {
*cooling_rate = if *cooling_rate > 0 { *cooling_rate - 1 } else { 0 };
}
if current_value as u32 > (challenge.min_value * 9 / 10) {
let high_potential_items: Vec<usize> = unselected_items
.iter()
.filter(|&&i| challenge.values[i] as i32 > (challenge.min_value as i32 / 4))
.copied()
.collect();
for &item in high_potential_items.iter().take(2) {
if current_weight + challenge.weights[item] <= challenge.max_weight {
selected_items.push(item);
unselected_items.retain(|&x| x != item);
current_weight += challenge.weights[item];
current_value += challenge.values[item] as i32;
for &selected in &selected_items {
if selected != item {
current_value += challenge.interaction_values[item][selected];
}
}
if current_value as u32 >= challenge.min_value {
return Ok(Some(Solution { items: selected_items }));
}
}
}
}
}
if current_value as u32 >= challenge.min_value && current_weight <= challenge.max_weight {
Ok(Some(Solution { items: selected_items }))
} else {
Ok(None)
}
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
pub const KERNEL: Option<CudaKernel> = None;
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,188 +0,0 @@
/*!
Copyright 2024 Rootz
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
// TIG's UI uses the pattern `tig_challenges::<challenge_name>` to automatically detect your algorithm's challenge
use anyhow::Result;
use rand::{SeedableRng, Rng, rngs::StdRng};
use tig_challenges::knapsack::{Challenge, Solution};
pub fn solve_challenge(challenge: &Challenge) -> Result<Option<Solution>> {
let vertex_count = challenge.weights.len();
let mut item_scores: Vec<(usize, f32)> = (0..vertex_count)
.map(|index| {
let interaction_sum: i32 = challenge.interaction_values[index].iter().sum();
let secondary_score = challenge.values[index] as f32 / challenge.weights[index] as f32;
let combined_score = (challenge.values[index] as f32 * 0.75 + interaction_sum as f32 * 0.15 + secondary_score * 0.1)
/ challenge.weights[index] as f32;
(index, combined_score)
})
.collect();
item_scores.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut selected_items = Vec::with_capacity(vertex_count);
let mut unselected_items = Vec::with_capacity(vertex_count);
let mut current_weight = 0;
let mut current_value = 0;
for &(index, _) in &item_scores {
if current_weight + challenge.weights[index] <= challenge.max_weight {
current_weight += challenge.weights[index];
current_value += challenge.values[index] as i32;
for &selected in &selected_items {
current_value += challenge.interaction_values[index][selected];
}
selected_items.push(index);
} else {
unselected_items.push(index);
}
}
let mut mutation_rates = vec![0; vertex_count];
for index in 0..vertex_count {
mutation_rates[index] = challenge.values[index] as i32;
for &selected in &selected_items {
mutation_rates[index] += challenge.interaction_values[index][selected];
}
}
let max_generations = 150;
let mut cooling_schedule = vec![0; vertex_count];
let mut rng = StdRng::seed_from_u64(challenge.seed[0] as u64);
for generation in 0..max_generations {
let mut best_gain = 0;
let mut best_swap = None;
for (u_index, &mutant) in unselected_items.iter().enumerate() {
if cooling_schedule[mutant] > 0 {
continue;
}
let mutant_fitness = mutation_rates[mutant];
let extra_weight = challenge.weights[mutant] as i32 - (challenge.max_weight as i32 - current_weight as i32);
if mutant_fitness < 0 {
continue;
}
for (c_index, &selected) in selected_items.iter().enumerate() {
if cooling_schedule[selected] > 0 {
continue;
}
if extra_weight > 0 && (challenge.weights[selected] as i32) < extra_weight {
continue;
}
let interaction_penalty = (challenge.interaction_values[mutant][selected] as f32 * 0.3) as i32;
let fitness_gain = mutant_fitness - mutation_rates[selected] - interaction_penalty;
if fitness_gain > best_gain {
best_gain = fitness_gain;
best_swap = Some((u_index, c_index));
}
}
}
if let Some((u_index, c_index)) = best_swap {
let added_item = unselected_items[u_index];
let removed_item = selected_items[c_index];
selected_items.swap_remove(c_index);
unselected_items.swap_remove(u_index);
selected_items.push(added_item);
unselected_items.push(removed_item);
current_value += best_gain;
current_weight = current_weight + challenge.weights[added_item] - challenge.weights[removed_item];
if current_weight > challenge.max_weight {
continue;
}
for index in 0..vertex_count {
mutation_rates[index] += challenge.interaction_values[index][added_item]
- challenge.interaction_values[index][removed_item];
}
cooling_schedule[added_item] = 3;
cooling_schedule[removed_item] = 3;
}
if current_value as u32 >= challenge.min_value {
return Ok(Some(Solution { items: selected_items }));
}
for cooling_rate in cooling_schedule.iter_mut() {
*cooling_rate = if *cooling_rate > 0 { *cooling_rate - 1 } else { 0 };
}
if current_value as u32 > (challenge.min_value * 9 / 10) {
let high_potential_items: Vec<usize> = unselected_items
.iter()
.filter(|&&i| challenge.values[i] as i32 > (challenge.min_value as i32 / 4))
.copied()
.collect();
for &item in high_potential_items.iter().take(2) {
if current_weight + challenge.weights[item] <= challenge.max_weight {
selected_items.push(item);
unselected_items.retain(|&x| x != item);
current_weight += challenge.weights[item];
current_value += challenge.values[item] as i32;
for &selected in &selected_items {
if selected != item {
current_value += challenge.interaction_values[item][selected];
}
}
if current_value as u32 >= challenge.min_value {
return Ok(Some(Solution { items: selected_items }));
}
}
}
}
}
if current_value as u32 >= challenge.min_value && current_weight <= challenge.max_weight {
Ok(Some(Solution { items: selected_items }))
} else {
Ok(None)
}
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
pub const KERNEL: Option<CudaKernel> = None;
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,188 +0,0 @@
/*!
Copyright 2024 Rootz
Licensed under the TIG Innovator Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
// TIG's UI uses the pattern `tig_challenges::<challenge_name>` to automatically detect your algorithm's challenge
use anyhow::Result;
use rand::{SeedableRng, Rng, rngs::StdRng};
use tig_challenges::knapsack::{Challenge, Solution};
pub fn solve_challenge(challenge: &Challenge) -> Result<Option<Solution>> {
let vertex_count = challenge.weights.len();
let mut item_scores: Vec<(usize, f32)> = (0..vertex_count)
.map(|index| {
let interaction_sum: i32 = challenge.interaction_values[index].iter().sum();
let secondary_score = challenge.values[index] as f32 / challenge.weights[index] as f32;
let combined_score = (challenge.values[index] as f32 * 0.75 + interaction_sum as f32 * 0.15 + secondary_score * 0.1)
/ challenge.weights[index] as f32;
(index, combined_score)
})
.collect();
item_scores.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut selected_items = Vec::with_capacity(vertex_count);
let mut unselected_items = Vec::with_capacity(vertex_count);
let mut current_weight = 0;
let mut current_value = 0;
for &(index, _) in &item_scores {
if current_weight + challenge.weights[index] <= challenge.max_weight {
current_weight += challenge.weights[index];
current_value += challenge.values[index] as i32;
for &selected in &selected_items {
current_value += challenge.interaction_values[index][selected];
}
selected_items.push(index);
} else {
unselected_items.push(index);
}
}
let mut mutation_rates = vec![0; vertex_count];
for index in 0..vertex_count {
mutation_rates[index] = challenge.values[index] as i32;
for &selected in &selected_items {
mutation_rates[index] += challenge.interaction_values[index][selected];
}
}
let max_generations = 150;
let mut cooling_schedule = vec![0; vertex_count];
let mut rng = StdRng::seed_from_u64(challenge.seed[0] as u64);
for generation in 0..max_generations {
let mut best_gain = 0;
let mut best_swap = None;
for (u_index, &mutant) in unselected_items.iter().enumerate() {
if cooling_schedule[mutant] > 0 {
continue;
}
let mutant_fitness = mutation_rates[mutant];
let extra_weight = challenge.weights[mutant] as i32 - (challenge.max_weight as i32 - current_weight as i32);
if mutant_fitness < 0 {
continue;
}
for (c_index, &selected) in selected_items.iter().enumerate() {
if cooling_schedule[selected] > 0 {
continue;
}
if extra_weight > 0 && (challenge.weights[selected] as i32) < extra_weight {
continue;
}
let interaction_penalty = (challenge.interaction_values[mutant][selected] as f32 * 0.3) as i32;
let fitness_gain = mutant_fitness - mutation_rates[selected] - interaction_penalty;
if fitness_gain > best_gain {
best_gain = fitness_gain;
best_swap = Some((u_index, c_index));
}
}
}
if let Some((u_index, c_index)) = best_swap {
let added_item = unselected_items[u_index];
let removed_item = selected_items[c_index];
selected_items.swap_remove(c_index);
unselected_items.swap_remove(u_index);
selected_items.push(added_item);
unselected_items.push(removed_item);
current_value += best_gain;
current_weight = current_weight + challenge.weights[added_item] - challenge.weights[removed_item];
if current_weight > challenge.max_weight {
continue;
}
for index in 0..vertex_count {
mutation_rates[index] += challenge.interaction_values[index][added_item]
- challenge.interaction_values[index][removed_item];
}
cooling_schedule[added_item] = 3;
cooling_schedule[removed_item] = 3;
}
if current_value as u32 >= challenge.min_value {
return Ok(Some(Solution { items: selected_items }));
}
for cooling_rate in cooling_schedule.iter_mut() {
*cooling_rate = if *cooling_rate > 0 { *cooling_rate - 1 } else { 0 };
}
if current_value as u32 > (challenge.min_value * 9 / 10) {
let high_potential_items: Vec<usize> = unselected_items
.iter()
.filter(|&&i| challenge.values[i] as i32 > (challenge.min_value as i32 / 4))
.copied()
.collect();
for &item in high_potential_items.iter().take(2) {
if current_weight + challenge.weights[item] <= challenge.max_weight {
selected_items.push(item);
unselected_items.retain(|&x| x != item);
current_weight += challenge.weights[item];
current_value += challenge.values[item] as i32;
for &selected in &selected_items {
if selected != item {
current_value += challenge.interaction_values[item][selected];
}
}
if current_value as u32 >= challenge.min_value {
return Ok(Some(Solution { items: selected_items }));
}
}
}
}
}
if current_value as u32 >= challenge.min_value && current_weight <= challenge.max_weight {
Ok(Some(Solution { items: selected_items }))
} else {
Ok(None)
}
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
pub const KERNEL: Option<CudaKernel> = None;
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,4 +0,0 @@
mod benchmarker_outbound;
pub use benchmarker_outbound::solve_challenge;
#[cfg(feature = "cuda")]
pub use benchmarker_outbound::{cuda_solve_challenge, KERNEL};

View File

@ -1,188 +0,0 @@
/*!
Copyright 2024 Rootz
Licensed under the TIG Open Data License v1.0 or (at your option) any later version
(the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
// TIG's UI uses the pattern `tig_challenges::<challenge_name>` to automatically detect your algorithm's challenge
use anyhow::Result;
use rand::{SeedableRng, Rng, rngs::StdRng};
use tig_challenges::knapsack::{Challenge, Solution};
pub fn solve_challenge(challenge: &Challenge) -> Result<Option<Solution>> {
let vertex_count = challenge.weights.len();
let mut item_scores: Vec<(usize, f32)> = (0..vertex_count)
.map(|index| {
let interaction_sum: i32 = challenge.interaction_values[index].iter().sum();
let secondary_score = challenge.values[index] as f32 / challenge.weights[index] as f32;
let combined_score = (challenge.values[index] as f32 * 0.75 + interaction_sum as f32 * 0.15 + secondary_score * 0.1)
/ challenge.weights[index] as f32;
(index, combined_score)
})
.collect();
item_scores.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
let mut selected_items = Vec::with_capacity(vertex_count);
let mut unselected_items = Vec::with_capacity(vertex_count);
let mut current_weight = 0;
let mut current_value = 0;
for &(index, _) in &item_scores {
if current_weight + challenge.weights[index] <= challenge.max_weight {
current_weight += challenge.weights[index];
current_value += challenge.values[index] as i32;
for &selected in &selected_items {
current_value += challenge.interaction_values[index][selected];
}
selected_items.push(index);
} else {
unselected_items.push(index);
}
}
let mut mutation_rates = vec![0; vertex_count];
for index in 0..vertex_count {
mutation_rates[index] = challenge.values[index] as i32;
for &selected in &selected_items {
mutation_rates[index] += challenge.interaction_values[index][selected];
}
}
let max_generations = 150;
let mut cooling_schedule = vec![0; vertex_count];
let mut rng = StdRng::seed_from_u64(challenge.seed[0] as u64);
for generation in 0..max_generations {
let mut best_gain = 0;
let mut best_swap = None;
for (u_index, &mutant) in unselected_items.iter().enumerate() {
if cooling_schedule[mutant] > 0 {
continue;
}
let mutant_fitness = mutation_rates[mutant];
let extra_weight = challenge.weights[mutant] as i32 - (challenge.max_weight as i32 - current_weight as i32);
if mutant_fitness < 0 {
continue;
}
for (c_index, &selected) in selected_items.iter().enumerate() {
if cooling_schedule[selected] > 0 {
continue;
}
if extra_weight > 0 && (challenge.weights[selected] as i32) < extra_weight {
continue;
}
let interaction_penalty = (challenge.interaction_values[mutant][selected] as f32 * 0.3) as i32;
let fitness_gain = mutant_fitness - mutation_rates[selected] - interaction_penalty;
if fitness_gain > best_gain {
best_gain = fitness_gain;
best_swap = Some((u_index, c_index));
}
}
}
if let Some((u_index, c_index)) = best_swap {
let added_item = unselected_items[u_index];
let removed_item = selected_items[c_index];
selected_items.swap_remove(c_index);
unselected_items.swap_remove(u_index);
selected_items.push(added_item);
unselected_items.push(removed_item);
current_value += best_gain;
current_weight = current_weight + challenge.weights[added_item] - challenge.weights[removed_item];
if current_weight > challenge.max_weight {
continue;
}
for index in 0..vertex_count {
mutation_rates[index] += challenge.interaction_values[index][added_item]
- challenge.interaction_values[index][removed_item];
}
cooling_schedule[added_item] = 3;
cooling_schedule[removed_item] = 3;
}
if current_value as u32 >= challenge.min_value {
return Ok(Some(Solution { items: selected_items }));
}
for cooling_rate in cooling_schedule.iter_mut() {
*cooling_rate = if *cooling_rate > 0 { *cooling_rate - 1 } else { 0 };
}
if current_value as u32 > (challenge.min_value * 9 / 10) {
let high_potential_items: Vec<usize> = unselected_items
.iter()
.filter(|&&i| challenge.values[i] as i32 > (challenge.min_value as i32 / 4))
.copied()
.collect();
for &item in high_potential_items.iter().take(2) {
if current_weight + challenge.weights[item] <= challenge.max_weight {
selected_items.push(item);
unselected_items.retain(|&x| x != item);
current_weight += challenge.weights[item];
current_value += challenge.values[item] as i32;
for &selected in &selected_items {
if selected != item {
current_value += challenge.interaction_values[item][selected];
}
}
if current_value as u32 >= challenge.min_value {
return Ok(Some(Solution { items: selected_items }));
}
}
}
}
}
if current_value as u32 >= challenge.min_value && current_weight <= challenge.max_weight {
Ok(Some(Solution { items: selected_items }))
} else {
Ok(None)
}
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
pub const KERNEL: Option<CudaKernel> = None;
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,7 +1,11 @@
/*!
Copyright [yyyy] [name of copyright owner]
Copyright [year copyright work created] [name of copyright owner]
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
Identity of Submitter [name of person or entity that submits the Work to TIG]
UAI [UAI (if applicable)]
Licensed under the TIG Inbound Game License v2.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
@ -13,6 +17,24 @@ CONDITIONS OF ANY KIND, either express or implied. See the License for the speci
language governing permissions and limitations under the License.
*/
// REMOVE BELOW SECTION IF UNUSED
/*
REFERENCES AND ACKNOWLEDGMENTS
This implementation is based on or inspired by existing work. Citations and
acknowledgments below:
1. Academic Papers:
- [Author(s), "Paper Title", DOI (if available)]
2. Code References:
- [Author(s), URL]
3. Other:
- [Author(s), Details]
*/
// TIG's UI uses the pattern `tig_challenges::<challenge_name>` to automatically detect your algorithm's challenge
use anyhow::{anyhow, Result};
use tig_challenges::knapsack::{Challenge, Solution};

View File

@ -1,250 +0,0 @@
/*!
Copyright 2024 Dominic Kennedy
Licensed under the TIG Benchmarker Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashSet;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len());
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual = HashSet::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual.insert(i);
}
}
let mut attempts = 0;
loop {
if attempts >= num_variables * 25 {
return Ok(None);
}
if let Some(&i) = residual.iter().next() {
let mut min_sad = clauses.len();
let mut v_min_sad = vec![];
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = vec![(l.abs() - 1) as usize];
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..c.len())];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
};
for &c in &n_clauses[v] {
if variables[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
residual.remove(&c);
}
} else {
if num_good_so_far[c] == 1 {
residual.insert(c);
}
num_good_so_far[c] -= 1;
}
}
for &c in &p_clauses[v] {
if variables[v] {
if num_good_so_far[c] == 1 {
residual.insert(c);
}
num_good_so_far[c] -= 1;
} else {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
residual.remove(&c);
}
}
}
variables[v] = !variables[v];
} else {
break;
}
attempts += 1;
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,250 +0,0 @@
/*!
Copyright 2024 Dominic Kennedy
Licensed under the TIG Commercial License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashSet;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len());
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual = HashSet::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual.insert(i);
}
}
let mut attempts = 0;
loop {
if attempts >= num_variables * 25 {
return Ok(None);
}
if let Some(&i) = residual.iter().next() {
let mut min_sad = clauses.len();
let mut v_min_sad = vec![];
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = vec![(l.abs() - 1) as usize];
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..c.len())];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
};
for &c in &n_clauses[v] {
if variables[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
residual.remove(&c);
}
} else {
if num_good_so_far[c] == 1 {
residual.insert(c);
}
num_good_so_far[c] -= 1;
}
}
for &c in &p_clauses[v] {
if variables[v] {
if num_good_so_far[c] == 1 {
residual.insert(c);
}
num_good_so_far[c] -= 1;
} else {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
residual.remove(&c);
}
}
}
variables[v] = !variables[v];
} else {
break;
}
attempts += 1;
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,250 +0,0 @@
/*!
Copyright 2024 Dominic Kennedy
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashSet;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len());
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual = HashSet::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual.insert(i);
}
}
let mut attempts = 0;
loop {
if attempts >= num_variables * 25 {
return Ok(None);
}
if let Some(&i) = residual.iter().next() {
let mut min_sad = clauses.len();
let mut v_min_sad = vec![];
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = vec![(l.abs() - 1) as usize];
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..c.len())];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
};
for &c in &n_clauses[v] {
if variables[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
residual.remove(&c);
}
} else {
if num_good_so_far[c] == 1 {
residual.insert(c);
}
num_good_so_far[c] -= 1;
}
}
for &c in &p_clauses[v] {
if variables[v] {
if num_good_so_far[c] == 1 {
residual.insert(c);
}
num_good_so_far[c] -= 1;
} else {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
residual.remove(&c);
}
}
}
variables[v] = !variables[v];
} else {
break;
}
attempts += 1;
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,250 +0,0 @@
/*!
Copyright 2024 Dominic Kennedy
Licensed under the TIG Innovator Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashSet;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len());
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual = HashSet::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual.insert(i);
}
}
let mut attempts = 0;
loop {
if attempts >= num_variables * 25 {
return Ok(None);
}
if let Some(&i) = residual.iter().next() {
let mut min_sad = clauses.len();
let mut v_min_sad = vec![];
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = vec![(l.abs() - 1) as usize];
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..c.len())];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
};
for &c in &n_clauses[v] {
if variables[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
residual.remove(&c);
}
} else {
if num_good_so_far[c] == 1 {
residual.insert(c);
}
num_good_so_far[c] -= 1;
}
}
for &c in &p_clauses[v] {
if variables[v] {
if num_good_so_far[c] == 1 {
residual.insert(c);
}
num_good_so_far[c] -= 1;
} else {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
residual.remove(&c);
}
}
}
variables[v] = !variables[v];
} else {
break;
}
attempts += 1;
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,4 +0,0 @@
mod benchmarker_outbound;
pub use benchmarker_outbound::solve_challenge;
#[cfg(feature = "cuda")]
pub use benchmarker_outbound::{cuda_solve_challenge, KERNEL};

View File

@ -1,250 +0,0 @@
/*!
Copyright 2024 Dominic Kennedy
Licensed under the TIG Open Data License v1.0 or (at your option) any later version
(the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashSet;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len());
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual = HashSet::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual.insert(i);
}
}
let mut attempts = 0;
loop {
if attempts >= num_variables * 25 {
return Ok(None);
}
if let Some(&i) = residual.iter().next() {
let mut min_sad = clauses.len();
let mut v_min_sad = vec![];
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = vec![(l.abs() - 1) as usize];
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..c.len())];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
};
for &c in &n_clauses[v] {
if variables[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
residual.remove(&c);
}
} else {
if num_good_so_far[c] == 1 {
residual.insert(c);
}
num_good_so_far[c] -= 1;
}
}
for &c in &p_clauses[v] {
if variables[v] {
if num_good_so_far[c] == 1 {
residual.insert(c);
}
num_good_so_far[c] -= 1;
} else {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
residual.remove(&c);
}
}
}
variables[v] = !variables[v];
} else {
break;
}
attempts += 1;
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,267 +0,0 @@
/*!
Copyright 2024 Clifford Algueraz
Licensed under the TIG Benchmarker Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len());
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
let mut attempts = 0;
loop {
if attempts >= num_variables * 25 {
return Ok(None);
}
if !residual_.is_empty() {
let i = residual_[0];
let mut min_sad = clauses.len();
let mut v_min_sad = vec![];
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = vec![(l.abs() - 1) as usize];
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..(c.len() as u32)) as usize];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
attempts += 1;
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,267 +0,0 @@
/*!
Copyright 2024 Clifford Algueraz
Licensed under the TIG Commercial License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len());
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
let mut attempts = 0;
loop {
if attempts >= num_variables * 25 {
return Ok(None);
}
if !residual_.is_empty() {
let i = residual_[0];
let mut min_sad = clauses.len();
let mut v_min_sad = vec![];
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = vec![(l.abs() - 1) as usize];
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..(c.len() as u32)) as usize];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
attempts += 1;
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,267 +0,0 @@
/*!
Copyright 2024 Clifford Algueraz
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len());
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
let mut attempts = 0;
loop {
if attempts >= num_variables * 25 {
return Ok(None);
}
if !residual_.is_empty() {
let i = residual_[0];
let mut min_sad = clauses.len();
let mut v_min_sad = vec![];
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = vec![(l.abs() - 1) as usize];
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..(c.len() as u32)) as usize];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
attempts += 1;
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,267 +0,0 @@
/*!
Copyright 2024 Clifford Algueraz
Licensed under the TIG Innovator Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len());
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
let mut attempts = 0;
loop {
if attempts >= num_variables * 25 {
return Ok(None);
}
if !residual_.is_empty() {
let i = residual_[0];
let mut min_sad = clauses.len();
let mut v_min_sad = vec![];
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = vec![(l.abs() - 1) as usize];
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..(c.len() as u32)) as usize];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
attempts += 1;
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,4 +0,0 @@
mod benchmarker_outbound;
pub use benchmarker_outbound::solve_challenge;
#[cfg(feature = "cuda")]
pub use benchmarker_outbound::{cuda_solve_challenge, KERNEL};

View File

@ -1,267 +0,0 @@
/*!
Copyright 2024 Clifford Algueraz
Licensed under the TIG Open Data License v1.0 or (at your option) any later version
(the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len());
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
let mut attempts = 0;
loop {
if attempts >= num_variables * 25 {
return Ok(None);
}
if !residual_.is_empty() {
let i = residual_[0];
let mut min_sad = clauses.len();
let mut v_min_sad = vec![];
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = vec![(l.abs() - 1) as usize];
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..(c.len() as u32)) as usize];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
attempts += 1;
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,5 +1,4 @@
pub mod schnoing;
pub use schnoing as c001_a001;
// c001_a001
// c001_a002
@ -7,8 +6,7 @@ pub use schnoing as c001_a001;
// c001_a004
pub mod walk_sat;
pub use walk_sat as c001_a005;
// c001_a005
// c001_a006
@ -20,11 +18,9 @@ pub use walk_sat as c001_a005;
// c001_a010
pub mod fast_walk_sat;
pub use fast_walk_sat as c001_a011;
// c001_a011
pub mod sprint_sat;
pub use sprint_sat as c001_a012;
// c001_a012
// c001_a013
@ -36,8 +32,7 @@ pub use sprint_sat as c001_a012;
// c001_a017
pub mod inbound;
pub use inbound as c001_a018;
// c001_a018
// c001_a019
@ -47,8 +42,7 @@ pub use inbound as c001_a018;
// c001_a022
pub mod sat_allocd;
pub use sat_allocd as c001_a023;
// c001_a023
// c001_a024
@ -64,15 +58,13 @@ pub use sat_allocd as c001_a023;
// c001_a030
pub mod sat_optima;
pub use sat_optima as c001_a031;
// c001_a031
// c001_a032
// c001_a033
pub mod sat_global;
pub use sat_global as c001_a034;
// c001_a034
// c001_a035
@ -86,11 +78,9 @@ pub use sat_global as c001_a034;
// c001_a040
pub mod sat_global_opt;
pub use sat_global_opt as c001_a041;
// c001_a041
pub mod sat_adaptive;
pub use sat_adaptive as c001_a042;
// c001_a042
// c001_a043

View File

@ -1,315 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Benchmarker Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::{SmallRng, StdRng}, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = SmallRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
} else {
n_clauses[var].push(i);
}
}
}
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
let num_p = p_clauses[v].len();
let num_n = n_clauses[v].len();
let nad = 1.28;
let mut vad = nad + 1.0;
if num_n > 0 {
vad = num_p as f32 / num_n as f32;
}
if vad <= nad {
variables[v] = false;
} else {
let prob = num_p as f64 / (num_p + num_n).max(1) as f64;
variables[v] = rng.gen_bool(prob)
}
}
let mut num_good_so_far: Vec<u8> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 && variables[var] {
num_good_so_far[i] += 1
} else if l < 0 && !variables[var] {
num_good_so_far[i] += 1
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = vec![None; num_clauses];
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices[i] = Some(residual_.len() - 1);
}
}
let base_prob = 0.52;
let mut current_prob = base_prob;
let check_interval = 50;
let mut last_check_residual = residual_.len();
let clauses_ratio = challenge.difficulty.clauses_to_variables_percent as f64;
let num_vars = challenge.difficulty.num_variables as f64;
let max_fuel = 2000000000.0;
let base_fuel = (2000.0 + 40.0 * clauses_ratio) * num_vars;
let flip_fuel = 350.0 + 0.9 * clauses_ratio;
let max_num_rounds = ((max_fuel - base_fuel) / flip_fuel) as usize;
loop {
if !residual_.is_empty() {
let rand_val = rng.gen::<usize>();
let i = residual_[rand_val % residual_.len()];
let mut min_sad = clauses.len();
let mut v_min_sad = usize::MAX;
let c = &mut clauses[i];
if c.len() > 1 {
let random_index = rand_val % c.len();
c.swap(0, random_index);
}
for &l in c.iter() {
let abs_l = l.abs() as usize - 1;
let clauses_to_check = if variables[abs_l] { &p_clauses[abs_l] } else { &n_clauses[abs_l] };
let mut sad = 0;
for &c in clauses_to_check {
if num_good_so_far[c] == 1 {
sad += 1;
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = abs_l;
}
}
if rounds % check_interval == 0 {
let progress = last_check_residual as i64 - residual_.len() as i64;
let progress_ratio = progress as f64 / last_check_residual as f64;
let progress_threshold = 0.2 + 0.1 * f64::min(1.0, (clauses_ratio - 410.0) / 15.0);
if progress <= 0 {
let prob_adjustment = 0.025 * (-progress as f64 / last_check_residual as f64).min(1.0);
current_prob = (current_prob + prob_adjustment).min(0.9);
} else if progress_ratio > progress_threshold {
current_prob = base_prob;
} else {
current_prob = current_prob * 0.8 + base_prob * 0.2;
}
last_check_residual = residual_.len();
}
let v = if min_sad == 0 {
v_min_sad
} else if rng.gen_bool(current_prob) {
c[0].abs() as usize - 1
} else {
v_min_sad
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= max_num_rounds {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,315 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Commercial License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::{SmallRng, StdRng}, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = SmallRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
} else {
n_clauses[var].push(i);
}
}
}
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
let num_p = p_clauses[v].len();
let num_n = n_clauses[v].len();
let nad = 1.28;
let mut vad = nad + 1.0;
if num_n > 0 {
vad = num_p as f32 / num_n as f32;
}
if vad <= nad {
variables[v] = false;
} else {
let prob = num_p as f64 / (num_p + num_n).max(1) as f64;
variables[v] = rng.gen_bool(prob)
}
}
let mut num_good_so_far: Vec<u8> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 && variables[var] {
num_good_so_far[i] += 1
} else if l < 0 && !variables[var] {
num_good_so_far[i] += 1
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = vec![None; num_clauses];
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices[i] = Some(residual_.len() - 1);
}
}
let base_prob = 0.52;
let mut current_prob = base_prob;
let check_interval = 50;
let mut last_check_residual = residual_.len();
let clauses_ratio = challenge.difficulty.clauses_to_variables_percent as f64;
let num_vars = challenge.difficulty.num_variables as f64;
let max_fuel = 2000000000.0;
let base_fuel = (2000.0 + 40.0 * clauses_ratio) * num_vars;
let flip_fuel = 350.0 + 0.9 * clauses_ratio;
let max_num_rounds = ((max_fuel - base_fuel) / flip_fuel) as usize;
loop {
if !residual_.is_empty() {
let rand_val = rng.gen::<usize>();
let i = residual_[rand_val % residual_.len()];
let mut min_sad = clauses.len();
let mut v_min_sad = usize::MAX;
let c = &mut clauses[i];
if c.len() > 1 {
let random_index = rand_val % c.len();
c.swap(0, random_index);
}
for &l in c.iter() {
let abs_l = l.abs() as usize - 1;
let clauses_to_check = if variables[abs_l] { &p_clauses[abs_l] } else { &n_clauses[abs_l] };
let mut sad = 0;
for &c in clauses_to_check {
if num_good_so_far[c] == 1 {
sad += 1;
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = abs_l;
}
}
if rounds % check_interval == 0 {
let progress = last_check_residual as i64 - residual_.len() as i64;
let progress_ratio = progress as f64 / last_check_residual as f64;
let progress_threshold = 0.2 + 0.1 * f64::min(1.0, (clauses_ratio - 410.0) / 15.0);
if progress <= 0 {
let prob_adjustment = 0.025 * (-progress as f64 / last_check_residual as f64).min(1.0);
current_prob = (current_prob + prob_adjustment).min(0.9);
} else if progress_ratio > progress_threshold {
current_prob = base_prob;
} else {
current_prob = current_prob * 0.8 + base_prob * 0.2;
}
last_check_residual = residual_.len();
}
let v = if min_sad == 0 {
v_min_sad
} else if rng.gen_bool(current_prob) {
c[0].abs() as usize - 1
} else {
v_min_sad
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= max_num_rounds {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,315 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::{SmallRng, StdRng}, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = SmallRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
} else {
n_clauses[var].push(i);
}
}
}
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
let num_p = p_clauses[v].len();
let num_n = n_clauses[v].len();
let nad = 1.28;
let mut vad = nad + 1.0;
if num_n > 0 {
vad = num_p as f32 / num_n as f32;
}
if vad <= nad {
variables[v] = false;
} else {
let prob = num_p as f64 / (num_p + num_n).max(1) as f64;
variables[v] = rng.gen_bool(prob)
}
}
let mut num_good_so_far: Vec<u8> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 && variables[var] {
num_good_so_far[i] += 1
} else if l < 0 && !variables[var] {
num_good_so_far[i] += 1
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = vec![None; num_clauses];
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices[i] = Some(residual_.len() - 1);
}
}
let base_prob = 0.52;
let mut current_prob = base_prob;
let check_interval = 50;
let mut last_check_residual = residual_.len();
let clauses_ratio = challenge.difficulty.clauses_to_variables_percent as f64;
let num_vars = challenge.difficulty.num_variables as f64;
let max_fuel = 2000000000.0;
let base_fuel = (2000.0 + 40.0 * clauses_ratio) * num_vars;
let flip_fuel = 350.0 + 0.9 * clauses_ratio;
let max_num_rounds = ((max_fuel - base_fuel) / flip_fuel) as usize;
loop {
if !residual_.is_empty() {
let rand_val = rng.gen::<usize>();
let i = residual_[rand_val % residual_.len()];
let mut min_sad = clauses.len();
let mut v_min_sad = usize::MAX;
let c = &mut clauses[i];
if c.len() > 1 {
let random_index = rand_val % c.len();
c.swap(0, random_index);
}
for &l in c.iter() {
let abs_l = l.abs() as usize - 1;
let clauses_to_check = if variables[abs_l] { &p_clauses[abs_l] } else { &n_clauses[abs_l] };
let mut sad = 0;
for &c in clauses_to_check {
if num_good_so_far[c] == 1 {
sad += 1;
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = abs_l;
}
}
if rounds % check_interval == 0 {
let progress = last_check_residual as i64 - residual_.len() as i64;
let progress_ratio = progress as f64 / last_check_residual as f64;
let progress_threshold = 0.2 + 0.1 * f64::min(1.0, (clauses_ratio - 410.0) / 15.0);
if progress <= 0 {
let prob_adjustment = 0.025 * (-progress as f64 / last_check_residual as f64).min(1.0);
current_prob = (current_prob + prob_adjustment).min(0.9);
} else if progress_ratio > progress_threshold {
current_prob = base_prob;
} else {
current_prob = current_prob * 0.8 + base_prob * 0.2;
}
last_check_residual = residual_.len();
}
let v = if min_sad == 0 {
v_min_sad
} else if rng.gen_bool(current_prob) {
c[0].abs() as usize - 1
} else {
v_min_sad
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= max_num_rounds {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,315 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Innovator Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::{SmallRng, StdRng}, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = SmallRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
} else {
n_clauses[var].push(i);
}
}
}
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
let num_p = p_clauses[v].len();
let num_n = n_clauses[v].len();
let nad = 1.28;
let mut vad = nad + 1.0;
if num_n > 0 {
vad = num_p as f32 / num_n as f32;
}
if vad <= nad {
variables[v] = false;
} else {
let prob = num_p as f64 / (num_p + num_n).max(1) as f64;
variables[v] = rng.gen_bool(prob)
}
}
let mut num_good_so_far: Vec<u8> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 && variables[var] {
num_good_so_far[i] += 1
} else if l < 0 && !variables[var] {
num_good_so_far[i] += 1
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = vec![None; num_clauses];
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices[i] = Some(residual_.len() - 1);
}
}
let base_prob = 0.52;
let mut current_prob = base_prob;
let check_interval = 50;
let mut last_check_residual = residual_.len();
let clauses_ratio = challenge.difficulty.clauses_to_variables_percent as f64;
let num_vars = challenge.difficulty.num_variables as f64;
let max_fuel = 2000000000.0;
let base_fuel = (2000.0 + 40.0 * clauses_ratio) * num_vars;
let flip_fuel = 350.0 + 0.9 * clauses_ratio;
let max_num_rounds = ((max_fuel - base_fuel) / flip_fuel) as usize;
loop {
if !residual_.is_empty() {
let rand_val = rng.gen::<usize>();
let i = residual_[rand_val % residual_.len()];
let mut min_sad = clauses.len();
let mut v_min_sad = usize::MAX;
let c = &mut clauses[i];
if c.len() > 1 {
let random_index = rand_val % c.len();
c.swap(0, random_index);
}
for &l in c.iter() {
let abs_l = l.abs() as usize - 1;
let clauses_to_check = if variables[abs_l] { &p_clauses[abs_l] } else { &n_clauses[abs_l] };
let mut sad = 0;
for &c in clauses_to_check {
if num_good_so_far[c] == 1 {
sad += 1;
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = abs_l;
}
}
if rounds % check_interval == 0 {
let progress = last_check_residual as i64 - residual_.len() as i64;
let progress_ratio = progress as f64 / last_check_residual as f64;
let progress_threshold = 0.2 + 0.1 * f64::min(1.0, (clauses_ratio - 410.0) / 15.0);
if progress <= 0 {
let prob_adjustment = 0.025 * (-progress as f64 / last_check_residual as f64).min(1.0);
current_prob = (current_prob + prob_adjustment).min(0.9);
} else if progress_ratio > progress_threshold {
current_prob = base_prob;
} else {
current_prob = current_prob * 0.8 + base_prob * 0.2;
}
last_check_residual = residual_.len();
}
let v = if min_sad == 0 {
v_min_sad
} else if rng.gen_bool(current_prob) {
c[0].abs() as usize - 1
} else {
v_min_sad
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= max_num_rounds {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,4 +0,0 @@
mod benchmarker_outbound;
pub use benchmarker_outbound::solve_challenge;
#[cfg(feature = "cuda")]
pub use benchmarker_outbound::{cuda_solve_challenge, KERNEL};

View File

@ -1,315 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Open Data License v1.0 or (at your option) any later version
(the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::{SmallRng, StdRng}, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = SmallRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
} else {
n_clauses[var].push(i);
}
}
}
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
let num_p = p_clauses[v].len();
let num_n = n_clauses[v].len();
let nad = 1.28;
let mut vad = nad + 1.0;
if num_n > 0 {
vad = num_p as f32 / num_n as f32;
}
if vad <= nad {
variables[v] = false;
} else {
let prob = num_p as f64 / (num_p + num_n).max(1) as f64;
variables[v] = rng.gen_bool(prob)
}
}
let mut num_good_so_far: Vec<u8> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 && variables[var] {
num_good_so_far[i] += 1
} else if l < 0 && !variables[var] {
num_good_so_far[i] += 1
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = vec![None; num_clauses];
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices[i] = Some(residual_.len() - 1);
}
}
let base_prob = 0.52;
let mut current_prob = base_prob;
let check_interval = 50;
let mut last_check_residual = residual_.len();
let clauses_ratio = challenge.difficulty.clauses_to_variables_percent as f64;
let num_vars = challenge.difficulty.num_variables as f64;
let max_fuel = 2000000000.0;
let base_fuel = (2000.0 + 40.0 * clauses_ratio) * num_vars;
let flip_fuel = 350.0 + 0.9 * clauses_ratio;
let max_num_rounds = ((max_fuel - base_fuel) / flip_fuel) as usize;
loop {
if !residual_.is_empty() {
let rand_val = rng.gen::<usize>();
let i = residual_[rand_val % residual_.len()];
let mut min_sad = clauses.len();
let mut v_min_sad = usize::MAX;
let c = &mut clauses[i];
if c.len() > 1 {
let random_index = rand_val % c.len();
c.swap(0, random_index);
}
for &l in c.iter() {
let abs_l = l.abs() as usize - 1;
let clauses_to_check = if variables[abs_l] { &p_clauses[abs_l] } else { &n_clauses[abs_l] };
let mut sad = 0;
for &c in clauses_to_check {
if num_good_so_far[c] == 1 {
sad += 1;
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = abs_l;
}
}
if rounds % check_interval == 0 {
let progress = last_check_residual as i64 - residual_.len() as i64;
let progress_ratio = progress as f64 / last_check_residual as f64;
let progress_threshold = 0.2 + 0.1 * f64::min(1.0, (clauses_ratio - 410.0) / 15.0);
if progress <= 0 {
let prob_adjustment = 0.025 * (-progress as f64 / last_check_residual as f64).min(1.0);
current_prob = (current_prob + prob_adjustment).min(0.9);
} else if progress_ratio > progress_threshold {
current_prob = base_prob;
} else {
current_prob = current_prob * 0.8 + base_prob * 0.2;
}
last_check_residual = residual_.len();
}
let v = if min_sad == 0 {
v_min_sad
} else if rng.gen_bool(current_prob) {
c[0].abs() as usize - 1
} else {
v_min_sad
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= max_num_rounds {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,284 +0,0 @@
/*!
Copyright 2024 AllFather
Licensed under the TIG Benchmarker Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
loop {
if !residual_.is_empty() {
let i = residual_[0];
let mut min_sad = clauses.len();
let mut v_min_sad = Vec::with_capacity(clauses[i].len()); // Preallocate with capacity
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad.clear();
v_min_sad.push((l.abs() - 1) as usize);
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..(c.len() as u32)) as usize];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= num_variables * 35 {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,284 +0,0 @@
/*!
Copyright 2024 AllFather
Licensed under the TIG Commercial License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
loop {
if !residual_.is_empty() {
let i = residual_[0];
let mut min_sad = clauses.len();
let mut v_min_sad = Vec::with_capacity(clauses[i].len()); // Preallocate with capacity
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad.clear();
v_min_sad.push((l.abs() - 1) as usize);
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..(c.len() as u32)) as usize];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= num_variables * 35 {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,284 +0,0 @@
/*!
Copyright 2024 AllFather
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
loop {
if !residual_.is_empty() {
let i = residual_[0];
let mut min_sad = clauses.len();
let mut v_min_sad = Vec::with_capacity(clauses[i].len()); // Preallocate with capacity
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad.clear();
v_min_sad.push((l.abs() - 1) as usize);
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..(c.len() as u32)) as usize];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= num_variables * 35 {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,284 +0,0 @@
/*!
Copyright 2024 AllFather
Licensed under the TIG Innovator Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
loop {
if !residual_.is_empty() {
let i = residual_[0];
let mut min_sad = clauses.len();
let mut v_min_sad = Vec::with_capacity(clauses[i].len()); // Preallocate with capacity
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad.clear();
v_min_sad.push((l.abs() - 1) as usize);
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..(c.len() as u32)) as usize];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= num_variables * 35 {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,4 +0,0 @@
mod benchmarker_outbound;
pub use benchmarker_outbound::solve_challenge;
#[cfg(feature = "cuda")]
pub use benchmarker_outbound::{cuda_solve_challenge, KERNEL};

View File

@ -1,284 +0,0 @@
/*!
Copyright 2024 AllFather
Licensed under the TIG Open Data License v1.0 or (at your option) any later version
(the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
loop {
if !residual_.is_empty() {
let i = residual_[0];
let mut min_sad = clauses.len();
let mut v_min_sad = Vec::with_capacity(clauses[i].len()); // Preallocate with capacity
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad.clear();
v_min_sad.push((l.abs() - 1) as usize);
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..(c.len() as u32)) as usize];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= num_variables * 35 {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,297 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Benchmarker Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
} else {
n_clauses[var].push(i);
}
}
}
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
let num_p = p_clauses[v].len();
let num_n = n_clauses[v].len();
let vad = num_p as f32 / (num_p + num_n).max(1) as f32;
if vad >= 1.8 {
variables[v] = true;
} else if vad <= 0.56 {
variables[v] = false;
} else {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
}
let mut num_good_so_far: Vec<u8> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 && variables[var] {
num_good_so_far[i] += 1
} else if l < 0 && !variables[var] {
num_good_so_far[i] += 1
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
let clauses_ratio = challenge.difficulty.clauses_to_variables_percent as f64;
let num_vars = challenge.difficulty.num_variables as f64;
let max_fuel = 2000000000.0;
let base_fuel = (2000.0 + 40.0 * clauses_ratio) * num_vars;
let flip_fuel = 900.0 + 1.8 * clauses_ratio;
let max_num_rounds = ((max_fuel - base_fuel) / flip_fuel) as usize;
loop {
if !residual_.is_empty() {
let rand_val = rng.gen::<usize>();
let i = residual_[rand_val % residual_.len()];
let mut min_sad = clauses.len();
let mut v_min_sad = usize::MAX;
let c = &mut clauses[i];
if c.len() > 1 {
let random_index = rand_val % c.len();
c.swap(0, random_index);
}
for &l in c.iter() {
let abs_l = l.abs() as usize - 1;
let clauses_to_check = if variables[abs_l] { &p_clauses[abs_l] } else { &n_clauses[abs_l] };
let mut sad = 0;
for &c in clauses_to_check {
if num_good_so_far[c] == 1 {
sad += 1;
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = abs_l;
}
}
let v = if min_sad == 0 {
v_min_sad
} else if rng.gen_bool(0.5) {
c[0].abs() as usize - 1
} else {
v_min_sad
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= max_num_rounds {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,297 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Commercial License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
} else {
n_clauses[var].push(i);
}
}
}
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
let num_p = p_clauses[v].len();
let num_n = n_clauses[v].len();
let vad = num_p as f32 / (num_p + num_n).max(1) as f32;
if vad >= 1.8 {
variables[v] = true;
} else if vad <= 0.56 {
variables[v] = false;
} else {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
}
let mut num_good_so_far: Vec<u8> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 && variables[var] {
num_good_so_far[i] += 1
} else if l < 0 && !variables[var] {
num_good_so_far[i] += 1
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
let clauses_ratio = challenge.difficulty.clauses_to_variables_percent as f64;
let num_vars = challenge.difficulty.num_variables as f64;
let max_fuel = 2000000000.0;
let base_fuel = (2000.0 + 40.0 * clauses_ratio) * num_vars;
let flip_fuel = 900.0 + 1.8 * clauses_ratio;
let max_num_rounds = ((max_fuel - base_fuel) / flip_fuel) as usize;
loop {
if !residual_.is_empty() {
let rand_val = rng.gen::<usize>();
let i = residual_[rand_val % residual_.len()];
let mut min_sad = clauses.len();
let mut v_min_sad = usize::MAX;
let c = &mut clauses[i];
if c.len() > 1 {
let random_index = rand_val % c.len();
c.swap(0, random_index);
}
for &l in c.iter() {
let abs_l = l.abs() as usize - 1;
let clauses_to_check = if variables[abs_l] { &p_clauses[abs_l] } else { &n_clauses[abs_l] };
let mut sad = 0;
for &c in clauses_to_check {
if num_good_so_far[c] == 1 {
sad += 1;
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = abs_l;
}
}
let v = if min_sad == 0 {
v_min_sad
} else if rng.gen_bool(0.5) {
c[0].abs() as usize - 1
} else {
v_min_sad
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= max_num_rounds {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,297 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
} else {
n_clauses[var].push(i);
}
}
}
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
let num_p = p_clauses[v].len();
let num_n = n_clauses[v].len();
let vad = num_p as f32 / (num_p + num_n).max(1) as f32;
if vad >= 1.8 {
variables[v] = true;
} else if vad <= 0.56 {
variables[v] = false;
} else {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
}
let mut num_good_so_far: Vec<u8> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 && variables[var] {
num_good_so_far[i] += 1
} else if l < 0 && !variables[var] {
num_good_so_far[i] += 1
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
let clauses_ratio = challenge.difficulty.clauses_to_variables_percent as f64;
let num_vars = challenge.difficulty.num_variables as f64;
let max_fuel = 2000000000.0;
let base_fuel = (2000.0 + 40.0 * clauses_ratio) * num_vars;
let flip_fuel = 900.0 + 1.8 * clauses_ratio;
let max_num_rounds = ((max_fuel - base_fuel) / flip_fuel) as usize;
loop {
if !residual_.is_empty() {
let rand_val = rng.gen::<usize>();
let i = residual_[rand_val % residual_.len()];
let mut min_sad = clauses.len();
let mut v_min_sad = usize::MAX;
let c = &mut clauses[i];
if c.len() > 1 {
let random_index = rand_val % c.len();
c.swap(0, random_index);
}
for &l in c.iter() {
let abs_l = l.abs() as usize - 1;
let clauses_to_check = if variables[abs_l] { &p_clauses[abs_l] } else { &n_clauses[abs_l] };
let mut sad = 0;
for &c in clauses_to_check {
if num_good_so_far[c] == 1 {
sad += 1;
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = abs_l;
}
}
let v = if min_sad == 0 {
v_min_sad
} else if rng.gen_bool(0.5) {
c[0].abs() as usize - 1
} else {
v_min_sad
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= max_num_rounds {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,297 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Innovator Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
} else {
n_clauses[var].push(i);
}
}
}
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
let num_p = p_clauses[v].len();
let num_n = n_clauses[v].len();
let vad = num_p as f32 / (num_p + num_n).max(1) as f32;
if vad >= 1.8 {
variables[v] = true;
} else if vad <= 0.56 {
variables[v] = false;
} else {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
}
let mut num_good_so_far: Vec<u8> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 && variables[var] {
num_good_so_far[i] += 1
} else if l < 0 && !variables[var] {
num_good_so_far[i] += 1
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
let clauses_ratio = challenge.difficulty.clauses_to_variables_percent as f64;
let num_vars = challenge.difficulty.num_variables as f64;
let max_fuel = 2000000000.0;
let base_fuel = (2000.0 + 40.0 * clauses_ratio) * num_vars;
let flip_fuel = 900.0 + 1.8 * clauses_ratio;
let max_num_rounds = ((max_fuel - base_fuel) / flip_fuel) as usize;
loop {
if !residual_.is_empty() {
let rand_val = rng.gen::<usize>();
let i = residual_[rand_val % residual_.len()];
let mut min_sad = clauses.len();
let mut v_min_sad = usize::MAX;
let c = &mut clauses[i];
if c.len() > 1 {
let random_index = rand_val % c.len();
c.swap(0, random_index);
}
for &l in c.iter() {
let abs_l = l.abs() as usize - 1;
let clauses_to_check = if variables[abs_l] { &p_clauses[abs_l] } else { &n_clauses[abs_l] };
let mut sad = 0;
for &c in clauses_to_check {
if num_good_so_far[c] == 1 {
sad += 1;
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = abs_l;
}
}
let v = if min_sad == 0 {
v_min_sad
} else if rng.gen_bool(0.5) {
c[0].abs() as usize - 1
} else {
v_min_sad
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= max_num_rounds {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,4 +0,0 @@
mod benchmarker_outbound;
pub use benchmarker_outbound::solve_challenge;
#[cfg(feature = "cuda")]
pub use benchmarker_outbound::{cuda_solve_challenge, KERNEL};

View File

@ -1,297 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Open Data License v1.0 or (at your option) any later version
(the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
} else {
n_clauses[var].push(i);
}
}
}
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
let num_p = p_clauses[v].len();
let num_n = n_clauses[v].len();
let vad = num_p as f32 / (num_p + num_n).max(1) as f32;
if vad >= 1.8 {
variables[v] = true;
} else if vad <= 0.56 {
variables[v] = false;
} else {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
}
let mut num_good_so_far: Vec<u8> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 && variables[var] {
num_good_so_far[i] += 1
} else if l < 0 && !variables[var] {
num_good_so_far[i] += 1
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
let clauses_ratio = challenge.difficulty.clauses_to_variables_percent as f64;
let num_vars = challenge.difficulty.num_variables as f64;
let max_fuel = 2000000000.0;
let base_fuel = (2000.0 + 40.0 * clauses_ratio) * num_vars;
let flip_fuel = 900.0 + 1.8 * clauses_ratio;
let max_num_rounds = ((max_fuel - base_fuel) / flip_fuel) as usize;
loop {
if !residual_.is_empty() {
let rand_val = rng.gen::<usize>();
let i = residual_[rand_val % residual_.len()];
let mut min_sad = clauses.len();
let mut v_min_sad = usize::MAX;
let c = &mut clauses[i];
if c.len() > 1 {
let random_index = rand_val % c.len();
c.swap(0, random_index);
}
for &l in c.iter() {
let abs_l = l.abs() as usize - 1;
let clauses_to_check = if variables[abs_l] { &p_clauses[abs_l] } else { &n_clauses[abs_l] };
let mut sad = 0;
for &c in clauses_to_check {
if num_good_so_far[c] == 1 {
sad += 1;
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = abs_l;
}
}
let v = if min_sad == 0 {
v_min_sad
} else if rng.gen_bool(0.5) {
c[0].abs() as usize - 1
} else {
v_min_sad
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= max_num_rounds {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,292 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Benchmarker Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::{SmallRng, StdRng}, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = SmallRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
} else {
n_clauses[var].push(i);
}
}
}
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
let num_p = p_clauses[v].len();
let num_n = n_clauses[v].len();
let nad = 1.28;
let mut vad = nad + 1.0;
if num_n > 0 {
vad = num_p as f32 / num_n as f32;
}
if vad <= nad {
variables[v] = false;
} else {
let prob = num_p as f64 / (num_p + num_n).max(1) as f64;
variables[v] = rng.gen_bool(prob)
}
}
let mut num_good_so_far: Vec<u8> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 && variables[var] {
num_good_so_far[i] += 1
} else if l < 0 && !variables[var] {
num_good_so_far[i] += 1
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = vec![None; num_clauses];
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices[i] = Some(residual_.len() - 1);
}
}
let clauses_ratio = challenge.difficulty.clauses_to_variables_percent as f64;
let num_vars = challenge.difficulty.num_variables as f64;
let max_fuel = 2000000000.0;
let base_fuel = (2000.0 + 40.0 * clauses_ratio) * num_vars;
let flip_fuel = 350.0 + 0.9 * clauses_ratio;
let max_num_rounds = ((max_fuel - base_fuel) / flip_fuel) as usize;
loop {
if !residual_.is_empty() {
let rand_val = rng.gen::<usize>();
let i = residual_[rand_val % residual_.len()];
let mut min_sad = clauses.len();
let mut v_min_sad = usize::MAX;
let c = &mut clauses[i];
if c.len() > 1 {
let random_index = rand_val % c.len();
c.swap(0, random_index);
}
for &l in c.iter() {
let abs_l = l.abs() as usize - 1;
let clauses_to_check = if variables[abs_l] { &p_clauses[abs_l] } else { &n_clauses[abs_l] };
let mut sad = 0;
for &c in clauses_to_check {
if num_good_so_far[c] == 1 {
sad += 1;
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = abs_l;
}
}
let v = if min_sad == 0 {
v_min_sad
} else if rng.gen_bool(0.5) {
c[0].abs() as usize - 1
} else {
v_min_sad
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= max_num_rounds {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,292 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Commercial License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::{SmallRng, StdRng}, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = SmallRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
} else {
n_clauses[var].push(i);
}
}
}
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
let num_p = p_clauses[v].len();
let num_n = n_clauses[v].len();
let nad = 1.28;
let mut vad = nad + 1.0;
if num_n > 0 {
vad = num_p as f32 / num_n as f32;
}
if vad <= nad {
variables[v] = false;
} else {
let prob = num_p as f64 / (num_p + num_n).max(1) as f64;
variables[v] = rng.gen_bool(prob)
}
}
let mut num_good_so_far: Vec<u8> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 && variables[var] {
num_good_so_far[i] += 1
} else if l < 0 && !variables[var] {
num_good_so_far[i] += 1
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = vec![None; num_clauses];
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices[i] = Some(residual_.len() - 1);
}
}
let clauses_ratio = challenge.difficulty.clauses_to_variables_percent as f64;
let num_vars = challenge.difficulty.num_variables as f64;
let max_fuel = 2000000000.0;
let base_fuel = (2000.0 + 40.0 * clauses_ratio) * num_vars;
let flip_fuel = 350.0 + 0.9 * clauses_ratio;
let max_num_rounds = ((max_fuel - base_fuel) / flip_fuel) as usize;
loop {
if !residual_.is_empty() {
let rand_val = rng.gen::<usize>();
let i = residual_[rand_val % residual_.len()];
let mut min_sad = clauses.len();
let mut v_min_sad = usize::MAX;
let c = &mut clauses[i];
if c.len() > 1 {
let random_index = rand_val % c.len();
c.swap(0, random_index);
}
for &l in c.iter() {
let abs_l = l.abs() as usize - 1;
let clauses_to_check = if variables[abs_l] { &p_clauses[abs_l] } else { &n_clauses[abs_l] };
let mut sad = 0;
for &c in clauses_to_check {
if num_good_so_far[c] == 1 {
sad += 1;
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = abs_l;
}
}
let v = if min_sad == 0 {
v_min_sad
} else if rng.gen_bool(0.5) {
c[0].abs() as usize - 1
} else {
v_min_sad
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= max_num_rounds {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,292 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::{SmallRng, StdRng}, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = SmallRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
} else {
n_clauses[var].push(i);
}
}
}
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
let num_p = p_clauses[v].len();
let num_n = n_clauses[v].len();
let nad = 1.28;
let mut vad = nad + 1.0;
if num_n > 0 {
vad = num_p as f32 / num_n as f32;
}
if vad <= nad {
variables[v] = false;
} else {
let prob = num_p as f64 / (num_p + num_n).max(1) as f64;
variables[v] = rng.gen_bool(prob)
}
}
let mut num_good_so_far: Vec<u8> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 && variables[var] {
num_good_so_far[i] += 1
} else if l < 0 && !variables[var] {
num_good_so_far[i] += 1
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = vec![None; num_clauses];
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices[i] = Some(residual_.len() - 1);
}
}
let clauses_ratio = challenge.difficulty.clauses_to_variables_percent as f64;
let num_vars = challenge.difficulty.num_variables as f64;
let max_fuel = 2000000000.0;
let base_fuel = (2000.0 + 40.0 * clauses_ratio) * num_vars;
let flip_fuel = 350.0 + 0.9 * clauses_ratio;
let max_num_rounds = ((max_fuel - base_fuel) / flip_fuel) as usize;
loop {
if !residual_.is_empty() {
let rand_val = rng.gen::<usize>();
let i = residual_[rand_val % residual_.len()];
let mut min_sad = clauses.len();
let mut v_min_sad = usize::MAX;
let c = &mut clauses[i];
if c.len() > 1 {
let random_index = rand_val % c.len();
c.swap(0, random_index);
}
for &l in c.iter() {
let abs_l = l.abs() as usize - 1;
let clauses_to_check = if variables[abs_l] { &p_clauses[abs_l] } else { &n_clauses[abs_l] };
let mut sad = 0;
for &c in clauses_to_check {
if num_good_so_far[c] == 1 {
sad += 1;
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = abs_l;
}
}
let v = if min_sad == 0 {
v_min_sad
} else if rng.gen_bool(0.5) {
c[0].abs() as usize - 1
} else {
v_min_sad
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= max_num_rounds {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,292 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Innovator Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::{SmallRng, StdRng}, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = SmallRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
} else {
n_clauses[var].push(i);
}
}
}
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
let num_p = p_clauses[v].len();
let num_n = n_clauses[v].len();
let nad = 1.28;
let mut vad = nad + 1.0;
if num_n > 0 {
vad = num_p as f32 / num_n as f32;
}
if vad <= nad {
variables[v] = false;
} else {
let prob = num_p as f64 / (num_p + num_n).max(1) as f64;
variables[v] = rng.gen_bool(prob)
}
}
let mut num_good_so_far: Vec<u8> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 && variables[var] {
num_good_so_far[i] += 1
} else if l < 0 && !variables[var] {
num_good_so_far[i] += 1
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = vec![None; num_clauses];
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices[i] = Some(residual_.len() - 1);
}
}
let clauses_ratio = challenge.difficulty.clauses_to_variables_percent as f64;
let num_vars = challenge.difficulty.num_variables as f64;
let max_fuel = 2000000000.0;
let base_fuel = (2000.0 + 40.0 * clauses_ratio) * num_vars;
let flip_fuel = 350.0 + 0.9 * clauses_ratio;
let max_num_rounds = ((max_fuel - base_fuel) / flip_fuel) as usize;
loop {
if !residual_.is_empty() {
let rand_val = rng.gen::<usize>();
let i = residual_[rand_val % residual_.len()];
let mut min_sad = clauses.len();
let mut v_min_sad = usize::MAX;
let c = &mut clauses[i];
if c.len() > 1 {
let random_index = rand_val % c.len();
c.swap(0, random_index);
}
for &l in c.iter() {
let abs_l = l.abs() as usize - 1;
let clauses_to_check = if variables[abs_l] { &p_clauses[abs_l] } else { &n_clauses[abs_l] };
let mut sad = 0;
for &c in clauses_to_check {
if num_good_so_far[c] == 1 {
sad += 1;
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = abs_l;
}
}
let v = if min_sad == 0 {
v_min_sad
} else if rng.gen_bool(0.5) {
c[0].abs() as usize - 1
} else {
v_min_sad
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= max_num_rounds {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,4 +0,0 @@
mod benchmarker_outbound;
pub use benchmarker_outbound::solve_challenge;
#[cfg(feature = "cuda")]
pub use benchmarker_outbound::{cuda_solve_challenge, KERNEL};

View File

@ -1,292 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Open Data License v1.0 or (at your option) any later version
(the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::{SmallRng, StdRng}, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = SmallRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
} else {
n_clauses[var].push(i);
}
}
}
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
let num_p = p_clauses[v].len();
let num_n = n_clauses[v].len();
let nad = 1.28;
let mut vad = nad + 1.0;
if num_n > 0 {
vad = num_p as f32 / num_n as f32;
}
if vad <= nad {
variables[v] = false;
} else {
let prob = num_p as f64 / (num_p + num_n).max(1) as f64;
variables[v] = rng.gen_bool(prob)
}
}
let mut num_good_so_far: Vec<u8> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 && variables[var] {
num_good_so_far[i] += 1
} else if l < 0 && !variables[var] {
num_good_so_far[i] += 1
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = vec![None; num_clauses];
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices[i] = Some(residual_.len() - 1);
}
}
let clauses_ratio = challenge.difficulty.clauses_to_variables_percent as f64;
let num_vars = challenge.difficulty.num_variables as f64;
let max_fuel = 2000000000.0;
let base_fuel = (2000.0 + 40.0 * clauses_ratio) * num_vars;
let flip_fuel = 350.0 + 0.9 * clauses_ratio;
let max_num_rounds = ((max_fuel - base_fuel) / flip_fuel) as usize;
loop {
if !residual_.is_empty() {
let rand_val = rng.gen::<usize>();
let i = residual_[rand_val % residual_.len()];
let mut min_sad = clauses.len();
let mut v_min_sad = usize::MAX;
let c = &mut clauses[i];
if c.len() > 1 {
let random_index = rand_val % c.len();
c.swap(0, random_index);
}
for &l in c.iter() {
let abs_l = l.abs() as usize - 1;
let clauses_to_check = if variables[abs_l] { &p_clauses[abs_l] } else { &n_clauses[abs_l] };
let mut sad = 0;
for &c in clauses_to_check {
if num_good_so_far[c] == 1 {
sad += 1;
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = abs_l;
}
}
let v = if min_sad == 0 {
v_min_sad
} else if rng.gen_bool(0.5) {
c[0].abs() as usize - 1
} else {
v_min_sad
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices[c] = Some(residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices[c].take().unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices[last] = Some(i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= max_num_rounds {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,285 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Benchmarker Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
loop {
if !residual_.is_empty() {
let i = residual_[rng.gen_range(0..residual_.len())];
let mut min_sad = clauses.len();
let mut v_min_sad = Vec::with_capacity(clauses[i].len()); // Preallocate with capacity
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad.clear();
v_min_sad.push((l.abs() - 1) as usize);
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..(c.len() as u32)) as usize];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= num_variables * 35 {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,285 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Commercial License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
loop {
if !residual_.is_empty() {
let i = residual_[rng.gen_range(0..residual_.len())];
let mut min_sad = clauses.len();
let mut v_min_sad = Vec::with_capacity(clauses[i].len()); // Preallocate with capacity
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad.clear();
v_min_sad.push((l.abs() - 1) as usize);
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..(c.len() as u32)) as usize];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= num_variables * 35 {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,285 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
loop {
if !residual_.is_empty() {
let i = residual_[rng.gen_range(0..residual_.len())];
let mut min_sad = clauses.len();
let mut v_min_sad = Vec::with_capacity(clauses[i].len()); // Preallocate with capacity
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad.clear();
v_min_sad.push((l.abs() - 1) as usize);
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..(c.len() as u32)) as usize];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= num_variables * 35 {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,285 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Innovator Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
loop {
if !residual_.is_empty() {
let i = residual_[rng.gen_range(0..residual_.len())];
let mut min_sad = clauses.len();
let mut v_min_sad = Vec::with_capacity(clauses[i].len()); // Preallocate with capacity
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad.clear();
v_min_sad.push((l.abs() - 1) as usize);
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..(c.len() as u32)) as usize];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= num_variables * 35 {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,4 +0,0 @@
mod benchmarker_outbound;
pub use benchmarker_outbound::solve_challenge;
#[cfg(feature = "cuda")]
pub use benchmarker_outbound::{cuda_solve_challenge, KERNEL};

View File

@ -1,285 +0,0 @@
/*!
Copyright 2024 syebastian
Licensed under the TIG Open Data License v1.0 or (at your option) any later version
(the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut rounds = 0;
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len()); // Preallocate with capacity
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![Vec::new(); num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
// Preallocate capacity for p_clauses and n_clauses
for c in &clauses {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
if p_clauses[var].capacity() == 0 {
p_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
} else {
if n_clauses[var].capacity() == 0 {
n_clauses[var] = Vec::with_capacity(clauses.len() / num_variables + 1);
}
}
}
}
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
loop {
if !residual_.is_empty() {
let i = residual_[rng.gen_range(0..residual_.len())];
let mut min_sad = clauses.len();
let mut v_min_sad = Vec::with_capacity(clauses[i].len()); // Preallocate with capacity
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad.clear();
v_min_sad.push((l.abs() - 1) as usize);
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..(c.len() as u32)) as usize];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..(v_min_sad.len() as u32)) as usize]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
rounds += 1;
if rounds >= num_variables * 35 {
return Ok(None);
}
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,87 +0,0 @@
/*!
Copyright 2024 Uncharted Trading Limited
Licensed under the TIG Benchmarker Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let num_variables = challenge.difficulty.num_variables;
let mut variables: Vec<bool> = (0..num_variables).map(|_| rng.gen::<bool>()).collect();
// Pre-generate a bunch of random integers
// IMPORTANT! When generating random numbers, never use usize! usize bytes varies from system to system
let rand_ints: Vec<usize> = (0..2 * num_variables)
.map(|_| rng.gen_range(0..1_000_000_000u32) as usize)
.collect();
for i in 0..num_variables {
// Evaluate clauses and find any that are unsatisfied
let substituted: Vec<bool> = challenge
.clauses
.iter()
.map(|clause| {
clause.iter().any(|&literal| {
let var_idx = literal.abs() as usize - 1;
let var_value = variables[var_idx];
(literal > 0 && var_value) || (literal < 0 && !var_value)
})
})
.collect();
let unsatisfied_clauses: Vec<usize> = substituted
.iter()
.enumerate()
.filter_map(|(idx, &satisfied)| if !satisfied { Some(idx) } else { None })
.collect();
let num_unsatisfied_clauses = unsatisfied_clauses.len();
if num_unsatisfied_clauses == 0 {
break;
}
// Flip the value of a random variable from a random unsatisfied clause
let rand_unsatisfied_clause_idx = rand_ints[2 * i] % num_unsatisfied_clauses;
let rand_unsatisfied_clause = unsatisfied_clauses[rand_unsatisfied_clause_idx];
let rand_variable_idx = rand_ints[2 * i + 1] % 3;
let rand_variable =
challenge.clauses[rand_unsatisfied_clause][rand_variable_idx].abs() as usize - 1;
variables[rand_variable] = !variables[rand_variable];
}
Ok(Some(Solution { variables }))
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,87 +0,0 @@
/*!
Copyright 2024 Uncharted Trading Limited
Licensed under the TIG Commercial License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let num_variables = challenge.difficulty.num_variables;
let mut variables: Vec<bool> = (0..num_variables).map(|_| rng.gen::<bool>()).collect();
// Pre-generate a bunch of random integers
// IMPORTANT! When generating random numbers, never use usize! usize bytes varies from system to system
let rand_ints: Vec<usize> = (0..2 * num_variables)
.map(|_| rng.gen_range(0..1_000_000_000u32) as usize)
.collect();
for i in 0..num_variables {
// Evaluate clauses and find any that are unsatisfied
let substituted: Vec<bool> = challenge
.clauses
.iter()
.map(|clause| {
clause.iter().any(|&literal| {
let var_idx = literal.abs() as usize - 1;
let var_value = variables[var_idx];
(literal > 0 && var_value) || (literal < 0 && !var_value)
})
})
.collect();
let unsatisfied_clauses: Vec<usize> = substituted
.iter()
.enumerate()
.filter_map(|(idx, &satisfied)| if !satisfied { Some(idx) } else { None })
.collect();
let num_unsatisfied_clauses = unsatisfied_clauses.len();
if num_unsatisfied_clauses == 0 {
break;
}
// Flip the value of a random variable from a random unsatisfied clause
let rand_unsatisfied_clause_idx = rand_ints[2 * i] % num_unsatisfied_clauses;
let rand_unsatisfied_clause = unsatisfied_clauses[rand_unsatisfied_clause_idx];
let rand_variable_idx = rand_ints[2 * i + 1] % 3;
let rand_variable =
challenge.clauses[rand_unsatisfied_clause][rand_variable_idx].abs() as usize - 1;
variables[rand_variable] = !variables[rand_variable];
}
Ok(Some(Solution { variables }))
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,156 +0,0 @@
/*!
Copyright 2024 TIG Foundation
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(challenge.seeds[0] as u64);
let num_variables = challenge.difficulty.num_variables;
let mut variables: Vec<bool> = (0..num_variables).map(|_| rng.gen::<bool>()).collect();
// Pre-generate a bunch of random integers
// IMPORTANT! When generating random numbers, never use usize! usize bytes varies from system to system
let rand_ints: Vec<usize> = (0..2 * num_variables)
.map(|_| rng.gen_range(0..1_000_000_000u32) as usize)
.collect();
for i in 0..num_variables {
// Evaluate clauses and find any that are unsatisfied
let substituted: Vec<bool> = challenge
.clauses
.iter()
.map(|clause| {
clause.iter().any(|&literal| {
let var_idx = literal.abs() as usize - 1;
let var_value = variables[var_idx];
(literal > 0 && var_value) || (literal < 0 && !var_value)
})
})
.collect();
let unsatisfied_clauses: Vec<usize> = substituted
.iter()
.enumerate()
.filter_map(|(idx, &satisfied)| if !satisfied { Some(idx) } else { None })
.collect();
let num_unsatisfied_clauses = unsatisfied_clauses.len();
if num_unsatisfied_clauses == 0 {
break;
}
// Flip the value of a random variable from a random unsatisfied clause
let rand_unsatisfied_clause_idx = rand_ints[2 * i] % num_unsatisfied_clauses;
let rand_unsatisfied_clause = unsatisfied_clauses[rand_unsatisfied_clause_idx];
let rand_variable_idx = rand_ints[2 * i + 1] % 3;
let rand_variable =
challenge.clauses[rand_unsatisfied_clause][rand_variable_idx].abs() as usize - 1;
variables[rand_variable] = !variables[rand_variable];
}
Ok(Some(Solution { variables }))
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = Some(CudaKernel {
// Example CUDA code from https://github.com/coreylowman/cudarc/blob/main/examples/matmul-kernel.rs
src: r#"
extern "C" __global__ void matmul(float* A, float* B, float* C, int N) {
int ROW = blockIdx.y*blockDim.y+threadIdx.y;
int COL = blockIdx.x*blockDim.x+threadIdx.x;
float tmpSum = 0;
if (ROW < N && COL < N) {
// each thread computes one element of the block sub-matrix
for (int i = 0; i < N; i++) {
tmpSum += A[ROW * N + i] * B[i * N + COL];
}
}
C[ROW * N + COL] = tmpSum;
}
"#,
funcs: &["matmul"],
});
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
// Example CUDA code from https://github.com/coreylowman/cudarc/blob/main/examples/matmul-kernel.rs
let start = std::time::Instant::now();
let a_host = [1.0f32, 2.0, 3.0, 4.0];
let b_host = [1.0f32, 2.0, 3.0, 4.0];
let mut c_host = [0.0f32; 4];
let a_dev = dev.htod_sync_copy(&a_host)?;
let b_dev = dev.htod_sync_copy(&b_host)?;
let mut c_dev = dev.htod_sync_copy(&c_host)?;
println!("Copied in {:?}", start.elapsed());
let cfg = LaunchConfig {
block_dim: (2, 2, 1),
grid_dim: (1, 1, 1),
shared_mem_bytes: 0,
};
unsafe {
funcs
.remove("matmul")
.unwrap()
.launch(cfg, (&a_dev, &b_dev, &mut c_dev, 2i32))
}?;
dev.dtoh_sync_copy_into(&c_dev, &mut c_host)?;
println!("Found {:?} in {:?}", c_host, start.elapsed());
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,87 +0,0 @@
/*!
Copyright 2024 Uncharted Trading Limited
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let num_variables = challenge.difficulty.num_variables;
let mut variables: Vec<bool> = (0..num_variables).map(|_| rng.gen::<bool>()).collect();
// Pre-generate a bunch of random integers
// IMPORTANT! When generating random numbers, never use usize! usize bytes varies from system to system
let rand_ints: Vec<usize> = (0..2 * num_variables)
.map(|_| rng.gen_range(0..1_000_000_000u32) as usize)
.collect();
for i in 0..num_variables {
// Evaluate clauses and find any that are unsatisfied
let substituted: Vec<bool> = challenge
.clauses
.iter()
.map(|clause| {
clause.iter().any(|&literal| {
let var_idx = literal.abs() as usize - 1;
let var_value = variables[var_idx];
(literal > 0 && var_value) || (literal < 0 && !var_value)
})
})
.collect();
let unsatisfied_clauses: Vec<usize> = substituted
.iter()
.enumerate()
.filter_map(|(idx, &satisfied)| if !satisfied { Some(idx) } else { None })
.collect();
let num_unsatisfied_clauses = unsatisfied_clauses.len();
if num_unsatisfied_clauses == 0 {
break;
}
// Flip the value of a random variable from a random unsatisfied clause
let rand_unsatisfied_clause_idx = rand_ints[2 * i] % num_unsatisfied_clauses;
let rand_unsatisfied_clause = unsatisfied_clauses[rand_unsatisfied_clause_idx];
let rand_variable_idx = rand_ints[2 * i + 1] % 3;
let rand_variable =
challenge.clauses[rand_unsatisfied_clause][rand_variable_idx].abs() as usize - 1;
variables[rand_variable] = !variables[rand_variable];
}
Ok(Some(Solution { variables }))
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,87 +0,0 @@
/*!
Copyright 2024 Uncharted Trading Limited
Licensed under the TIG Innovator Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let num_variables = challenge.difficulty.num_variables;
let mut variables: Vec<bool> = (0..num_variables).map(|_| rng.gen::<bool>()).collect();
// Pre-generate a bunch of random integers
// IMPORTANT! When generating random numbers, never use usize! usize bytes varies from system to system
let rand_ints: Vec<usize> = (0..2 * num_variables)
.map(|_| rng.gen_range(0..1_000_000_000u32) as usize)
.collect();
for i in 0..num_variables {
// Evaluate clauses and find any that are unsatisfied
let substituted: Vec<bool> = challenge
.clauses
.iter()
.map(|clause| {
clause.iter().any(|&literal| {
let var_idx = literal.abs() as usize - 1;
let var_value = variables[var_idx];
(literal > 0 && var_value) || (literal < 0 && !var_value)
})
})
.collect();
let unsatisfied_clauses: Vec<usize> = substituted
.iter()
.enumerate()
.filter_map(|(idx, &satisfied)| if !satisfied { Some(idx) } else { None })
.collect();
let num_unsatisfied_clauses = unsatisfied_clauses.len();
if num_unsatisfied_clauses == 0 {
break;
}
// Flip the value of a random variable from a random unsatisfied clause
let rand_unsatisfied_clause_idx = rand_ints[2 * i] % num_unsatisfied_clauses;
let rand_unsatisfied_clause = unsatisfied_clauses[rand_unsatisfied_clause_idx];
let rand_variable_idx = rand_ints[2 * i + 1] % 3;
let rand_variable =
challenge.clauses[rand_unsatisfied_clause][rand_variable_idx].abs() as usize - 1;
variables[rand_variable] = !variables[rand_variable];
}
Ok(Some(Solution { variables }))
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,4 +0,0 @@
mod benchmarker_outbound;
pub use benchmarker_outbound::solve_challenge;
#[cfg(feature = "cuda")]
pub use benchmarker_outbound::{cuda_solve_challenge, KERNEL};

View File

@ -1,87 +0,0 @@
/*!
Copyright 2024 Uncharted Trading Limited
Licensed under the TIG Open Data License v1.0 or (at your option) any later version
(the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let num_variables = challenge.difficulty.num_variables;
let mut variables: Vec<bool> = (0..num_variables).map(|_| rng.gen::<bool>()).collect();
// Pre-generate a bunch of random integers
// IMPORTANT! When generating random numbers, never use usize! usize bytes varies from system to system
let rand_ints: Vec<usize> = (0..2 * num_variables)
.map(|_| rng.gen_range(0..1_000_000_000u32) as usize)
.collect();
for i in 0..num_variables {
// Evaluate clauses and find any that are unsatisfied
let substituted: Vec<bool> = challenge
.clauses
.iter()
.map(|clause| {
clause.iter().any(|&literal| {
let var_idx = literal.abs() as usize - 1;
let var_value = variables[var_idx];
(literal > 0 && var_value) || (literal < 0 && !var_value)
})
})
.collect();
let unsatisfied_clauses: Vec<usize> = substituted
.iter()
.enumerate()
.filter_map(|(idx, &satisfied)| if !satisfied { Some(idx) } else { None })
.collect();
let num_unsatisfied_clauses = unsatisfied_clauses.len();
if num_unsatisfied_clauses == 0 {
break;
}
// Flip the value of a random variable from a random unsatisfied clause
let rand_unsatisfied_clause_idx = rand_ints[2 * i] % num_unsatisfied_clauses;
let rand_unsatisfied_clause = unsatisfied_clauses[rand_unsatisfied_clause_idx];
let rand_variable_idx = rand_ints[2 * i + 1] % 3;
let rand_variable =
challenge.clauses[rand_unsatisfied_clause][rand_variable_idx].abs() as usize - 1;
variables[rand_variable] = !variables[rand_variable];
}
Ok(Some(Solution { variables }))
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,267 +0,0 @@
/*!
Copyright 2024 Dominic Kennedy
Licensed under the TIG Benchmarker Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len());
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
let mut attempts = 0;
loop {
if attempts >= num_variables * 25 {
return Ok(None);
}
if !residual_.is_empty() {
let i = residual_[0];
let mut min_sad = clauses.len();
let mut v_min_sad = vec![];
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = vec![(l.abs() - 1) as usize];
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..c.len())];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
attempts += 1;
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,267 +0,0 @@
/*!
Copyright 2024 Dominic Kennedy
Licensed under the TIG Commercial License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len());
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
let mut attempts = 0;
loop {
if attempts >= num_variables * 25 {
return Ok(None);
}
if !residual_.is_empty() {
let i = residual_[0];
let mut min_sad = clauses.len();
let mut v_min_sad = vec![];
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = vec![(l.abs() - 1) as usize];
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..c.len())];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
attempts += 1;
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,267 +0,0 @@
/*!
Copyright 2024 Dominic Kennedy
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len());
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
let mut attempts = 0;
loop {
if attempts >= num_variables * 25 {
return Ok(None);
}
if !residual_.is_empty() {
let i = residual_[0];
let mut min_sad = clauses.len();
let mut v_min_sad = vec![];
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = vec![(l.abs() - 1) as usize];
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..c.len())];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
attempts += 1;
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,267 +0,0 @@
/*!
Copyright 2024 Dominic Kennedy
Licensed under the TIG Innovator Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len());
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
let mut attempts = 0;
loop {
if attempts >= num_variables * 25 {
return Ok(None);
}
if !residual_.is_empty() {
let i = residual_[0];
let mut min_sad = clauses.len();
let mut v_min_sad = vec![];
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = vec![(l.abs() - 1) as usize];
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..c.len())];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
attempts += 1;
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,4 +0,0 @@
mod benchmarker_outbound;
pub use benchmarker_outbound::solve_challenge;
#[cfg(feature = "cuda")]
pub use benchmarker_outbound::{cuda_solve_challenge, KERNEL};

View File

@ -1,267 +0,0 @@
/*!
Copyright 2024 Dominic Kennedy
Licensed under the TIG Open Data License v1.0 or (at your option) any later version
(the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::collections::HashMap;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let mut p_single = vec![false; challenge.difficulty.num_variables];
let mut n_single = vec![false; challenge.difficulty.num_variables];
let mut clauses_ = challenge.clauses.clone();
let mut clauses: Vec<Vec<i32>> = Vec::with_capacity(clauses_.len());
let mut dead = false;
while !(dead) {
let mut done = true;
for c in &clauses_ {
let mut c_: Vec<i32> = Vec::with_capacity(c.len());
let mut skip = false;
for (i, l) in c.iter().enumerate() {
if (p_single[(l.abs() - 1) as usize] && *l > 0)
|| (n_single[(l.abs() - 1) as usize] && *l < 0)
|| c[(i + 1)..].contains(&-l)
{
skip = true;
break;
} else if p_single[(l.abs() - 1) as usize]
|| n_single[(l.abs() - 1) as usize]
|| c[(i + 1)..].contains(&l)
{
done = false;
continue;
} else {
c_.push(*l);
}
}
if skip {
done = false;
continue;
};
match c_[..] {
[l] => {
done = false;
if l > 0 {
if n_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
p_single[(l.abs() - 1) as usize] = true;
}
} else {
if p_single[(l.abs() - 1) as usize] {
dead = true;
break;
} else {
n_single[(l.abs() - 1) as usize] = true;
}
}
}
[] => {
dead = true;
break;
}
_ => {
clauses.push(c_);
}
}
}
if done {
break;
} else {
clauses_ = clauses;
clauses = Vec::with_capacity(clauses_.len());
}
}
if dead {
return Ok(None);
}
let num_variables = challenge.difficulty.num_variables;
let num_clauses = clauses.len();
let mut p_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut n_clauses: Vec<Vec<usize>> = vec![vec![]; num_variables];
let mut variables = vec![false; num_variables];
for v in 0..num_variables {
if p_single[v] {
variables[v] = true
} else if n_single[v] {
variables[v] = false
} else {
variables[v] = rng.gen_bool(0.5)
}
}
let mut num_good_so_far: Vec<usize> = vec![0; num_clauses];
for (i, &ref c) in clauses.iter().enumerate() {
for &l in c {
let var = (l.abs() - 1) as usize;
if l > 0 {
p_clauses[var].push(i);
if variables[var] {
num_good_so_far[i] += 1
}
} else {
n_clauses[var].push(i);
if !variables[var] {
num_good_so_far[i] += 1
}
}
}
}
let mut residual_ = Vec::with_capacity(num_clauses);
let mut residual_indices = HashMap::with_capacity(num_clauses);
for (i, &num_good) in num_good_so_far.iter().enumerate() {
if num_good == 0 {
residual_.push(i);
residual_indices.insert(i, residual_.len() - 1);
}
}
let mut attempts = 0;
loop {
if attempts >= num_variables * 25 {
return Ok(None);
}
if !residual_.is_empty() {
let i = residual_[0];
let mut min_sad = clauses.len();
let mut v_min_sad = vec![];
let c = &clauses[i];
for &l in c {
let mut sad = 0 as usize;
if variables[(l.abs() - 1) as usize] {
for &c in &p_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
} else {
for &c in &n_clauses[(l.abs() - 1) as usize] {
if num_good_so_far[c] == 1 {
sad += 1;
if sad > min_sad {
break;
}
}
}
}
if sad < min_sad {
min_sad = sad;
v_min_sad = vec![(l.abs() - 1) as usize];
} else if sad == min_sad {
v_min_sad.push((l.abs() - 1) as usize);
}
}
let v = if min_sad == 0 {
if v_min_sad.len() == 1 {
v_min_sad[0]
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
} else {
if rng.gen_bool(0.5) {
let l = c[rng.gen_range(0..c.len())];
(l.abs() - 1) as usize
} else {
v_min_sad[rng.gen_range(0..v_min_sad.len())]
}
};
if variables[v] {
for &c in &n_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
for &c in &p_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
} else {
for &c in &n_clauses[v] {
if num_good_so_far[c] == 1 {
residual_.push(c);
residual_indices.insert(c, residual_.len() - 1);
}
num_good_so_far[c] -= 1;
}
for &c in &p_clauses[v] {
num_good_so_far[c] += 1;
if num_good_so_far[c] == 1 {
let i = residual_indices.remove(&c).unwrap();
let last = residual_.pop().unwrap();
if i < residual_.len() {
residual_[i] = last;
residual_indices.insert(last, i);
}
}
}
}
variables[v] = !variables[v];
} else {
break;
}
attempts += 1;
}
return Ok(Some(Solution { variables }));
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,7 +1,11 @@
/*!
Copyright [yyyy] [name of copyright owner]
Copyright [year copyright work created] [name of copyright owner]
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
Identity of Submitter [name of person or entity that submits the Work to TIG]
UAI [UAI (if applicable)]
Licensed under the TIG Inbound Game License v2.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
@ -13,6 +17,24 @@ CONDITIONS OF ANY KIND, either express or implied. See the License for the speci
language governing permissions and limitations under the License.
*/
// REMOVE BELOW SECTION IF UNUSED
/*
REFERENCES AND ACKNOWLEDGMENTS
This implementation is based on or inspired by existing work. Citations and
acknowledgments below:
1. Academic Papers:
- [Author(s), "Paper Title", DOI (if available)]
2. Code References:
- [Author(s), URL]
3. Other:
- [Author(s), Details]
*/
// TIG's UI uses the pattern `tig_challenges::<challenge_name>` to automatically detect your algorithm's challenge
use anyhow::{anyhow, Result};
use tig_challenges::satisfiability::{Challenge, Solution};

View File

@ -1,76 +0,0 @@
/*!
Copyright 2024 Chad Blanchard
Licensed under the TIG Benchmarker Outbound Game License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
// TIG's UI uses the pattern `tig_challenges::<challenge_name>` to automatically detect your algorithm's challenge
use rand::prelude::*;
use rand::rngs::StdRng;
use rand::SeedableRng;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let num_variables = challenge.difficulty.num_variables;
let max_flips = 1000;
let mut variables: Vec<bool> = (0..num_variables).map(|_| rng.gen::<bool>()).collect();
for _ in 0..max_flips {
let mut unsatisfied_clauses: Vec<&Vec<i32>> = challenge
.clauses
.iter()
.filter(|clause| !clause_satisfied(clause, &variables))
.collect();
if unsatisfied_clauses.is_empty() {
return Ok(Some(Solution { variables }));
}
let clause = unsatisfied_clauses.choose(&mut rng).unwrap();
let literal = clause.choose(&mut rng).unwrap();
let var_idx = literal.abs() as usize - 1;
variables[var_idx] = !variables[var_idx];
}
Ok(None)
}
fn clause_satisfied(clause: &Vec<i32>, variables: &[bool]) -> bool {
clause.iter().any(|&literal| {
let var_idx = literal.abs() as usize - 1;
(literal > 0 && variables[var_idx]) || (literal < 0 && !variables[var_idx])
})
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,76 +0,0 @@
/*!
Copyright 2024 Chad Blanchard
Licensed under the TIG Commercial License v1.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
// TIG's UI uses the pattern `tig_challenges::<challenge_name>` to automatically detect your algorithm's challenge
use rand::prelude::*;
use rand::rngs::StdRng;
use rand::SeedableRng;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let num_variables = challenge.difficulty.num_variables;
let max_flips = 1000;
let mut variables: Vec<bool> = (0..num_variables).map(|_| rng.gen::<bool>()).collect();
for _ in 0..max_flips {
let mut unsatisfied_clauses: Vec<&Vec<i32>> = challenge
.clauses
.iter()
.filter(|clause| !clause_satisfied(clause, &variables))
.collect();
if unsatisfied_clauses.is_empty() {
return Ok(Some(Solution { variables }));
}
let clause = unsatisfied_clauses.choose(&mut rng).unwrap();
let literal = clause.choose(&mut rng).unwrap();
let var_idx = literal.abs() as usize - 1;
variables[var_idx] = !variables[var_idx];
}
Ok(None)
}
fn clause_satisfied(clause: &Vec<i32>, variables: &[bool]) -> bool {
clause.iter().any(|&literal| {
let var_idx = literal.abs() as usize - 1;
(literal > 0 && variables[var_idx]) || (literal < 0 && !variables[var_idx])
})
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

View File

@ -1,76 +0,0 @@
/*!
Copyright 2024 Chad Blanchard
Licensed under the TIG Inbound Game License v1.0 or (at your option) any later
version (the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
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.
*/
// TIG's UI uses the pattern `tig_challenges::<challenge_name>` to automatically detect your algorithm's challenge
use rand::prelude::*;
use rand::rngs::StdRng;
use rand::SeedableRng;
use tig_challenges::satisfiability::*;
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
let mut rng = StdRng::seed_from_u64(u64::from_le_bytes(challenge.seed[..8].try_into().unwrap()) as u64);
let num_variables = challenge.difficulty.num_variables;
let max_flips = 1000;
let mut variables: Vec<bool> = (0..num_variables).map(|_| rng.gen::<bool>()).collect();
for _ in 0..max_flips {
let mut unsatisfied_clauses: Vec<&Vec<i32>> = challenge
.clauses
.iter()
.filter(|clause| !clause_satisfied(clause, &variables))
.collect();
if unsatisfied_clauses.is_empty() {
return Ok(Some(Solution { variables }));
}
let clause = unsatisfied_clauses.choose(&mut rng).unwrap();
let literal = clause.choose(&mut rng).unwrap();
let var_idx = literal.abs() as usize - 1;
variables[var_idx] = !variables[var_idx];
}
Ok(None)
}
fn clause_satisfied(clause: &Vec<i32>, variables: &[bool]) -> bool {
clause.iter().any(|&literal| {
let var_idx = literal.abs() as usize - 1;
(literal > 0 && variables[var_idx]) || (literal < 0 && !variables[var_idx])
})
}
#[cfg(feature = "cuda")]
mod gpu_optimisation {
use super::*;
use cudarc::driver::*;
use std::{collections::HashMap, sync::Arc};
use tig_challenges::CudaKernel;
// set KERNEL to None if algorithm only has a CPU implementation
pub const KERNEL: Option<CudaKernel> = None;
// Important! your GPU and CPU version of the algorithm should return the same result
pub fn cuda_solve_challenge(
challenge: &Challenge,
dev: &Arc<CudaDevice>,
mut funcs: HashMap<&'static str, CudaFunction>,
) -> anyhow::Result<Option<Solution>> {
solve_challenge(challenge)
}
}
#[cfg(feature = "cuda")]
pub use gpu_optimisation::{cuda_solve_challenge, KERNEL};

Some files were not shown because too many files have changed in this diff Show More