Skip to content

Commit

Permalink
add option to not store intermediate states; change force_ac3 default…
Browse files Browse the repository at this point in the history
… value
  • Loading branch information
AlexeyBond committed Feb 10, 2024
1 parent d0e036b commit 40a89f7
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 2 deletions.
22 changes: 21 additions & 1 deletion addons/wfc/solver/solver.gd
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func _make_initial_state(num_cells: int, initial_domain: WFCBitSet) -> WFCSolver
state.cell_solution_or_entropy.fill(-(initial_domain.count_set_bits() - 1))

state.unsolved_cells = num_cells
state.observations_count = 0

return state

Expand All @@ -77,6 +78,10 @@ var best_state: WFCSolverState
func _init(problem_: WFCProblem, settings_: WFCSolverSettings = WFCSolverSettings.new()):
settings = settings_
backtracking_enabled = settings.allow_backtracking

if settings.is_sparse_history_enabled():
assert(settings.sparse_history_interval > 1)

problem = problem_
ac4_enabled = (not settings.force_ac3) and problem.supports_ac4()

Expand Down Expand Up @@ -230,6 +235,21 @@ func _try_backtrack() -> bool:

return false

func _should_keep_previous_state(state: WFCSolverState) -> bool:
if not backtracking_enabled:
return false

if not settings.is_sparse_history_enabled():
return true

if state.observations_count < settings.sparse_history_start:
return true

if (state.observations_count - settings.sparse_history_start) % settings.sparse_history_interval == 0:
return true

return false

## Perform one iteration of problem solution.
## [br]
## Returns [code]true[/code] iff solution is completed.
Expand All @@ -251,7 +271,7 @@ func solve_step() -> bool:

current_state.prepare_divergence()

if backtracking_enabled:
if _should_keep_previous_state(current_state):
var next_state := current_state.diverge(problem)

if next_state == null:
Expand Down
39 changes: 38 additions & 1 deletion addons/wfc/solver/solver_settings.gd
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,42 @@ var require_backtracking: bool = false
@export
var backtracking_limit: int = -1

## Number of "observations" after which some of intermediate states will not be stored even when
## backtracking is enabled.
## [br]
## When set to [code]0[/code] or less - all intermediate states will be stored if backtracking is
## enabled.
## [br]
## Skipping some intermediate states will reduce memory usage during solution but will randomly
## affect amount of time required to solve the problem.
@export
var sparse_history_start: int = 10

## Number of intermediate states skipped when [member sparse_history_start] is activated.
## [br]
## When [member sparse_history_interval] is set to [code]N[/code], only every [code]N[/code]'th
## intermediate state will be stored, and thus, the memory consumption by algorithm will be reduced
## [code]N[/code] times.
## However, when backtracking happens, the solver will revert multiple (from 1 to [code]N[/code])
## observations - until the last saved state.
## In case of problems with high probability of backtracking this may increase time required to
## solve the problem, or even meke the solver unable to solve it at all.
@export
var sparse_history_interval: int = 10

func is_sparse_history_enabled():
return sparse_history_start > 0

## Forces use of AC3-like constraint propagation algorithm.
## [br]
## When disabled, the solver will use an AC4-like algorithm if possible.
## [br]
## [color=red]Current implementation of AC4-like algorithm is less stable and, suddenly, less
## efficient in some cases[/color] (but it is more efficient in some other cases as well), so this
## option is marked as experimental and enabled by default.
## [br]
## Experimental mark will be removed and default value will be changed when/if the issue with low
## performance will be fixed and all edge-cases will be covered.
## @experimental
@export
var force_ac3: bool = false
var force_ac3: bool = true
10 changes: 10 additions & 0 deletions addons/wfc/solver/solver_state.gd
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ var cell_solution_or_entropy: PackedInt64Array
## Number of cells that still have domains of more than one value.
var unsolved_cells: int

## Number of "observations" made to reach this state.
## [br]
## This nubmer may be different from [code]len(cell_domains) - unsolved_cells[/code] since one
## observation may cause immediate collapse of other cells.
var observations_count: int

var changed_cells: PackedInt64Array

var divergence_cell: int = -1
Expand Down Expand Up @@ -144,6 +150,8 @@ func make_next() -> WFCSolverState:
new.ac4_acknowledged_domains = ac4_acknowledged_domains
ac4_acknowledged_domains = []

new.observations_count = observations_count

new.previous = self

return new
Expand Down Expand Up @@ -215,6 +223,7 @@ func diverge(problem: WFCProblem) -> WFCSolverState:
var solution := problem.pick_divergence_option(divergence_options)

next_state.set_solution(divergence_cell, solution)
next_state.observations_count += 1

return next_state

Expand All @@ -228,6 +237,7 @@ func diverge_in_place(problem: WFCProblem):

divergence_options.clear()
divergence_cell = -1
observations_count += 1

func get_ac4_counter_offset(cell_id: int, constraint_id: int, tile_id: int) -> int:
var t := ac4_counter_index_coefficients * Vector3i(cell_id, constraint_id, tile_id)
Expand Down

0 comments on commit 40a89f7

Please sign in to comment.