Edit on GitHub

pytact.common

common wrapping functions for python - capnp - tactician interface

provides class Proving with method run_prover that evaluates your python proving session in coq environment over capnp communication

you need yourself to establish socket/pipe connection with capnp end of coq and instantiate Proving object with

  1"""
  2common  wrapping functions for python - capnp - tactician interface
  3
  4provides class Proving with method run_prover that evaluates your python
  5proving session in coq environment over capnp communication
  6
  7you need yourself to establish socket/pipe connection with capnp end of coq
  8and instantiate Proving object with
  9"""
 10
 11import pkg_resources
 12import os
 13import logging
 14import asyncio
 15import functools
 16from typing import List
 17import capnp
 18
 19test_filename_stdin = pkg_resources.resource_filename('pytact','tests/TestReinforceStdin.v')
 20test_filename_tcp  =  pkg_resources.resource_filename('pytact','tests/TestReinforceTcp.v')
 21
 22def testfile(fname: str):
 23    return pkg_resources.resource_filename('pytact', os.path.join('tests', fname))
 24
 25
 26logger = logging.getLogger(__name__)
 27
 28
 29
 30
 31
 32class Connection:
 33    """
 34    wrapper class for serving capnp  connection
 35    this wrapper is not specialized to a particular capnp schema
 36    """
 37    async def _reading_socket(self):
 38        """
 39        This loop reads from connected pipe and writes to local capnp client
 40        """
 41        client = self.client
 42        reader = self.reader
 43        while not reader.at_eof():
 44            data = await reader.read(4096)
 45            logger.debug("read from socket %d bytes", len(data))
 46            client.write(data)
 47            logger.debug("wrote to client %d bytes", len(data))
 48
 49        logger.debug("_reading_socket ended")
 50        return '_reading_socket ended'
 51
 52
 53    async def _writing_socket(self):
 54        """
 55        This reads from local capnp client and writes to connected pipe
 56        """
 57        client = self.client
 58        writer = self.writer
 59        while True:
 60            data = await client.read(4096)
 61            logger.debug("read from client %d bytes", len(data))
 62
 63            writer.write(data.tobytes())
 64            await writer.drain()
 65            logger.debug("wrote to socket %d bytes", len(data))
 66
 67        logger.debug("_writing to socket ended")
 68        return '_writing_socket ended'
 69
 70    def __init__(self, reader, writer):
 71        self.reader = reader
 72        self.writer = writer
 73
 74        logger.debug("starting capnp client")
 75
 76        import pytact.graph_api_capnp as api
 77        self.api = api
 78
 79        self.client = capnp.TwoPartyClient()
 80
 81
 82
 83    async def run(self, proc):
 84        """
 85        this method runs the function proc
 86        that defines the process of interacting with capnp connection
 87        on python side
 88
 89        the function proc should be of async awaitable type that takes
 90        two arguments, proc(client, api), the types of client and api
 91        are like in these cals
 92
 93        client = capnp.TwoPartyClient()
 94        api = capnp.load(api.capnp)
 95
 96        and returns None when completed
 97
 98        example:
 99
100        async def proc(client)
101            # do your interaction with with capnp client using the api
102            return
103
104        """
105
106        read_task = asyncio.create_task(self._reading_socket())
107        write_task = asyncio.create_task(self._writing_socket())
108        proc_task = asyncio.create_task(proc(self.client, self.api))
109
110        _done, _pending = await asyncio.wait([read_task, write_task, proc_task],
111                                           return_when=asyncio.FIRST_COMPLETED)
112
113        if proc_task.done():
114            logger.debug("process with capnp ended %s", repr(proc_task))
115            if proc_task.exception():
116                raise Exception("EXCEPTION in connection task; this is not expected, debug: %s",
117                                repr(proc_task))
118
119        else:
120            if read_task.done():
121                raise Exception("reading_socket ended before reinforce ended: "
122                             "possibly terminated from other side")
123            if write_task.done():
124                raise Exception("_writing_socket ended ended before reinforce ended: "
125                             "possibly connection broken")
126
127        read_task.cancel()
128        write_task.cancel()
129        proc_task.cancel()
130        self.writer.close()
131
132        logger.info("serving connection finished")
133
134class Proving(Connection):
135    """
136    this is a higher level wrapper over Connection class that
137    provides higher level run_prover method that takes as an input
138    and runs your function prover and provides
139    to prover the pull object of graph_api.capnp schema
140
141    Example:
142
143    proving = Proving(reader, writer)
144    await proving.run_prover(your_super_prover)
145
146    where reader and writer are the read and write end of socket/pipe to
147    the other end of capnp coq
148
149    and where you need to implement your_super_prover function as you like
150
151    See doc string of run_prover method
152    """
153    @staticmethod
154    async def __proc(prover, client, api):
155        logger.info("calling PullReinforce")
156        pull = client.bootstrap().cast_as(api.PullReinforce)
157        await prover(pull)
158
159    async def run_prover(self, prover):
160        """
161        The method run_prover runs your function prover in coq
162        evaluation session  using capnp protocol graph_api.capnp schema
163
164        Your function prover should take one argument
165
166        pull
167
168        that is an object defined by graph_api.capnp schema
169
170        You can start the  proving session in your functin prover
171        by opening coq proving environment with a call to pull as follows:
172
173        response = await pull.reinforce(lemma).a_wait
174
175        You get available tactics with
176
177        available = await response.available.tactics().a_wait
178
179        You get the context and goal packed in response.result
180        as specified in graph_api.capnp schema
181
182        NOTICE: the implementation of this class depends on the particular naming
183        and data structures we have chosen in graph_api.capnp schema
184
185        This is subject to change
186        """
187        await self.run(functools.partial(self.__proc, prover))
188
189
190def globalNode(nodeIndex):
191    """
192    returns capnp global node argument given local node index
193    """
194    return {'depIndex': 0, 'nodeIndex': nodeIndex}
195
196def capnpLocalTactic(ident: int, local_arguments: List[int]):
197    """
198    returns capnpTactic argument given  ident and a list of local nodes
199    """
200    res = {'ident': ident}, [{'term': globalNode(nodeIndex)} for nodeIndex in local_arguments]
201#           'arguments': [{'term': globalNode(nodeIndex)} for nodeIndex in local_arguments]}
202    return res
203
204def graph_api_capnp():
205    return pkg_resources.resource_filename('pytact','graph_api.capnp')
206
207async def runTactic(obj, tactic, vis=None):
208    """
209    wrapper on capnp runTactic with logging
210    vis: pytact.graph_visualize.Visualizer
211    """
212    logger.info("awaiting tactic %s", repr(tactic))
213    if isinstance(tactic, str):
214        resp = await obj.runTextTactic(tactic).a_wait()
215    else:
216        resp = await obj.runTactic(*tactic).a_wait()
217    result = resp.result
218    logger.info('received result of type %s', result.which())
219    if result.which() == 'newState':
220        logger.info('new proof state: %s', result.newState.state.text)
221        root = result.newState.state.root
222        context = list(result.newState.state.context)
223        logger.debug('with root: %d', root)
224        logger.debug('with context: %s', repr(context))
225    if vis is not None:
226        vis.render(result)
227
228    if result.which() == 'protocolError':
229        logger.error('received protocolError %s', result.protocolError.which())
230    #    raise ProtocolError  # our code is wrong
231
232    return result
test_filename_stdin = '/home/lasse/Documents/Projects/Tactician/develop/coq-tactician-reinforce/pytact/tests/TestReinforceStdin.v'
test_filename_tcp = '/home/lasse/Documents/Projects/Tactician/develop/coq-tactician-reinforce/pytact/tests/TestReinforceTcp.v'
def testfile(fname: str):
23def testfile(fname: str):
24    return pkg_resources.resource_filename('pytact', os.path.join('tests', fname))
logger = <Logger pytact.common (WARNING)>
class Connection:
 33class Connection:
 34    """
 35    wrapper class for serving capnp  connection
 36    this wrapper is not specialized to a particular capnp schema
 37    """
 38    async def _reading_socket(self):
 39        """
 40        This loop reads from connected pipe and writes to local capnp client
 41        """
 42        client = self.client
 43        reader = self.reader
 44        while not reader.at_eof():
 45            data = await reader.read(4096)
 46            logger.debug("read from socket %d bytes", len(data))
 47            client.write(data)
 48            logger.debug("wrote to client %d bytes", len(data))
 49
 50        logger.debug("_reading_socket ended")
 51        return '_reading_socket ended'
 52
 53
 54    async def _writing_socket(self):
 55        """
 56        This reads from local capnp client and writes to connected pipe
 57        """
 58        client = self.client
 59        writer = self.writer
 60        while True:
 61            data = await client.read(4096)
 62            logger.debug("read from client %d bytes", len(data))
 63
 64            writer.write(data.tobytes())
 65            await writer.drain()
 66            logger.debug("wrote to socket %d bytes", len(data))
 67
 68        logger.debug("_writing to socket ended")
 69        return '_writing_socket ended'
 70
 71    def __init__(self, reader, writer):
 72        self.reader = reader
 73        self.writer = writer
 74
 75        logger.debug("starting capnp client")
 76
 77        import pytact.graph_api_capnp as api
 78        self.api = api
 79
 80        self.client = capnp.TwoPartyClient()
 81
 82
 83
 84    async def run(self, proc):
 85        """
 86        this method runs the function proc
 87        that defines the process of interacting with capnp connection
 88        on python side
 89
 90        the function proc should be of async awaitable type that takes
 91        two arguments, proc(client, api), the types of client and api
 92        are like in these cals
 93
 94        client = capnp.TwoPartyClient()
 95        api = capnp.load(api.capnp)
 96
 97        and returns None when completed
 98
 99        example:
100
101        async def proc(client)
102            # do your interaction with with capnp client using the api
103            return
104
105        """
106
107        read_task = asyncio.create_task(self._reading_socket())
108        write_task = asyncio.create_task(self._writing_socket())
109        proc_task = asyncio.create_task(proc(self.client, self.api))
110
111        _done, _pending = await asyncio.wait([read_task, write_task, proc_task],
112                                           return_when=asyncio.FIRST_COMPLETED)
113
114        if proc_task.done():
115            logger.debug("process with capnp ended %s", repr(proc_task))
116            if proc_task.exception():
117                raise Exception("EXCEPTION in connection task; this is not expected, debug: %s",
118                                repr(proc_task))
119
120        else:
121            if read_task.done():
122                raise Exception("reading_socket ended before reinforce ended: "
123                             "possibly terminated from other side")
124            if write_task.done():
125                raise Exception("_writing_socket ended ended before reinforce ended: "
126                             "possibly connection broken")
127
128        read_task.cancel()
129        write_task.cancel()
130        proc_task.cancel()
131        self.writer.close()
132
133        logger.info("serving connection finished")

