This commit is contained in:
Spencer Killen 2022-06-25 18:57:56 -06:00
parent 7c8e17ec59
commit 8e6e9edf64
No known key found for this signature in database
GPG Key ID: 750742B5BFA28418
6 changed files with 215 additions and 0 deletions

22
.devcontainer/Dockerfile Normal file
View File

@ -0,0 +1,22 @@
FROM sjkillen/clyngor
RUN apt-get -qq update; apt-get -qq install sudo
ARG USERNAME=asp
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# Copied from https://code.visualstudio.com/docs/remote/containers-advanced#_adding-a-nonroot-user-to-your-dev-container
# Create the user
RUN groupadd --gid $USER_GID $USERNAME \
&& useradd --uid $USER_UID --gid $USER_GID -m $USERNAME --shell /bin/bash \
#
# [Optional] Add sudo support. Omit if you don't need to install software after connecting.
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME
USER $USERNAME
ENTRYPOINT ["bash"]

View File

@ -0,0 +1,34 @@
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.117.0/containers/docker-existing-dockerfile
{
"name": "Clyngor setup",
// Sets the run context to one level up instead of the .devcontainer folder.
"context": "..",
// Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
"dockerFile": "./Dockerfile",
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": null
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": ["abelcour.asp-syntax-highlight", "ms-python.python"]
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Uncomment the next line to run commands after the container is created - for example installing git.
// "postCreateCommand": "apt-get update && apt-get install -y git",
// Uncomment when using a ptrace-based debugger like C++, Go, and Rust
// "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ],
// Uncomment to use the Docker CLI from inside the container. See https://aka.ms/vscode-remote/samples/docker-in-docker.
// "mounts": [ "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" ],
// Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
// "remoteUser": "vscode"
}

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
notes

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"discord.enabled": true
}

19
ontology.py Normal file
View File

@ -0,0 +1,19 @@
from typing import Set
models = (
{"a", "b", "c"},
)
DL_ATOMS = set.union(*models)
def propagate(atoms: Set[str]) -> Set[str]:
atoms = atoms.intersection(DL_ATOMS)
sub_models = (model for model in models if atoms <= model)
first: set = next(sub_models, None)
if first is None:
return set()
return first.intersection(*sub_models)
def check(atoms: Set[str]) -> bool:
atoms = atoms.intersection(DL_ATOMS)
return atoms in models

136
propagator.py Normal file
View File

@ -0,0 +1,136 @@
from copy import deepcopy
from itertools import chain
from operator import itemgetter
from typing import Iterable, List, Tuple
import clingo
from clingo import PropagateControl, PropagateInit, PropagateControl, PropagatorCheckMode, Assignment, Symbol, Control, TheoryAtom
import ontology as O
class Ontology:
def init(self, init: PropagateInit) -> None:
init.check_mode = PropagatorCheckMode.Total
self.assignment = dict()
self.symbolic_atoms = {
init.solver_literal(atom.literal): str(atom.symbol)
for atom in init.symbolic_atoms
}
self.theory_atoms = {
init.solver_literal(atom.literal): atom.elements[0].terms[0].name
for atom in init.theory_atoms
}
self.symbolic_atoms_inv = { v: k for k, v in self.symbolic_atoms.items() }
self.theory_atoms_inv = { v: k for k, v in self.theory_atoms.items() }
# Might only need to watch just theory atoms / just symbol atoms but for now
# watching everything is easier
for lit in chain(self.symbolic_atoms, self.theory_atoms):
init.add_watch(lit)
def truthy_atoms_text(self):
return (str(self.lookup_solver_lit(atom)[0]) for atom in self.assignment if self.assignment[atom])
def atom_text_to_dl_atom(self, atoms: Iterable[str]) -> Iterable[int]:
return map(self.theory_atoms.get, atoms)
def falsey_atoms_text(self):
return (str(self.lookup_solver_lit(atom)[0]) for atom in self.assignment if not self.assignment[atom])
def propagate(self, pcontrol: PropagateControl, changes) -> None:
for change in changes:
atom = abs(change)
assert atom not in self.assignment
self.assignment[atom] = change >= 0
in_atoms = set(self.truthy_atoms_text())
out_atoms = self.atom_text_to_dl_atom(O.propagate())
new_atoms = out_atoms - in_atoms
new_lits = self.atom_text_to_dl_atom(new_atoms)
def undo(self, thread_id: int, assignment: Assignment, changes: List[int]):
for change in changes:
atom = abs(change)
del self.assignment[atom]
def check(self, pcontrol: PropagateControl) -> None:
self.print_assignment()
def print_assignment(self):
print("assignment: ", end="")
for lit in self.assignment:
lit = -lit if not self.assignment[lit] else lit
print(self.solver_lit_text(lit), end=" ")
print()
def is_theory_atom(self, lit: int):
_, _, a = self.lookup_solver_lit(lit)
return a
def solver_lit_text(self, lit: int):
symbol, is_neg, is_theory = self.lookup_solver_lit(lit)
if symbol is None:
return None
theory = "O: " if is_theory else ""
neg = "not " if is_neg else ""
return f"({theory}{neg}{symbol})"
def lookup_solver_lit(self, lit: int) -> Tuple[Symbol, bool, bool]:
atom = abs(lit)
if (atom_symb := self.symbolic_atoms.get(atom, None)) is not None:
return atom_symb, lit < 0, False
if (theo_symbol := self.theory_atoms.get(atom, None)) is not None:
return theo_symbol, lit < 0, True
return None, False, False
program="""
a :- not b.
b :- not a.
c :- not d.
"""
# Need to ground program before we can look up symbolic atoms and
# Having two waves of grounding might be having some weird effects
# So we parse and ground and then revert back to text then reparse
def add_external_atoms(program: str) -> str:
control = clingo.Control(["0"])
control.add("base", [], program)
control.ground([("base", [])])
theory_grammar = """
#theory o {
kterm {- : 0, unary };
&o/0 : kterm, any
}.
"""
external_atoms = "\n".join(
f"{atom} :- &o{{{atom}}}." for atom in
(str(atom.symbol) for atom in control.symbolic_atoms)
)
return theory_grammar + program + external_atoms
program = add_external_atoms(program)
control = clingo.Control(["0"])
propagator = Ontology()
control.register_propagator(propagator)
control.add("base", [], program)
control.ground([("base", [])])
# control.add("external", [], theory_grammar + external_atoms)
# control.ground([("external", [])])
with control.solve(yield_=True) as solve_handle:
for model in solve_handle:
print("answer set:", model)