What is Executable Philosophy?

Table of Contents

1 2014.11.20

2 "Introduction to Executable Philosophy"

2.1 Abstract

This paper puts forth Executable Philosophy, a new philosophical methodology that enables us to compute philosophical facts, declare and enforce well-defined constraints on each type of philosophical theory, weigh philosophical theories according to such constraints (by calculating what percentage of them they satisfy, where said constraints are source-agnostic (they can come from anywhere)), choose certain theories over others based on these weightings, create well-defined representations of objects (including abstract, mental, virtual, and physical objects), programmatically uncover sets of inconsistent would-be "counterexamples" leveled at philosophical theories, remove human intuition from the chain of argument justification (though perhaps not theory justification), and automatically detect various types of flaws in (programmatically specified) philosophical arguments.

These benefits come at the cost of implementing philosophical theories in software – that is, constructing them in a programming language – rather than speaking (too loosely) in natural language, at which point we may leverage an automatable, well-defined formal system that can serve as a superset of logic, mathematics, set theory, and computer programming, borrowing techniques from Mathematical Philosophy. Theory choice is justified by appealing to some combination of Mathematical Philosophy, Experimental Philosophy, empirical evidence (where possible), and Analytic Philosophy.

This methodology also provides the more straightforward and immediate benefit obtained by merely attempting to implement a theory in code, or represent an object by specifying its salient features. To date, this implementation/translation step has uncovered numerous gaps and ambiguities in the often quite popular theories implemented thus far.

Executable Philosophy's capabilities also suggest a new philosophical project: namely implementing as many philosophical and physical theories as possible, including their background assumptions and the logical and conceptual relationships between them, then computing the repercussions of holding one set of beliefs versus another, as well as the repercussions of changing one belief in a belief system (e.g., computing which beliefs thereby become consistent or inconsistent to hold), throughout the network of ideas that we call Philosophy – and beyond.

2.2 What is Executable Philosophy?

The only way to rectify our reasonings is to make them as tangible as those of the Mathematicians, so that we can find our error at a glance, and when there are disputes among persons, we can simply say: Let us calculate, without further ado, to see who is right. –Gottfried Leibniz

Executable Philosophy is a new philosophical methodology that enables us to compute philosophical facts. It also provides us with many other new capabilities, detailed below.

In version 0.1 of Executable Philosophy ("ExPhil" henceforth), the focus is on implementing philosophical theories in code, then using them to compute facts of various sorts. (See later sections for the longer-term goals of the methodology.) The process of this theory-centric fact computation consists of:

(1) Theory Definition: implement a philosophical theory – that is, build the theory in its totality as a well-defined algorithm – in Python, including programmatic "representations" of said theory's posited or otherwise relied-upon objects where necessary;

(2) Theory Input Definition: if necessary, define one or more input values suitable to be passed to the theory you would like to compute facts about – specifically facts about the output of the theory given these inputs;

(3) Expression Construction: construct expressions[2] made up of some combination of philosophical theories, inputs to those theories, and Python primitives (depending on what it is you are trying to compute); then finally

(4) Expression Execution: execute said expressions, outputting the result of the computation.

Let's make this process more concrete.

Suppose Philosopher `Ph` is writing an ExPhil paper/program in order to compute the truth of some philosophical claim instead of making her case in a natural language such as English.

Steps (1) and (2) may either be performed by Ph herself, or the philosophical community at large. Step (3) is performed by the paper-/program-writer (in this case our protagonist, Ph). Step (4) is always performed by a computer, thereby bypassing all possible human error during the key reasoning process of evaluating Ph's (now programmatically expressed) claim.

In ExPhil arguments, the definitions, premises, axioms, inference rules, and so on – whatever one grants oneself at the beginning of the argument/computation – can be questioned, as can the interpretation of the results, but everything between the premises and the conclusion cannot be, just like in logic and mathematics; the (computed or proven) result is demonstrated to follow from the definitions used.

This helps achieve a primary aim of ExPhil – the defensibility of philosophical claims, which, in my view, is lacking at present (in Analytic Philosophy) for reasons we will get to below.

A programming language gets us well-definedness, well-definedness gets us certainty, certainty gets us justification – and I want justification.

2.2.1 Why is this methodology called "Executable Philosophy"?

The idea is that we create Philosophy that we can execute (or "run"), just like a computer program, because it is a computer program.

Under ExPhil, humans write Philosophy, then computers execute it (see below). The goal is not to teach Philosophy to computers, but to, among other things (see below), have we humans create well-defined terminology from which undeniable facts can be mechanistically computed, and, eventually – thanks to logical and mathematical methods, such as those leveraged by Mathematical Philosophy – proven.

2.2.2 The Phases of Arguments

There are three phases of philosophical arguments:

(1) Creating or using, then defending the definitions, premises, axioms, and so on that an argument relies upon (2) The argument itself (3) The interpretation of the argument's results

ExPhil performs phase (2), leaving phases (1) and (3) to others, such as Analytic philosophers.

Compared to an Analytic Philosophy argument, ExPhil removes conceptual analysis from phase (2) and packs the results of said analysis into phase (1). ((TODO: Add a picture here showing phase (2) of that process being replaced.))

One goal of ExPhil is to eliminate entire categories of possible errors from philosophical arguments, the most obvious being whether the premises entail the conclusion, and by turning phase (2) into a purely mechanistic process that computes with terminology (in the form of programmatic definitions) that are guaranteed to be not just be defined – another benefit of using ExPhil – but well-defined.

Analytic Philosophy, where the meanings of the terminology in question is simultaneously sought in themselves, as well as used to defend other claims and explicate other terms, thereby blurring together phases (1) and (2), is quite different in this regard.

2.2.3 The Methodology's Components

ExPhil v0.1 has two components:

(1) The tools, techniques, and aim of creating an implementation of philosophical theories in Python, the programming language used.

(The translated ideas are usually philosophical, but not always; encoding a (perhaps partial) model of physics, for example, is sometimes necessary.)