wrapper class for serving capnp connection this wrapper is not specialized to a particular capnp schema

Connection(reader, writer)
71    def __init__(self, reader, writer):
72        self.reader = reader
73        self.writer = writer
74
75        logger.debug("starting capnp client")
76
77        import pytact.graph_api_capnp as api
78        self.api = api
79
80        self.client = capnp.TwoPartyClient()
reader
writer
api
client
async def run(self, proc):
 84    async def run(self, proc):
 85        """
 86        this method runs the function proc
 87        that defines the process of interacting with capnp connection
 88        on python side
 89
 90        the function proc should be of async awaitable type that takes
 91        two arguments, proc(client, api), the types of client and api
 92        are like in these cals
 93
 94        client = capnp.TwoPartyClient()
 95        api = capnp.load(api.capnp)
 96
 97        and returns None when completed
 98
 99        example:
100
101        async def proc(client)
102            # do your interaction with with capnp client using the api
103            return
104
105        """
106
107        read_task = asyncio.create_task(self._reading_socket())
108        write_task = asyncio.create_task(self._writing_socket())
109        proc_task = asyncio.create_task(proc(self.client, self.api))
110
111        _done, _pending = await asyncio.wait([read_task, write_task, proc_task],
112                                           return_when=asyncio.FIRST_COMPLETED)
113
114        if proc_task.done():
115            logger.debug("process with capnp ended %s", repr(proc_task))
116            if proc_task.exception():
117                raise Exception("EXCEPTION in connection task; this is not expected, debug: %s",
118                                repr(proc_task))
119
120        else:
121            if read_task.done():
122                raise Exception("reading_socket ended before reinforce ended: "
123                             "possibly terminated from other side")
124            if write_task.done():
125                raise Exception("_writing_socket ended ended before reinforce ended: "
126                             "possibly connection broken")
127
128        read_task.cancel()
129        write_task.cancel()
130        proc_task.cancel()
131        self.writer.close()
132
133        logger.info("serving connection finished")

