# Copyright (c) 2009 Tim Freeman # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # (This is the standard MIT License, copied from # http://www.opensource.org/licenses/mit-license.php on 24 Apr 2007.) #desc Like video_prediction, except the AI's past actions are #desc given as input and therefore do not need to be explained. # The universe-state at time n combines with the action at time n to # yield the universe-state at time n+1. from turing_tape import tape_tuple import machine from bits import many_bits, ensure from speed_prior import Speed_prior import physics from physics import Generic_physics_problem from video_prediction import Generic_video_prediction_explanation class Video_prediction_explanation(Generic_video_prediction_explanation): # Return the first framecount frames from the given world-model # explanation, or None if the explanation makes no prediction. # If we had requirements on the syntax of a frame of video, we'd # enforce them here by making run_physics return None if the syntax # doesn't fit. def run_physics(self, framecount, actions): p = self.physics() state = p.run(p.null_value()) result = [] for i in range(0, framecount): if state is None: return None frame = self.perception().run(state) if frame is None: return None result.append(frame) if i < framecount-1: # Only compute a next state if we need one. Otherwise # there might not be enough actions. state = self.physics().run(tape_tuple(state, actions[i])) return result def extrapolated_frame(self, frameno, actions): # Return the frameno'th frame from the physical evolution for # the current explanation. l = self.run_physics(frameno+1, actions) if l is None: return None return l[frameno] class Video_prediction_problem(Generic_physics_problem): def __init__(self, video, actions, next_act): # Video is the array of video frames observed so far. # Actions is an array with the AI actions taken so far. # next_act is the next action. Generic_physics_problem.__init__( self, explanation_class=Video_prediction_explanation) self.video = video self.actions = actions + [next_act] def matches(self, explanation): l = explanation.run_physics(len(self.video)+1, self.actions) ensure(l[0:len(self.video)] == self.video) # Try to find the most likely next frame of video, # assuming that the speed prior is the right probability distribution # for the possible laws of physics. # eps is the probability of the possibilities we ignore. # If there are multiple frames with about the same total probability, # and those probabilities differ by less than eps, then the laws of # physics we ignored might have determined the most probable one and # therefore we might return the wrong frame. def next_frame(video, actions, next_act, eps = 0.000001, # Pass in a non-default problem_class for unit testing. problem_class = Video_prediction_problem): assert len(video) == len(actions)+1 problem = problem_class(video, actions, next_act = next_act) # frames maps each potential frame to its estimated probability. frames={} for explanation in physics.laws_of_physics(problem, eps): frame = explanation.extrapolated_frame(len(video), actions+[next_act]) frames[frame] = frames.get(frame, 1.0) * explanation.measure() # Now pick the most probable. result = None for frame in frames: if result is None or frames[frame] > frames[result]: result = frame return result