(2) Silence and strict neutrality regarding pre-existing meanings or definitions of the terms defined within ExPhil arguments.

  • Why the scare quotes around "representation"?

    All characters and events in this show—even those based on real people—are entirely fictional. –South Park opening credits (excerpt)

    Within ExPhil, it is critical that the definitions be understood as definitions, not as representations, for the latter can be deemed inaccurate, bear sufficiently insufficient resemblance to the thing represented so as to be deemed an "invalid" representation, or be a flawed representation in some other sense.

    Arguing that a `Person` class is "false" because it doesn't accurately describe what a person "actually" is, for example, makes no sense when leveled against an ExPhil argument – or, perhaps it's more accurate to say, the ExPhil portion of an argument – whose purpose is to demonstrate that its conclusion follows from its premises (phase (2)), not to defend the premises themselves (phase (1)).

    (Imagine if first-order logic could have been criticized this way in the beginning! "Sorry, right arrow already has a meaning; you can't just make up a new one and ignore the ones that exist!")

2.2.4 Benefits and Advantages of ExPhil

There are many benefits to leveraging ExPhil, as argued below. Many of these stem from making Philosophy more well-defined and mind-independent.

  • Prevent argument shape-shifting

    At present, it is common for philosophers to respond to a criticism of their view by "clarifying" them, which often includes substantial changes to a proposed theory.

    When the entirety of a theory is implemented in code, as an algorithm, its behavior is inarguably independent of the minds of the author(s) of that theory. Therefore said theory's output, given a certain input, is objective and undeniable. Analytic Philosophy can make no such guarantee that those explaining how a theory behaves isn't changing it along the way.

  • Avoiding talking past one another[3]

    When all terminology is explicitly defined, as ExPhil requires, a difference in "implicit" assumptions is much more difficult, as these assumptions often must be made explicit for the program to run at all.

    The ramifications of this run very deep. To use a simple example, use of the term "red" in a typical philosophical argument is treated as being utterly unproblematic. But are we talking about a particular shade of red? A range of colors? If so, what is the range, exactly?

    (In ExPhil we often represent colors using what programmers call RGB values, where the 'R', 'G', and 'B' stand for 'red', 'green', and 'blue', respectively. An RGB value specifies the exact amount of red, green, and blue to combine in order to represent some color, where that amount is specified as an integer between 0 and 255, inclusive. So the brightest, purest red possible is (255, 0, 0) – maximum red, no green, no blue – for example, but if we want to represent a range of values that we then define as "red", we can trivially do so as a range from (r_small, g_small, b_small) to (r_big, g_big, b_big), where each of these 6 variables is some integer from 0 to 255, and where r_small <= r_big, g_small <= g_big, and b_small <= b_big.)

    It is unclear which philosophical problems could be dissolved if we were to simply speak more precisely – and if we continue to speak loosely, we may never find out.

    ExPhil enforces this precision policy by force, thereby guaranteeing that it is followed, as the Python interpreter will not execute lines of code that contain an undefined variable that is relied upon for the computation. The interpreter running our code has no common sense, and will never mistakenly claim to know what we mean like humans do.

    This lack of common sense is a powerful "enabling constraint"[4] that makes the computing of objective conclusions possible.

2.2.5 Why is it OK for ExPhil arguments to create or use any definition of any term, no matter how absurd?

The only hard requirement that ExPhil v0.1 places on its programs/arguments is that they must be syntactically valid Python 2.7.10 programs. ((TODO: According to the spec, or the interpreter?)) I am open to adding stricter constraints given that they are, of course, well-defined.

((TODO: What if a function's output is invariant with its input? Should we rule those rule out as "bad" theories? That may encompass skeptical theories that say, for example, that there is no such thing as knowledge – you can't have it – in which case `is_knowledge = lambda x: False` is the ~trivial theory, so is that too strict?))

If you have a well-defined notion of "absurd", please translate it into Python so the rest of us can use it to weed out absurd programs, definitions, and arguments.

A goal of the methodology itself is not to tell people how to use it. I believe that social pressure is enough to ensure that philosophers only try to publish relevant Philosophy; ideas deemed bad or uninteresting will be weeded out in the philosophical marketplace, just as they are now. Silly definitions, such as defining "water" to be CO2 rather than H2O, will be ignored.

  • How are we supposed to choose which definition or theory of names, for example, is best?

    First of all, if Analytic Philosophers, scientists, mathematicians, or others manage to successfully argue that one definition of some philosophical term is "better" (in some relevant sense) than another, this only helps the ExPhil community decide which definitions to favor.

    The deeper question is, when performing a logical or mathematical proof, computing facts, or constructing some other formal system, what does it take to justify an axiom or definition at all?

    If every claim must be defended by evidence, and that evidence is justified by other evidence still, well, how do we rid ourselves of this nasty regress, which seems to either be infinite, or terminate on a question we cannot answer or claim we cannot justify? (Logic tries, via metalogic, but what justifies its axioms?)

    I could try to make ExPhil more all-encompassing and go beyond phase (2), but foundational justification is a question that no field yet has an answer to – not math, not logic, not even science (aside from appeals to common sense).

    These questions are out of scope for ExPhil v0.1 proper, and probably all future versions as well, but below I provide a more compelling and much more detailed answer, since it is important that I make clear that, while this question plagued Carnap's constructed systems – the closest analogue to Executable Philosophy I am aware of – this question does not plague ExPhil.

2.3 What's wrong with Analytic Philosophy?

I know of two ways to justify an assertion – induction, and deduction. If the assertion is about the world, it may be justified via induction (i.e., science). And if the assertion is made within a deductive or a similarly well-defined system, such as logic or mathematics, it can only be justified via deductive proof (or, as per ExPhil, via computation).

Where does Analytic fit in? Its claims are not empirical, and they are rarely purely logical or mathematical.

So… what is the methodology? Analytic Philosophy purports to use conceptual analysis and logic to get at and justify deep, metaphysical truths (e.g., "knowledge is a true, justified belief") that result from answering philosophical questions (e.g., "what is knowledge?").

Analytic philosophers presuppose that humans possess some sort of metaphysical truth-tracking trait that we tap into when doing Philosophy. Scientists are aware no evolutionary pressure on the brains of mammals who evolved on the plains of Africa, as we did, to acquire such an ability ((TODO: specific citation needed)).

I fear that the closest Analytic Philosophy has gotten to defensibly answering a question is, "knowledge is a true, justified belief"… without telling us what 'true', 'justified', or 'belief' might mean! (Why would we – and how could we – even believe that "knowledge is a true, justified belief" is true without knowing the meanings of the constituent terms?)

Why the lackluster results? I believe the tools of Analytic Philosophy are broken. But as tool-makers, we can augment our analytical abilities with our technology – computers, in particular.