this method runs the function proc that defines the process of interacting with capnp connection on python side

the function proc should be of async awaitable type that takes two arguments, proc(client, api), the types of client and api are like in these cals

client = capnp.TwoPartyClient() api = capnp.load(api.capnp)

and returns None when completed

example:

async def proc(client) # do your interaction with with capnp client using the api return

class Proving(Connection):
135class Proving(Connection):
136    """
137    this is a higher level wrapper over Connection class that
138    provides higher level run_prover method that takes as an input
139    and runs your function prover and provides
140    to prover the pull object of graph_api.capnp schema
141
142    Example:
143
144    proving = Proving(reader, writer)
145    await proving.run_prover(your_super_prover)
146
147    where reader and writer are the read and write end of socket/pipe to
148    the other end of capnp coq
149
150    and where you need to implement your_super_prover function as you like
151
152    See doc string of run_prover method
153    """
154    @staticmethod
155    async def __proc(prover, client, api):
156        logger.info("calling PullReinforce")
157        pull = client.bootstrap().cast_as(api.PullReinforce)
158        await prover(pull)
159
160    async def run_prover(self, prover):
161        """
162        The method run_prover runs your function prover in coq
163        evaluation session  using capnp protocol graph_api.capnp schema
164
165        Your function prover should take one argument
166
167        pull
168
169        that is an object defined by graph_api.capnp schema
170
171        You can start the  proving session in your functin prover
172        by opening coq proving environment with a call to pull as follows:
173
174        response = await pull.reinforce(lemma).a_wait
175
176        You get available tactics with
177
178        available = await response.available.tactics().a_wait
179
180        You get the context and goal packed in response.result
181        as specified in graph_api.capnp schema
182
183        NOTICE: the implementation of this class depends on the particular naming
184        and data structures we have chosen in graph_api.capnp schema
185
186        This is subject to change
187        """
188        await self.run(functools.partial(self.__proc, prover))