((Impolite answer: it has never answered a question before – ever – yet purports to be able to do so. Therefore not only is it a poor methodology, but we knowa priori, even – that it's at best tied for the worst methodology in any field to ever exist, because its track record that matches the theoretical maximum for the least successful possible methodology, with all losses and no victories.))

2.3.1 Analytic Philosophy is like theoretical physics without experimental physics

Forming theories and claims about what is metaphysically true without ever being able to check our answers puts Philosophy in the position that theoretical physics would be in without experimental physics; it can come up with promising ideas, but has no way to vindicate them… other than with more, also unvindicated arguments and ideas.

2.3.2 Thought Experiments

"I got a skylight put in my apartment. The people who live above me are furious." –Steven Wright

((TODO: Here, talk about problems with thought experiments. E.g., it can take years to notice subtle assumptions we all made when forming some mental picture (CITATION NEEDED; add an example, and GETHELP doing so), perhaps quote or cite Dan Dennett on intuition pumps, and look up criticisms you've made of thought experiments in the past.))

2.4 Is ExPhil an extension of the Analytic tradition?

Yes. ExPhil comes out of a respect for the values, aspirations, subject matter, and some of the creations of Analytic Philosophy (e.g., clarity of thought, solving and dissolving philosophical problems, trying to answer the particular questions it tries to answer (such as the mind-body problem), all forms of logic, and ethics), as well as a disdain for its practical embodiment of those values (e.g., inability to defend claims against the skeptic (to my satisfaction), using undefined terms to define other undefined terms, treating intuitive plausibility as indication of metaphysical truth, among others).

2.5 Is ExPhil intended to be a complete replacement for Analytic Philosophy?

No. As noted above, ExPhil makes no attempt to take part in phases (1) or (3) of philosophical arguments. ExPhil needs Analytic to:

(1) Provide the plethora of ideas, theories, thought experiments, and conceptual and logical distinctions it has developed over at least several decades; (2) Continue creating new ideas; and (3) Innovate in the area of foundational justification, for the benefit of all arguments of all types – philosophical and otherwise.

Note that ExPhil itself does not attempt to do (3); this task is considered out of scope. Like logic or mathematics, ExPhil starts with well-defined components, taking them as given, then computes or proves upward from there, leaving its own foundation unjustified (and bypassing a hard-to-avoid infinite regress in the process).

When creating ExPhil programs/arguments, the part that requires by far the most cleverness and ingenuity is the translation step, which itself can be thought of as two sub-steps – namely conceptual analysis and programmatic idea representation, respectively – the first of which Analytic philosophers do better than anyone else in the world – which I hope you all will contribute to.

2.6 What are the key differences between ExPhil and Analytic?

  1. ExPhil does not assume that beneath each idea, no matter how confused or widely spread, lies a well-defined, human-knowable, metaphysically-privileged fact of the matter.
  2. In practice, Analytic Philosophy seems to typically follow these steps:

(1) Choose an idea or word to study (2) Assume there is a fact of the matter as to what it "actually" is/means (3) Use intuition and reason to get at such facts

ExPhil, as mentioned above, encourages us to:

(i) Define our terms programmatically (ii) Use said terms to compute facts

((TODO: Consider whether to mention Axiomatic Philosophy, the successor to Executable: "define terms programmatically => convert definitions to sets => perform proofs". Mathematical Philosophy is similar, but uses math directly instead of going through an intermediate programmatic "representation", which has its pros and cons.))

In some sense, ExPhil turns the Analytic worldview on its head. Instead of trying to end up with the "correct" meanings of various terms, we instead begin with well-defined terminology, defined programmatically, and compute upward from there.

  1. In ExPhil, human intuition and human reasoning play no official role; the origins of your definitions in step (1) do not matter. Humans set the system up, and the computer computes the answer.
  2. ExPhil forces us to define our terms before using them.

In Analytic we often see the supposed meaning of terms expressed in terms of several other undefined terms. For example, "knowledge is a true, justified belief with no luck involved" is claimed by Analytics, but without saying what "true", "justified", "belief", and "luck" are.

If one were to write a program consisting merely of

print knowledge(P) == true(P) and justified(P) and belief(P)

it would immediately throw an error: `NameError: name 'knowledge' is not defined`.

  1. A fundamental difference is that Analytics consider words to have a pre-existing, unknown meaning. Executable arguments are agnostic – strictly neutral – with regard to whether such meanings exist, and only insists that such possible meanings be ignored.

Arguably, this alone makes it impossible for Analytic Philosophy to justify any claim whatsoever. If you force yourself to use terminology that you claim already has meanings, and then you try to state the meaning of said terminology in terms of each other (as well as other terminology with unknown meanings), can you ever dig yourself out of that hole?

2.7 What does Executable Philosophy look like?

2.7.1 Color Example: "Orange is redder than blue" and disambiguation

class Color(object):

    def __init__(self, r, g, b):
        if any([color < 0 or color > 255 for color in (r, g, b)]):
            raise ValueError("r, g, and b must be between 0 and 255, inclusive")

        self.red = r
        self.green = g
        self.blue = b

    def __eq__(self, color):
        '''
        For two colors to be equal to each other, where each color is
        "represented" as an RGB (red, green, blue) value, is for them
        to have the same amount of red, green, and blue, respectively.
        '''
        return (self.red, self.green, self.blue) == \
            (color.red, color.green, color.blue)

    def __ne__(self, color):
        return not self == color

    def redder_than(self, color):
        return self.red > color.red

    def greener_than(self, color):
        return self.green > color.green

    def bluer_than(self, color):
        return self.blue > color.blue

    def naive_distance(self, color):
        '''
        See http://en.wikipedia.org/wiki/Color_difference for "better"
        definitions
        '''
        return abs(self.red - color.red) + \
            abs(self.green - color.green) + \
            abs(self.blue - color.blue)

    def naive_distance2(self, color):
        self_sum = self.red + self.green + self.blue
        color_sum = color.red + color.green + color.blue
        return abs(self_sum - color_sum)


orange = Color(255, 102, 0)
blue = Color(0, 0, 255)
green = Color(0, 255, 0)

# "Orange is redder than blue"
print orange.redder_than(blue)  # True

# Or we could do without the convenience methods and just do
print orange.red > blue.red
# although this relies more upon the underlying implementation


# "Blue is as blue as orange is red"
print blue.blue == orange.red  # True

# Disambiguation of "orange is greener than blue" -- does this mean
# that "orange contains more greenness than blue contains greenness,"
# or that "orange is 'closer to' green than it is to blue?"

# "Orange is more green than blue is green," or "orange contains more
# greenness than blue contains greenness."
print orange.green > blue.green  # True

# "Orange is closer to green than it is to blue," where 'closer' means
# Color.naive_distance
print orange.naive_distance(green) < orange.naive_distance(blue)    # True

# "Orange is closer to green than it is to blue," where 'closer' means
# Color.naive_distance2
print orange.naive_distance2(green) < orange.naive_distance2(blue)  # False

# The missing shade of blue
#
# ((TODO: Explain the significance of this in relation to Hume:
# http://en.wikipedia.org/wiki/The_Missing_Shade_of_Blue))

missing = Color(0, 0, 254.5)
print Color(0, 0, 254).blue < missing.blue < Color(0, 0, 255).blue  # True

2.7.2 Temperature Example: room_temperature


def room_temperature_stevenwright(room):
    '''
    Definition of "room temperature" inspired by this Steven Wright
    joke:

    "It doesn't matter what temperature the room is, it's always room
    temperature."  --Steven Wright
    '''
    return exphil.get_attr(room, exphil.TEMPERATURE)[0]


def room_temperature_colloquial(room):
    '''
    Colloquial definition of room temperature
    '''
    temp, attr = exphil.get_attr(room, exphil.TEMPERATURE)

    if attr.endswith('_c'):  # Celsius
        return 20 <= temp <= 22

    if attr.endswith('_f'):  # Fahrenheit
        return 68 <= temp <= 71.6

2.7.3 Philosophy of Language Examples: Descriptivism and Direct Reference

  • File: exphil.objects.query

import exphil
import exphil.objects

def by_dict(kwargs, all_objects=exphil.objects.all):
    objects = []

    for obj in all_objects:
        all_attrs_match = True
        for k in kwargs:
            try:
                val_found = exphil.get_attr(obj, k)[0]
            except KeyError:
                # obj doesn't have attr k; skip to next obj
                all_attrs_match = False
                break

            val_wanted = kwargs[k]
            if not (val_found == val_wanted or \
                    exphil.is_collection(val_found) and val_wanted in val_found):
                # obj doesn't match; skip to next obj
                all_attrs_match = False
                break

        if all_attrs_match:
            objects.append(obj)

    return objects


def by_id(obj_id, all_objects=exphil.objects.all):
    return [obj for obj in all_objects if id(obj) == obj_id]


  • File: exphil.objects.people (excerpt)
import datetime

import _person

Nietzsche = _person.Person(
    'Friedrich', 'Wilhelm', 'Nietzsche', datetime.date(1844, 10, 15),
    nationality='German',
    religion=None,
    mustache=True,
    philosopher=True,
    author=True,
    author_of=('Thus Spake Zarathustra', 'The Gay Science'),
)
Nietzsche_ID = id(Nietzsche)

  • Commentary

    Descriptivism is a theory of names which holds that, roughly speaking, a name is short-hand for a description of the thing named, and this short-hand uniquely "picks out" said thing. For example, according to Descriptivism, "Friedrich Nietzsche" means something like, "the German philosopher who wrote 'Thus Spake Zarathustra' and had a mustache", and whoever knows this about Nietzsche can refer to him with the name "Nietzsche".

    We encode this above by defining a variable, `nietzsche`, whose value encodes properties of Friedrich Nietzsche:

    nietzsche = {
        'author_of':   'Thus Spake Zarathustra',
        'philosopher': True,
        'mustache':    True,
    }
    

    We then compute what Descriptivism says this term refers to using the expression

    descriptivism.refers_to(nietzsche)
    

    which, thanks to `exphil.objects.query.by_dict` (which is called by descriptivism's `refers_to` method), searches all objects defined in every ExPhil program ever written for one with the specified properties (e.g., `author_of`) and their corresponding values (e.g., 'Thus Spake Zarathustra').

    This computation confirms that Descriptivism's `refers_to` method indeed returns our programmatic representation of Nietzsche as defined in `exphil.objects.people.Nietzsche`, as desired. (Put another way, according to Descriptivism, the description `{'author_of': Thus Spake Zarathustra', 'philosopher': True, 'mustache': True}` refers to Nietzsche as defined in `exphil.objects.people.Nietzsche`.)

  • Significance

    This example is significant for a number of reasons (see below).

    • Objective, mind-independent theory output

      Unlike philosophical arguments in English, German, or any other natural language, it is utterly undeniable what Descriptivism (as defined above) says `nietzsche` (as defined above) refers to; anyone can examine the output of this computation.

      Keeping in mind that the interpretation of (the results of) computations is outside the scope of Executable Philosophy proper – roughly speaking, we just computed the fact that, according to Descriptivism, whenever by "Nietzsche" we mean "the philosopher who wrote 'Thus Spake Zarathustra' and has a mustache", we are successfully referring to the Nietzsche.

      ((TODO: Say more))

    • Open Source

      It is important that ExPhil programs be open source.

      It is not possible for Executable philosophers to meaningfully inspect each other's programs without seeing the source code of these programs.

      ((TODO: Say more))

  • Direct Reference
    • File: exphil.theories.language.direct_reference
    import exphil
    import exphil.objects.query
    
    from exphil.objects.people import SantaClaus_ID, Nietzsche_ID
    
    class DirectReference(exphil.Theory):
    
        def __init__(self):
            self.exphil_attrs.update({
                'theory_type': ['reference', 'names'],
            })
    
    
        def refers_to(self, ref):
            '''
            Answers the question, "what does `ref` refer to (according to
            Direct Reference)?"
            '''
            if ref is None:
                return None
    
            # Make sure we have an ID
            #
            # TODO(sdp): Should/does Direct Reference say 
            if not isinstance(ref, int):
                raise ValueError("Reference '{}' must be an ID (int)", ref)
    
            objs = exphil.objects.query.by_id(ref)
    
            if len(objs) > 1:
                raise ValueError(
                    "Reference is ambiguous; refers to {} objects: {}".format(
                        len(objs), objs
                    )
                )
    
            if not objs:
                return None
    
            return list(objs)[0]
    
    
    direct_reference = DirectReference()
    
    
    if __name__ == '__main__':
        print " *** According to DirectReference...\n"
    
        nietzsche = Nietzsche_ID
        santa = SantaClaus_ID
    
        for ref in [nietzsche, santa, None]:
            print ref, "  refers to  ", direct_reference.refers_to(ref)
    
    
    • Commentary

      Direct Reference is a theory of names which holds that, roughly speaking, a name refers to the thing named directly – not via any other mechanism, such as a description – and that this name uniquely "picks out" its referent. So according to Direct Reference, "Friedrich Nietzsche" means Nietzsche – the man himself.

      We have encoded this above by defining a variable, `nietzsche`, whose value is `NIETZSCHE_ID`, an ID (identifier) that uniquely picks out Nietzsche (or, more precisely, picks out `exphil.objects.people.Nietzsche`). This identifier is the unique location of `exphil.objects.people.Nietzsche` in memory.[5]

      `direct_reference.refers_to` then uses the `exphil.objects.query.by_id` function to search for the object with the ID of NIETZSCHE_ID among all objects ever defined in any ExPhil program. (`query.by_id` also optionally accepts an ontology – a list of objects defined – in case we are interested in searching among a subset of defined entities rather than all of them.)

      This underscores the importance of keeping all ExPhil programs open source, so that they can be centralized and used for this sort of of purpose, and many more.

  • 2.7.4 Voting Example

    • voting.py
    import collections
    import math
    import random
    
    import exphil
    
    def borda(prefs):
        '''
        prefs should be a tuple of tuples indicating preferences.  E.g.,
        (('A', 'B', 'C'), ('A', 'C', 'B'), ('C', 'B', 'A'))
    
        TODO(sdp): Handle ties, like ('A', ('B', 'C')) or perhaps ('A',
        {'B', 'C'}) means that A is preferred to B and C, but neither B
        nor C is preferred to the other.
    
    
        NOTE(sdp): Supposedly always spits out an ordering, unlike
        Condorcet (as per MathPhil lecture 7-1)
    
        Violates Independence of Irrelevant Alternatives
        '''
        # assert len(pairs) == math.factorial(numvoters)/2
    
        if not prefs:
            return None
    
        # If only 1 person voted, the first person's favorite candidate is
        # the winner
        if len(prefs) == 1:
            return prefs[0][0]
    
        assert len(prefs) > 1
    
        vote_totals = collections.defaultdict(int)
    
        # Tally votes for each candidate.  Each time a candidate is
        # preferred over another one, add 1 to its vote total.
        #
        # (This is equivalent to, but simpler to implement than, assigning
        # points based upon ordering; those point assignments are
        # mathematically identical to the sum of the number of opponents
        # beaten by each candidate according to each voter, which is how
        # this algorithm is implemented below.)
        #
        # Also track the candidate with the most votes with `winners`.
        winners = set()
        max_votes = 0
    
        for vote in prefs:
            for left_ndx in xrange(len(vote)):
                for _ in vote[left_ndx+1:]:
                    # left candidate
                    l_candidate = vote[left_ndx]
                    vote_totals[l_candidate] += 1
    
                    # print vote
    
                    # Keep track of who's winning
                    candidate_total = vote_totals[l_candidate]
                    # print l_candidate, "now has", candidate_total, "votes"
                    if candidate_total == max_votes:
                        winners.add(l_candidate)
                    elif candidate_total > max_votes:
                        winners = set([l_candidate])
                        max_votes = candidate_total
    
                    # print "winners:", winners
                    # print
    
    
        # print "vote_totals:", vote_totals, "\n"
    
        if len(winners) == 1:
            return winners.pop()
    
        # Multiple winners
        return frozenset(winners)
    
    
    def condorcet(prefs):
        '''
        Pair-wise comparison of all candidates
    
        Violates Universal Domain
        '''
        vote_totals = collections.defaultdict(int)
    
        for vote in prefs:
            for left_ndx in xrange(len(vote)):
                for right in vote[left_ndx+1:]:
                    left = vote[left_ndx]
                    vote_totals[(left, right)] += 1
    
    
        # TODO(sdp): Detect cycles
    
        # The winner is the one that defeats all other candidates in a
        # pair-wise comparison, unless vote_totals[A] == vote_totals[B]
        # and A and B each beat all other candidates.
    
        # Only bother comparing (A, B), not (B, A); that's wasteful
    
        # "There's a cycle => Transitivity was violated".  So check for
        # transitivity violations to check for cycles?
    
        # When detecting cycles, remember that there could be one option
        # as a winner and a cycle between the remaining options!
    
    
        # FIXME(sdp): For now, assume there is either 1 winner, or a tie
        # between all candidates
        candidates = prefs[0]
        for c in candidates:
            other_candidates = [other for other in candidates if other != c]
            if all(vote_totals[(c, other)] > vote_totals[(other, c)] for other in other_candidates):
                # c beat all others
                return c
    
        # To repeat...
        # FIXME(sdp): For now, assume there is either 1 winner, or a tie
        # between all candidates
        return frozenset(candidates)
    
    
    def approval_n(prefs, top_n):
        '''
        Approval Voting.  Voters state their preferences, then we ignore
        all but their favorite top_n candidates and see who gets more
        votes, ignoring the ordering of those top_n candidates and just
        counting how many times a candidate shows up in the top_n (0 or 1
        times per voter).
    
        Assumes every voter states their opinion on every candidate
        running.
    
        Violates Universal Domain (right? Since someone's first n choices
        could be swapped and that won't affect the outcome?).
        '''
        winners = set()
        max_votes = 0
    
        vote_totals = collections.defaultdict(int)
        for pref in prefs:
            for candidate in pref[:top_n]:
                vote_totals[candidate] += 1
    
                # Keep track of who's winning
                candidate_total = vote_totals[candidate]
                if candidate_total == max_votes:
                    winners.add(candidate)
                elif candidate_total > max_votes:
                    winners = set([candidate])
                    max_votes = candidate_total
    
    
        if len(winners) == 1:
            return winners.pop()
    
        # Multiple winners
        return frozenset(winners)
    
    
    def approval_2(prefs):
        return approval_n(prefs, 2)
    
    def approval_3(prefs):
        return approval_n(prefs, 3)
    
    
    def majority(prefs):
        '''
        Which candidate is the first choice of the most voters?
        '''
        # Majority voting is a special case of approval voting, where
        # voters only approve of their top 1 favorite candidate.
        return approval_n(prefs, 1)
    
    
    all_theories = (
        borda,
        condorcet,
        approval_2,
        approval_3,
        majority,
    )
    
    
    def metatheory_simple(prefs, theories=all_theories):
        '''
        Which candidate do most theories consider to be the winner?
        '''
        borda_winner     = borda(prefs)
        condorcet_winner = condorcet(prefs)
        approval2_winner = approval_2(prefs)
        approval3_winner = approval_3(prefs)
        majority_winner  = majority(prefs)
    
        winners = (
            tuple([borda_winner]),
            tuple([condorcet_winner]),
            tuple([approval2_winner]),
            tuple([approval3_winner]),
            tuple([majority_winner]),
        )
    
        return majority(winners)
    
    
    
    if __name__ == '__main__':
        all_prefs = []
    
        # A
        prefs1 = (
            ('A', 'B', 'C'),
            ('A', 'B', 'C'),
            ('A', 'B', 'C'),
        )
        all_prefs.append(prefs1)
    
        # Usually A
        prefs2 = (
            ('A', 'B', 'C'),
            ('B', 'A', 'C'),
            ('C', 'A', 'B'),
        )
        all_prefs.append(prefs2)
    
        # No preference
        prefs3 = (
            ('A', 'B', 'C'),
            ('B', 'C', 'A'),
            ('C', 'A', 'B'),
        )
        all_prefs.append(prefs3)
    
        # D borda-helps A
        prefs4 = (
            ('A', 'D', 'B', 'C'),
            ('B', 'C', 'A', 'D'),
            ('C', 'A', 'D', 'B'),
        )
        all_prefs.append(prefs4)
    
        # A is majority winner & condorcet loser; B is borda winner
        prefs5 = (
            ('A', 'B', 'C', 'D'),
            ('A', 'B', 'C', 'D'),
            ('B', 'C', 'D', 'A'),
            ('D', 'B', 'C', 'A'),
            ('C', 'D', 'B', 'A'),
        )
        all_prefs.append(prefs5)
    
    
        for prefs in all_prefs:
            print "\n\n\nVotes:", prefs
            print
            for theory in all_theories + (metatheory_simple,):
                print theory.func_name, "-", theory(prefs)
    
    
  • Commentary

    Here we can see implementations of various vote aggregation methods: the Borda count, the Condorcet method, approval voting (top 2 candidates), approval voting (top 3 candidates), and simply majority voting.

    Votes are represented as tuples of tuples, specifically tuples of per-voter votes, where each voter specifies his or her favorite candidates in rank order, from favorite to least favorite (e.g., `('A', 'B', 'C')`, which means that this voter favors candidate A over candidate B over candidate C.)

    Given the votes from various voters as input (that is, all voter "preferences" I've called them, or "prefs" for short), each vote aggregation method's output – each implemented as a Python function – is either one winner if there was just one, or a set of candidates who tied for first according to that aggregation methods.

    ((TODO: Say much more. Talk about: metatheory_simple, do something like `exphil.who(exphil.theories.voting.won, election)` to show the objective computing of the output of a theory + "who won the election given these votes?" is ambiguous + show how ExPhil deals with this ambiguity (namely by computing the answer according to each particular theory of ~election-winning), perhaps something that contributes to MathPhil itself, how metatheories can be used to bypass shortcomings of individual theories, perhaps something about detected biases in systems (which theory wins if you iterate over all possibilities within certain bounds? or does that not imply biases, but the superiority/additional utility of the winning theory?), show that you can see which theories could be removed from the theories used (e.g., the `all_theories` tuple, in this case) without affecting the outcome when indeed that's what would happen, quantitative theory weighing via constraints, then blow them away by showing theory generation + visualizations.))

  • On Facts

    "Given these votes, which candidate won the election?" is in fact ambiguous – it doesn't specify the vote aggregation method – and there is no fact of the matter as to who won until this parameter is specified.

    ((TODO: Decide when to argue (probably not in this paper) that this problem is utterly pervasive throughout Philosophy.))

  • 2.8 Isn't ExPhil a technique, not a methodology?

    ExPhil is a methodology whose core technique is the programmatic representation of ideas, but I fully expect – and recommend – that this technique be used by Analytic Philosophers. Specifically, I think Analytics should translate philosophical theories into computer programs, then use these programmatic representations of said theories as a means of clarifying their intuitions, then use ththese clarifications to produce better theories.

    ((TODO: Say more.))

    2.9 What else does ExPhil enable us to do?

    2.9.1 Defend oneself against the skeptic

    Our claims are defensible because they are made within a well-defined, formal system, and our conclusions follow from our premises. (Again, justifying the beginning of an argument – in our case, the definitions one begins with – is considered out of scope for ExPhil.)

    ((TODO: In Draft 03, mention several more benefits: combating theory shape-shifting, automation (also why ExPhil is better than pure logic), terms must be defined before use (emphasize this), clarity/insights gained in practice by translating ideas into Python => useful partition of ideas clear enough to graduate to a programmatic translation/"representation" and those that still need clarificatory work, much easier to know when Philosophers are talking past each other (since all terms must be defined explicitly), using PUTs to encode intuitions/counterexamples/constraints, auto-detect sets of inconsistent PUTs/intuitions/counterexamples (which can lead to pushing back against a "counterexample"'s insistence on `theory(P) == True` if another "counterexample" insists `theory(P) == False`), making Transduction (induction + deduction/computation) possible, making extravagant claims that rely on thousands of variables now can't be done casually (requires lots of work), mind-independent/"objective" measure of well-definedness (namely the Python interpreter).))

    ((New TODOs: Anti-constraints, dynamic constraints.))

    2.10 Comparisons with Carnap

    The Philosophy most similar to ExPhil is the constructed systems of Rudolph Carnap.

    Carnap wanted to take all philosophical, scientific, and other notions, "explicate" (read: logically clarify) them, then define them in a logically constructed system. This one goal of Carnap's is similar to mine, as is his austere ontology. That said, unlike Carnap, I do not try to reduce mathematics to logic (Logicism has not succeeded), my intent is not to deem all metaphysics meaningless, and I do not want to throw away all Philosophy that is not Philosophy of Science.

    Carnap also wanted to define everything as collections of sense data, which is not something I am trying to do. (I also do not expect this project to be possible, but I would like to see someone pick up where Carnap left off, introducing metaphysical assumptions that Carnap would not accept (e.g., that there is a mind-independent world) until all phenomena can be accounted for. This would be hard to do without something like ExPhil, but may be possible with it.)

    More comparisons:

    1. ExPhil is far more "neutral" than Carnap's constructed systems/languages
      • He built languages with the goal of showing that metaphysical statements are meaningless
      • In ExPhil you can define whatever you want as long as it's syntactically valid Python
        • I personally treat all natural language claims as not precise until they're made precise, rather than asserting that they're meaningless
    2. I don't hate metaphysics, and ExPhil reflects this
      • I think that some metaphysical questions certainly do have answers, at least once they're stated precisely
        • Two examples: the mind-body problem, and the nature of numbers
      • I don't believe in Platonic Heaven, but if you wan't to implement it, go ahead
        • In fact, I want it implemented so we can compute that whatever people think Platonic Heaven does for us (e.g., gives numbers their meaning or structure) is also provided by a more defensible, less inflationary ontology, but demonstrating this is not possible until "Platonic Heaven" is well-defined
    3. I mostly like what Carnap is saying about "internal questions", and treating analytic statements as those that follow from the system as constructed, without any empirical facts determining the answers to such questions. That said, I personally disagree that these (framework-)external existence claims are meaningless; I think they are ambiguous, but can be made precise ("explicated", as Carnap would say) by making such claims within ExPhil.

    I find it embarrassing (for Carnap) that he so confidently declared so many claims to be "devoid of cognitive content" or "non-cognitive" (and therefore meaningless) without defining those very terms.

    1. Carnap says in "Empiricism, Semantics, and Ontology" (1950),

    > I cannot think of any possible evidence that would be regarded as relevant by both [Platonic and Nominalist (with regard to numbers)] philosophers, and therefore, if actually found, would decide the controversy or at least make one of the opposite theses more probable than the other. … Therefore, I feel compelled to regard the external question as a pseudo-question, until both parties to the controversy offer a common interpretation of the question as a cognitive question; this would involve an indication of possible evidence regarded as relevant by both sides.

    This is backward. Until each party's position is well-defined, we cannot say for certain whether there is any disagreement it all. That is, it isn't clear that when one person says, "numbers exist", and another says, "numbers do not exist", that there is disagreement at all until each says what he or she means by "numbers" and "exist", which may turn out to be entirely different from one another.

    It is also a mistake to insist that two parties agree to an interpretation of a question; each should be free to mean whatever they'd like by each term provided that each term is well-defined. (It would be strange to insist that two people who favor different theories of names agree on what "name" means, for example.)

    This illustrates that, embarrassingly (to Analytic Philosophy), we do not even know which philosophical "debates" are legitimate, and which are merely instances of philosophers talking past each other.

    And the fact that no one can say exactly what they mean by "number", "exists", "true", "justified", "belief", and almost all other terms used by philosophers shows how little philosophical progress has been made – indeed, could possibly have been made – even after thousands of years, given that we can't even state the theories we believe. (Is it even possible to believe a theory that hasn't been fully specified?)

    ExPhil helps remedy this dire situation by forcing all terms to be defined before use, and by offering a more expressive language than pure logic in which to define our terms, thanks to modern programming languages, within which we are free to use logic, mathematics, set theory, computer science, and more.

    But to Carnap's credit, he developed systematic distinctions between logical statements, observational statements, theoretical statements, and rules of correspondence. In developing ExPhil I have, thus far, focused mostly on implementing philosophical ideas in software, and when it comes to using ExPhil arguments to make statements about physical reality, to date I have merely spoken of "reinterpreting definitions as descriptions of aspects of reality" (as opposed to treating them as analytic), which is quite vague. That said, "Carnap admits, however, that the distinction [between observational and theoretical terms] is not always clear and the line of demarcation often arbitrary" (source: http://www.iep.utm.edu/carnap/), so it is unclear how precise this and his other distinctions are.

    2.11 Is ExPhil an inherently Anti-realist methodology?

    No. If ExPhil were to assert that the terms defined in its arguments/programs (e.g., 'person') don't have meanings (that stem from, e.g., how the word 'person' is used, or what it refers to) outside of their programmatic definitions, then it would be. But ExPhil asserts no such thing, and only insists that whatever pre-existing meanings there may be are ignored; the Python interpreter cannot intuit these other meanings, and can only compute with what we give it.

    2.12 On Modularity

    By keeping ExPhil v0.1 modest in its scope, it remains general enough to become part of multiple recent strains in philosophy – namely MathPhil and X-Phi.

    In short, Mathematical Philosophy can help make ExPhil more precise (by leveraging math), and X-Phi can empirically justify the use of certain theories in ExPhil. ((TODO: Say more.))

    2.13 Why not just use logic?

    The type of programmatic system that ExPhil provides is a superset of logic, mathematics, and set theory. PyLog provides first-order logic functionality, and Python, though this could change to Haskell or some dialect of Lisp in the future – itself includes numbers as primitives (ints, floats, doubles, etc) along with sets (and frozensets, which are immutable sets.)

    Programming languages also provide much richer data types than logic or math, such as classes, that have already proven to make it much easier to "represent" philosophical ideas, which often include objects with certain properties; using classes, translating these ideas into code is trivial.

    2.14 Unsolved problems in/remaining questions of ExPhil

    ((When do I need to handle these? Which ones am I safe to leave for Analytic Philosophers to interpret?))

    2.14.1 The philosophical semantics of exceptions

    When an exception is thrown, what does that mean? That the theory throwing the exception doesn't have an answer? that it refuses to answer?

    2.15 What are ExPhil's shortcomings?

    While I consider it a strength that ExPhil is more expressive than logic and more precise than natural language, it is also less expressive than natural language and, in practice (thus far), usually less rigorous than logic.

    ((TODO: Talk about overcoming artifacts. E.g., we can compute the fact that `object` is an object, or that empty string contains itself, etc, because that's how Python works, not because of anything specific to any ExPhil argument. These can have subtle, seriously negative consequences. Could they lead to new types of ambiguity?))

    2.15.1 Artifacts

    By artifact I mean a computable fact that follows from how Python (or whichever programming language is used) works, as opposed to facts that follow from the deliberate aspects of our definitions. See below for examples.

    • "Everything is an object"

      More precisely, for all x where x is a Python variable, `isinstance(x, object)` will evaluate to `True`.

      This is something we can compute, but may not be something we intended. Many philosophers deny that colors are objects, for example.

      We can remedy this by creating an `is_object` function that does whatever we like – perhaps one where `is_object(exphil.things.color.ColorWhite)` returns `False`, despite the fact that `isinstance(exphil.things.color.ColorWhite, object)` returns `True` – but this illustrates that we must be careful in how we define our terms, and careful how we use Python's built-in functionality, which may behave differently from how we would expect or prefer.

      Example:

      class Shadow(exphil.Object):
          is_object = False
          color = None
          # TODO: Add more properties here
      
      shadow = Shadow()
      print isinstance(shadow, object)  # True
      
      # What we should have done instead:
      # print shadow.is_object  # False
      

      This seems to show that a shadow is an object, but this is merely a result that stems from every thing in ExPhil inheriting from exphil.Object, which itself inherits from the Python built-in type/class `object`.

    2.15.2 False Artifacts

    With our definitions as they currently stand, there is sometimes artifact-like behavior that we see:

    1. Nietzsche is the author of strings – the titles of books – not books
    2. Nietzsche is neither alive nor dead (or assumed to be alive?)

    Because `exphil.objects.people.Nietzsche` merely specifies the names of some of the books Nietzsche wrote rather than defining and using Book objects, and because we didn't bother explicitly stating whether Nietzsche had died yet when representing him in code, we can reach misleading conclusions about Nietzsche the person based upon `exphil.objects.people.Nietzsche`.

    These issues be remedied with more precise definitions/representations, which is why I say these are "false" artifacts. (The concern remains, though, that our definitions will always be inadequate. ((TODO: Say much more.)))

    2.15.3 Immaturity

    Also, it is arguably too early to tell whether ExPhil is rich enough to encode natural language arguments; the largest existing ExPhil program isn't very big, and the most complex statement translated into ExPhil isn't very complex.

    It's not clear how powerful its techniques can be. Once Rigoristics exists (see below), will we be able to go to psychologists, encode (literally, in code) their notion of "mind" (and other ideas) they implicitly use when conducting their work, then** make this notion more precise in some useful way when implementing it in code?

    ((TODO: **I should be able to say multiple things here; don't mentally treat this fork as a straight-away!))

    2.15.4 Isn't Magic

    ExPhil does not claim to help us get at metaphysical truths and is strictly agnostic on the issue; what it is possible to do with the methodology is subject to debate and, in any case, remains to be seen.

    2.15.5 Lacks consistency assurances

    If by "inconsistent" we mean "implying that something is both true and false", this would discriminate against paraconsistent logic. And I do use the word "discriminate" very intentionally here; I don't want to play favorites with the foundations of ExPhil, tilting the playing field in favor of philosophical arguments I agree with, or even making it impossible to state arguments I disagree with (as Carnap did with his constructed systems).

    Furthermore, it is neither (practically) possible nor desirable for all ExPhil definitions to be jointly consistent, as this would imply that no two opposing theories have been implemented – one implying that the name "Santa Claus" means a fictional person and another that it means an idea, for example. This is not the kind of consistency that ExPhil should aim to enforce.

    ((TODO: Consider saying something about the fact that everyone's belief system is inconsistent, and that doesn't destroy our ability to reach correct conclusions, provided that we avoid reasoning with contradictions.))

    But avoiding undesired inconsistencies would be nice, even though we don't even know if mathematics is consistent. But two wrongs don't make a right, and just because demonstrable consistency is a problem with mathematics doesn't make it acceptable for a new inconsistency to be added to our philosophical arguments – especially programmatic ones, where we should be able to automatically detect such things.

    All that said, I would like to have some sort of setting – imagine declaring `consistency_required = True` in some .py file – that can be set that then tells the rest of the system to enforce consistency and to tell us when the argument we've created is inconsistent.

    This does not yet exist, and without it, I worry that the outputs of ExPhil arguments will not be objectively true in a defensible sense; "who cares if this conclusion 'objectively' follows from the definitions used if those definitions are jointly inconsistent?", they will say. This could reintroduce some kinds of problems that ExPhil should help us do away with.

    2.16 What will the world look like if ExPhil wildly succeeds?

    2.16.1 The disappearance from Philosophy of certain kinds of disagreements altogether

    Does your theory of language actually entail that Santa Claus is not a person, or does it just seem to? Translate your theory from English into code, create (or use an existing) definition of `SantaClaus`, and end the debate definitively.

    2.17 "I still don't care about Executable Philosophy"

    Here's why you should.

    If what we're able to do with the programmatic "representation" of philosophical ideas proves fruitful, why stop at Philosophy? And if all goes well, there are more benefits to be reaped by other fields of knowledge, too.

    2.17.1 Belief Engine

    Using techniques developed within ExPhil, it is possible to build software that, when given a set of beliefs, will output inconsistencies within this belief system, recommend ways of rectifying these inconsistencies based on the explicitly-provided values of the user, and recommend new beliefs that also promote these same values.

    ((TODO: Say more))

    2.17.2 New field: Computational Law[1]

    Once the law is translated into a computer program, it is in principle possible to create an `is_legal` function that is passed a programmatic description of some action (including its jurisdiction), which returns `True` if said action in said jurisdiction is legal, and `False` otherwise.

    This would automate away lawyers as we know them, and would transform the job of a lawyer from someone who interprets the law to someone who argues that the translation of the law from English into Python is buggy.

    2.17.3 New field: Rigoristics (or, "Executable Philosophy qua metamethodology")

    The particular example of Computational Law points to a much broader possibility – why not try to apply the technique of programmatic idea representation to other fields, too?

    ((TODO: Add more here about what is learned about an idea by translating it into a programming language, the clarity that requires, etc.))

    Footnotes:

    [1] Thank you Dan Miller-Smith for this idea, which he conceived of about 10 seconds after I explained the idea of Executable Philosophy to him. (From in-person conversation.)

    [2] Well-defined rules for what constitutes a Python 2.x expression: https://docs.python.org/2/reference/expressions.html

    [3] Thank you Morgan Burke for pointing this out as an important practical problem in Philosophy that should be rectified.

    [4] Thank you Gabrielle Molina for teaching me this concept and phrase.

    [5] At http://play.golang.org/p/fQUbJHZhFr we can see an example from the Go programming language where many "different" objects arguably occupy the same (virtual) space. While it can be compellingly argued that these are merely references to the same object, and not distinct objects (as they are at the same address and due to the implementation details), these objects nonetheless have different indices in the `items` array.

    Author: Steve Phillips <steve@tryingtobeawesome.com>

    Date: 2017-01-28 11:09:55 PST