this is a higher level wrapper over Connection class that provides higher level run_prover method that takes as an input and runs your function prover and provides to prover the pull object of graph_api.capnp schema

Example:

proving = Proving(reader, writer) await proving.run_prover(your_super_prover)

where reader and writer are the read and write end of socket/pipe to the other end of capnp coq

and where you need to implement your_super_prover function as you like

See doc string of run_prover method

async def run_prover(self, prover):
160    async def run_prover(self, prover):
161        """
162        The method run_prover runs your function prover in coq
163        evaluation session  using capnp protocol graph_api.capnp schema
164
165        Your function prover should take one argument
166
167        pull
168
169        that is an object defined by graph_api.capnp schema
170
171        You can start the  proving session in your functin prover
172        by opening coq proving environment with a call to pull as follows:
173
174        response = await pull.reinforce(lemma).a_wait
175
176        You get available tactics with
177
178        available = await response.available.tactics().a_wait
179
180        You get the context and goal packed in response.result
181        as specified in graph_api.capnp schema
182
183        NOTICE: the implementation of this class depends on the particular naming
184        and data structures we have chosen in graph_api.capnp schema
185
186        This is subject to change
187        """
188        await self.run(functools.partial(self.__proc, prover))

The method run_prover runs your function prover in coq evaluation session using capnp protocol graph_api.capnp schema

Your function prover should take one argument

pull

that is an object defined by graph_api.capnp schema

You can start the proving session in your functin prover by opening coq proving environment with a call to pull as follows:

response = await pull.reinforce(lemma).a_wait

You get available tactics with

available = await response.available.tactics().a_wait

You get the context and goal packed in response.result as specified in graph_api.capnp schema

NOTICE: the implementation of this class depends on the particular naming and data structures we have chosen in graph_api.capnp schema

This is subject to change

def globalNode(nodeIndex):
191def globalNode(nodeIndex):
192    """
193    returns capnp global node argument given local node index
194    """
195    return {'depIndex': 0, 'nodeIndex': nodeIndex}

returns capnp global node argument given local node index

def capnpLocalTactic(ident: int, local_arguments: List[int]):
197def capnpLocalTactic(ident: int, local_arguments: List[int]):
198    """
199    returns capnpTactic argument given  ident and a list of local nodes
200    """
201    res = {'ident': ident}, [{'term': globalNode(nodeIndex)} for nodeIndex in local_arguments]
202#           'arguments': [{'term': globalNode(nodeIndex)} for nodeIndex in local_arguments]}
203    return res

returns capnpTactic argument given ident and a list of local nodes

def graph_api_capnp():
205def graph_api_capnp():
206    return pkg_resources.resource_filename('pytact','graph_api.capnp')
async def runTactic(obj, tactic, vis=None):
208async def runTactic(obj, tactic, vis=None):
209    """
210    wrapper on capnp runTactic with logging
211    vis: pytact.graph_visualize.Visualizer
212    """
213    logger.info("awaiting tactic %s", repr(tactic))
214    if isinstance(tactic, str):
215        resp = await obj.runTextTactic(tactic).a_wait()
216    else:
217        resp = await obj.runTactic(*tactic).a_wait()
218    result = resp.result
219    logger.info('received result of type %s', result.which())
220    if result.which() == 'newState':
221        logger.info('new proof state: %s', result.newState.state.text)
222        root = result.newState.state.root
223        context = list(result.newState.state.context)
224        logger.debug('with root: %d', root)
225        logger.debug('with context: %s', repr(context))
226    if vis is not None:
227        vis.render(result)
228
229    if result.which() == 'protocolError':
230        logger.error('received protocolError %s', result.protocolError.which())
231    #    raise ProtocolError  # our code is wrong
232
233    return result

wrapper on capnp runTactic with logging vis: pytact.graph_visualize.Visualizer