text:
# Chapter 19 {docsify-ignore}

## Introduction to Natural Language

> Language is everywhere. It permeates our thoughts,
> mediates our relations with others, and even creeps
> into our dreams. The overwhelming hulk of human
> knowledge is stored and transmitted in language.
> Language is so ubiquitous that we take itfor granted,
> but without it, society as we know it would
> be impossible.
>
> - Ronand Langacker
>
> Language and its Structure (1967)

A natural language is a language spoken by people, such as English, German, or Tagalog.
This is in opposition to artificial languages like Lisp, FORTRAN, or Morse code.
Natural language processing is an important part of AI because language is intimately
connected to thought. One measure of this is the number of important books that mention
language and thought in the title: in AI, Schank and Colby's Computer Models of Thought
and Language; in linguistics, Whorf's Language, Thought, and Reality (and Chomsky's Language
and Mind;) in philosophy, Fodor's The Language of Thought; and in psychology, Vygotsky's
Thought and Language and John Anderson's Language, Memory, and Thought. Indeed, language is

the trait many think of as being the most characteristic of humans. Much controversy
has been generated over the question of whether animals, especially primates and
dolphins, can use and "understand" language. Similar controversy surrounds the
same question asked of computers.

The study of language has been traditionally separated into two broad classes:
syntax, or grammar, and semantics, or meaning. Historically, syntax has achieved
the most attention, largely because on the surface it is more amenable to formal and
semiformal methods. Although there is evidence that the boundary between the two
is at best fuzzy, we still maintain the distinction for the purposes of these notes. We
will cover the "easier" part, syntax, first, and then move on to semantics.

A good artificial language, like Lisp or C, is unambiguous. There is only one
interpretation for a valid Lisp expression. Of course, the interpretation may depend
on the state of the current state of the Lisp world, such as the value of global variables.
But these dependencies can be explicitly enumerated, and once they are spelled out,
then there can only be one meaning for the expression,^

Natural language does not work like this. Natural expressions are inherently
ambiguous, depending on any number of factors that can never be quite spelled out
completely. It is perfectly reasonable for two people to disagree on what some other
person meant by a natural language expression. (Lawyers and judges make their
living largely by interpreting natural language expressions - laws - that are meant to
be unambiguous but are not.)

This chapter is a brief introduction to natural language processing. The next
chapter gives a more thorough treatment from the point of view of logic grammars,
and the chapter after that puts it all together into a full-fledged system.

### 19.1 Parsing with a Phrase-Structure Grammar

To parse a sentence means to recover the constituent structure of the sentence - to
discover what sequence of generation rules could have been applied to come up with
the sentence. In general, there may be several possible derivations, in which case
we say the sentence is grammatically ambiguous. In certain circles, the term "parse"
means to arrive at an understanding of a sentence's meaning, not just its grammatical
form. We will attack that more difficult question later.

^Some erroneous expressions are underspecified and may return different results in different
implementations, but we will ignore that problem.

We start with the grammar defined on [page 39](chapter2.md#page-39) for the generate program:

``` lisp(
defvar ^grammar* "The grammar used by GENERATE.")

(defparameter *grammarl*

'((Sentence -> (NP VP))
(NP -> (Art Noun))
(VP -> (Verb NP))
(Art -> the a)
(Noun -> man ball woman table)
(Verb -> hit took saw liked)))
```

Our parser takes as input a list of words and returns a structure containing the parse
tree and the unparsed words, if any. That way, we can parse the remaining words
under the next category to get compound rules. For example, in parsing "the man
saw the table," we would first parse "the man," returning a structure representing
the noun phrase, with the remaining words "saw the table." This remainder would
then be parsed as a verb phrase, returning no remainder, and the two phrases could
then be joined to form a parse that is a complete sentence with no remainder.

Before proceeding, I want to make a change in the representation of grammar
rules. Currently, rules have a left-hand side and a list of alternative right-hand sides.
But each of these alternatives is really a separate rule, so it would be more modular
to write them separately. For the generate program it was fine to have them all together,
because that made processing choices easier, but now I want a more flexible
representation. Later on we will want to add more information to each rule, like the
semantics of the assembled left-hand side, and constraints between constituents on
the right-hand side, so the rules would become quite large indeed if we didn't split up
the alternatives. I also take this opportunity to clear up the confusion between words
and category symbols. The convention is that a right-hand side can be either an
atom, in which case it is a word, or a list of symbols, which are then all interpreted as
categories. To emphasize this, I include "noun" and "verb" as nouns in the grammar
*grammar3*, which is otherwise equivalent to the previous *grammarl*.

``` lisp
(defparameter *grammar3*

'((Sentence -> (NP VP))

(NP -> (Art Noun))

(VP -> (Verb NP))

(Art -> the) (Art -> a)

(Noun -> man) (Noun -> ball) (Noun -> woman) (Noun -> table)

(Noun -> noun) (Noun -> verb)

(Verb -> hit) (Verb -> took) (Verb -> saw) (Verb -> liked)))

(setf *grammar* *grammar3*)
```

I also define the data types rul e, parse, and tree, and some functions for getting

at the rules. Rules are defined as structures of type list with three slots: the left-
hand side, the arrow (which should always be represented as the literal ->) and the
right-hand side. Compare this to the treatment on [page 40](chapter2.md#page-40).

``` lisp
(defstruct (rule (:type list)) Ihs -> rhs)

(defstruct (parse) "A parse tree and a remainder." tree rem)

;; Trees are of the form: (Ihs . rhs)
(defun new-tree (cat rhs) (cons cat rhs))
(defun tree-lhs (tree) (first tree))
(defun tree-rhs (tree) (rest tree))

(defun parse-lhs (parse) (tree-lhs (parse-tree parse)))

(defun lexical-rules (word)
"Return a list of rules with word on the right-hand side."
(find-all word ^grammar* :key #'rule-rhs :test #'equal))

(defun rules-starting-with (cat)
"Return a list of rules where cat starts the rhs."
(find-all cat *grammar*

:key #'(lambda (rule) (first-or-nil (rule-rhs rule)))))

(defun first-or-nil (x)
"The first element of . if it is a list; else nil."
(if (consp X) (first x) nil))
```

Now we're ready to define the parser. The main function parser takes a list of
words to parse. It calls parse, which returns a Ust of all parses that parse some
subsequence of the words, starting at the beginning, parser keeps only the parses
with no remainder - that is, the parses that span all the words.

``` lisp
(defun parser (words)
"Return all complete parses of a list of words."
(mapcar #'parse-tree (complete-parses (parse words))))

(defun complete-parses (parses)
"Those parses that are complete (have no remainder)."
(find-all-if #*null parses :key #*parse-rem))
```

The function parse looks at the first word and considers each category it could be. It
makes a parse of the first word under each category, and calls extend - pa rse to try to
continue to a complete parse, pa rse uses mapcan to append together all the resulting
parses. As an example, suppose we are trying to parse "the man took the ball." pa rse
would find the single lexical rule for "the" and call extend-pa rse with a parse with
tree (Art t he) and remainder "man took the ball," with no more categories needed.

extend-parse has two cases. If the partial parse needs no more categories to be
complete, then it returns the parse itself, along with any parses that can be formed
by extending parses starting with the partial parse. In our example, there is one rule
startingwith Art, namely (NP -> (Art Noun)), so the function would try to extend
theparse tree (NP (Art the)) with remainder "man took the ball," with the category
Noun needed. That call to extend-parse represents the second case. We first parse
"man took the ball," and for every parse that is of category Noun (there will be only
one), we combine with the partial parse. In this case we get (NP (Art the) (Noun
man)). This gets extended as a sentence with a VP needed, and eventually we get a
parse of the complete hst of words.

``` lisp
(defun parse (words)
"Bottom-up parse, returning all parses of any prefix of words."
(unless (null words)

(mapcan #'(lambda (rule)
(extend-parse (rule-lhs rule) (list (first words))
(rest words) nil))
(lexical-rules (first words)))))

(defun extend-parse (Ihs rhs rem needed)
"Look for the categories needed to complete the parse."
(if (null needed)

;; If nothing needed, return parse and upward extensions
(let ((parse (make-parse :tree (new-tree Ihs rhs) :rem rem)))
(cons parse
(mapcan
#.(lambda (rule)

(extend-parse (rule-lhs rule)
(list (parse-tree parse))
rem (rest (rule-rhs rule))))

(rules-starting-with Ihs))))
;; otherwise try to extend rightward
(mapcan
#'(lambda (p)
(if (eq (parse-lhs p) (first needed))
(extend-parse Ihs (appendl rhs (parse-tree p))
(parse-rem p) (rest needed))))

(parse rem))))
```

This makes use of the auxiliary function appendl:

``` lisp
(defun appendl (items item)
"Add item to end of list of items."
(append items (list item)))
```

Some examples of the parser in action are shown here:

``` text
> (parser '(the table))
((NP (ART THE) (NOUN TABLE)))

> (parser '(the ball hit the table))

((SENTENCE (NP (ART THE) (NOUN BALD)

(VP (VERB HIT)

(NP (ARTTHE) (NOUN TABLE)))))

> (parser '(the noun took the verb))
((SENTENCE (NP (ART THE) (NOUN NOUN))
(VP (VERB TOOK)
(NP (ARTTHE) (NOUN VERB)))))
```

### 19.2 Extending the Grammar and Recognizing Ambiguity

Overall, the parser seems to work fine, but the range of sentences we can parse is
quite limited with the current grammar. The following grammar includes a wider
variety of linguistic phenomena: adjectives, prepositional phrases, pronouns, and
proper names. It also uses the usual linguistic conventions for category names,
summarized in the table below:

|      | **Category**                     | **Examples**             |
| ---- | -------------------------------- | ------------------------ |
| S    | Sentence                         | John likes Mary          |
| NP   | Noun Phrase                      | John; a blue table       |
| VP   | Verb Phrase                      | likes Mary; hit the ball |
| PP   | Prepositional Phrase             | to Mary; with the man    |
| ---- | -------------------------------- | ------------------------ |
| A    | Adjective                        | little; blue             |
| A+   | A list of one or more adjectives | little blue              |
| D    | Determiner                       | the; a                   |
| N    | Noun                             | ball; table              |
| Name | Proper Name                      | John; Mary               |
| P    | Preposition                      | to; with                 |
| Pro  | Pronoun                          | you; me                  |
| V    | Verb                             | liked; hit               |

Here is the grammar:

``` lisp
(defparameter *grammar4*

'((S -> (NP VP))
(NP -> (D N))
(NP -> (D A+ N))
(NP -> (NP PP))
(NP -> (Pro))
(NP -> (Name))
(VP -> (V NP))
(VP -> (V))
(VP -> (VP PP))
(PP -> (P NP))
(A+ -> (A))
(A+ -> (A A+))
(Pro -> I) (Pro -> you) (Pro -> he) (Pro -> she)
(Pro -> it) (Pro -> me) (Pro -> him) (Pro -> her)
(Name -> John) (Name -> Mary)
(A -> big) (A -> little) (A -> old) (A -> young)
(A -> blue) (A -> green) (A -> orange) (A -> perspicuous)
(D -> the) (D -> a) (D -> an)
(N -> man) (N -> ball) (N -> woman) (N -> table) (N -> orange)
(N -> saw) (N -> saws) (N -> noun) (N -> verb)
(P -> with) (P -> for) (P -> at) (P -> on) (P -> by) (P -> of) (P -> in)
(V -> hit) (V -> took) (V -> saw) (V -> liked) (V -> saws)))
(setf ^grammar* *grammar4*)
```

Now we can parse more interesting sentences, and we can see a phenomenon that
was not present in the previous examples: ambiguous sentences. The sentence "The
man hit the table with the ball" has two parses, one where the ball is the thing that
hits the table, and the other where the ball is on or near the table, parser finds both
of these parses (although of course it assigns no meaning to either parse):

``` lisp
> (parser '(The man hit the table with the ball))
((S (NP (D THE) (N MAN))
(VP (VP (V HIT) (NP (D THE) (N TABLE)))
(PP (P WITH) (NP (DTHE) (N BALL)))))
(S (NP (D THE) (N MAN))
(VP (V HIT)
(NP (NP (D THE) (N TABLE))
(PP (P WITH) (NP (DTHE) (N BALL)))))))
```

Sentences are not the only category that can be ambiguous, and not all ambiguities
have to be between parses in the same category. Here we see a phrase that is
ambiguous between a sentence and a noun phrase:

``` lisp
> (parser '(the orange saw))
((S (NP (D THE) (N ORANGE)) (VP (V SAW)))
(NP (D THE) (A+ (A ORANGE)) (N SAW)))
```

### 19.3 More Efficient Parsing

With more complex grammars and longer sentences, the parser starts to slow down.
The main problem is that it keeps repeating work. For example, in parsing "The
man hit the table with the ball," it has to reparse "with the ball" for both of the
resulting parses, even though in both cases it receives the same analysis, a PP. We
have seen this problem before and have already produced an answer: memoization
(see section 9.6). To see how much memoization will help, we need a benchmark:

``` text
> (setf s (generate 's))
(THE PERSPICUOUS BIG GREEN BALL BY A BLUE WOMAN WITH A BIG MAN
HIT A TABLE BY THE SAW BY THE GREEN ORANGE)

> (time (length (parser s)))
Evaluation of (LENGTH (PARSER S)) took 33.11 Seconds of elapsed time.
10
```

The sentence S has 10 parses, since there are two ways to parse the subject NP and
five ways to parse the VP. It took 33 seconds to discover these 10 parses with the
pa rse function as it was written.

We can improve this dramatically by memoizing parse (along with the table-
lookup functions). Besides memoizing, the only change is to clear the memoization
table within parser.

``` lisp
(memoize 'lexical-rules)
(memoize *rules-starting-with)
(memoize 'parse -.test #*eq)

(defun parser (words)
"Return all complete parses of a list of words."
(clear-memoize 'parse)
(mapcar #'parse-tree (complete-parses (parse words))))
```

In normal human language use, memoization would not work very well, since the
interpretation of a phrase depends on the context in which the phrase was uttered.
But with context-free grammars we have a guarantee that the context cannot affect the
interpretation. The call (parse words) must return all possible parses for the words.
We are free to choose between the possibilities based on contextual information, but

context can never supply a new interpretation that is not in the context-free list of

parses.

The function use is introduced to tell the table-lookup functions that they are out
of date whenever the grammar changes:

``` lisp
(defun use (grammar)

"Switch to a new grammar."

(clear-memoize 'rules-starting-with)

(clear-memoize 'lexical-rules)

(length (setf *grammar* grammar)))
```

Now we run the benchmark again with the memoized version of pa rse:

``` text
> (time (length (parser s)))

Evaluation of (LENGTH (PARSER S 'S)) took .13 Seconds of elapsed time.

10
```

By memoizing pa rs e we reduce the parse time from 33 to .13 seconds, a 250-fold speedup.
We can get a more systematic comparison by looking at a range of examples.
For example, consider sentences of the form "The man hit the table [with the ball]*"
for zero or more repetitions of the PP "with the ball." In the following table we
record N, the number of repetitions of the PP, along with the number of resulting
parses^, and for both memoized and unmemoized versions of parse, the number
of seconds to produce the parse, the number of parses per second (PPS), and the
number of recursive calls to parse. The performance of the memoized version is
quite acceptable; for N=5, a 20-word sentence is parsed into 132 possibilities in .68
seconds, as opposed to the 20 seconds it takes in the unmemoized version.

^The number of parses of sentences of this kind is the same as the number of bracketings
of a arithmetic expression, or the number of binary trees with a given number of leaves. The
resulting sequence (1,2,5,14,42,...) is known as the Catalan Numbers. This kind of ambiguity
is discussed by Church and Patil (1982) in their articleCoping with Syntactic Ambiguity, or How
to Put the Block in the Box on the Table.

|       |            | **Memoized** |         |           | **Unmemoized** |         |           |
| **N** | **Parses** | **Sees**     | **PPS** | **Calls** | **Sees**       | **PPS** | **Calls** |
| ----- | ---------- | ------------ | ------- | --------- | -------------- | ------- | --------- |
| 0     | 1          | 0.02         | 60      | 4         | 0.02           | 60      | 17        |
| 1     | 2          | 0.02         | 120     | 11        | 0.07           | 30      | 96        |
| 2     | 5          | 0.05         | 100     | 21        | 0.23           | 21      | 381       |
| 3     | 14         | 0.10         | 140     | 34        | 0.85           | 16      | 1388      |
| 4     | 42         | 0.23         | 180     | 50        | 3.17           | 13      | 4999      |
| 5     | 132        | 0.68         | 193     | 69        | 20.77          | 6       | 18174     |
| 6     | 429        | 1.92         | 224     | 91        | -              |         |           |
| 7     | 1430       | 5.80         | 247     | 116       | -              |         |           |
| 8     | 4862       | 20.47        | 238     | 144       | -              |         |           |

▣ **Exercise 19.1 Pi]** It seems that we could be more efficient still by memoizing with
a table consisting of a vector whose length is the number of words in the input (plus
one). Implement this approach and see if it entails less overhead than the more
general hash table approach.

### 19.4 The Unknown-Word Problem

As it stands, the parser cannot deal with unknown words. Any sentence containing
a word that is not in the grammar will be rejected, even if the program can parse all
the rest of the words perfectly. One way of treating unknown words is to allow them
to be any of the "open-class" categories - nouns, verbs, adjectives, and names, in our
grammar. An unknown word will not be considered as one of the "closed-class"
categories - prepositions, determiners, or pronouns. This can be programmed very
simply by having 1 exi ca 1 - rul es return a list of these open-class rules for every word
that is not already known.

``` lisp
(defparameter *open-categories* '(NVA Name)
"Categories to consider for unknown words")

(defun lexical-rules (word)
"Return a list of rules with word on the right-hand side."
(or (find-all word *grammar* :key #'rule-rhs :test #'equal)

(mapcar #'(lambda (cat) '(.cat -> .word)) *open-categories*)))
```

With memoization of 1 exi cal - rul es, this means that the lexicon is expanded every
time an unknown word is encountered. Let's try this out:

``` text
> (parser '(John liked Mary))
((S (NP (NAME JOHN))
(VP (V LIKED) (NP (NAME MARY)))))

<a id='page-665'></a>

> (parser '(Dana liked Dale))
((S (NP (NAME DANA))
(VP (V LIKED) (NP (NAME DALE)))))

> (parser '(the rab zaggled the woogly quax))
((S (NP (D THE) (N RAB))
(VP (V ZAGGLED) (NP (D THE) (A+ (A WOOGLY)) (N QUAX)))))
```

We see the parser works as well with words it knows (John and Mary) as with new
words (Dana and Dale), which it can recognize as names because of their position
in the sentence. In the last sentence in the example, it recognizes each unknown
word unambiguously. Things are not always so straightforward, unfortunately, as
the following examples show:

``` text
> (parser '(the slithy toves gymbled))

((S (NP (D THE) (N SLITHY)) (VP (V TOVES) (NP (NAME GYMBLED))))
(S (NP (D THE) (A+ (A SLITHY)) (N TOVES)) (VP (V GYMBLED)))
(NP (D THE) (A+ (A SLITHY) (A+ (A TOVES))) (N GYMBLED)))

> (parser '(the slithy toves gymbled on the wabe))
((S (NP (D THE) (N SLITHY))
(VP (VP (V TOVES) (NP (NAME GYMBLED)))
(PP (P ON) (NP (D THE) (N WABE)))))
(S (NP (D THE) (N SLITHY))
(VP (V TOVES) (NP (NP (NAME GYMBLED))
(PP (P ON) (NP (D THE) (N WABE))))))
(S (NP (D THE) (A+ (A SLITHY)) (N TOVES))
(VP (VP (V GYMBLED)) (PP (P ON) (NP (D THE) (N WABE)))))
(NP (NP (D THE) (A+ (A SLITHY) (A+ (A TOVES))) (N GYMBLED))
(PP (P ON) (NP (D THE) (N WABE)))))
```

If the program knew morphology - that a y at the end of a word often signals an
adjective, an s a plural noun, and an ed a past-tense verb - then it could do much
better.

### 19.5 Parsing into a Semantic Representation

Syntactic parse trees of a sentence may be interesting, but by themselves they're not
very useful. We use sentences to communicate ideas, not to display grammatical
structures. To explore the idea of the semantics, or meaning, of a phrase, we need
a domain to talk about. Imagine the scenario of a compact disc player capable of
playing back selected songs based on their track number. Imagine further that this
machine has buttons on the front panel indicating numbers, as well as words such as
"play," "to," "and," and "without." If you then punch in the sequence of buttons "play

1 to 5 without 3/' you could reasonably expect the machine to respond by playing
tracks 1,2,4, and 5. After a few such successful interactions, you might say that the
machine "understands" a limited language. The important point is that the utility of
this machine would not be enhanced much if it happened to display a parse tree of
the input. On the other hand, you would be justifiably annoyed if it responded to
"play 1 to 5 without 3" by playing 3 or skipping 4.

Now let's stretch the imagination one more time by assuming that this CD player
comes equipped with a full Common Lisp compiler, and that we are now in charge
of writing the parser for its input language. Let's first consider the relevant data
structures. We need to add a component for the semantics to both the rule and tree
structures. Once we've done that, it is clear that trees are nothing more than instances
of rules, so their definitions should reflect that. Thus, I use an : 1nc1 ude defstruct
to define trees, and I specify no copier function, because copy-tree is already a
Common Lisp function, and I don't want to redefine it. To maintain consistency
with the old new-tree function (and to avoid having to put in all those keywords) I
definetheconstructor new-tree. Thisoptiontodefstructmakes (new-tree a b c)
equivalent to (make-tree :lhs a :sem b :rhsc).

``` lisp
(defstruct (rule (itype list))
Ihs -> rhs sem)

(defstruct (tree (:type list) (:include rule) (rcopiernil)
(:constructor new-tree (Ihs sem rhs))))
```

We will adopt the convention that the semantics of a word can be any Lisp object. For
example, the semantics of the word "1" could be the object 1, and the semantics of
"without" could be the function set-di ff erence. The semantics of a tree is formed
by taking the semantics of the rule that generated the tree and applying it (as a
function) to the semantics of the constituents of the tree. Thus, the grammar writer
must insure that the semantic component of rules are functions that expect the right
number of arguments. For example, given the rule

``` lisp
(NP -> (NP CONJ NP) infix-funcall)
```

then the semantics of the phrase "1 to 5 without 3" could be determined by first deter-
miningthesemanticsof"lto5"tobe(l 2 3 4 5),of"without"tobeset -difference,
and of "3" to be (3). After these sub-constituents are determined, the rule is applied
by calling the function infix-funcall with the three arguments (1 2 3 4 5),
set-difference, and (3). Assuming that infix-funcall is defined to apply its
second argument to the other two arguments, the result will be (1 2 4 5).

This may make more sense if we look at a complete grammar for the CD player
problem:

``` lisp
(use

'((NP -> (NP CONJ NP) infix-funcall)
(NP -> (N) list)
(NP -> (N . .) infix-funcall)
(. -> (DIGIT) identity)
(P -> to integers)
(CONJ -> and union)
(CONJ -> without set-difference)
(N -> 1 1) (N -> 2 2) (N -> 3 3) (N -> 4 4) (N -> 5 5)
(N -> 6 6) (N -> 7 7) (N -> 8 8) (N -> 9 9) (N -> 0 0)))

(defun integers (start end)
"A list of all the integers in the range [start...end] inclusive."
(if (> start end) nil

(cons start (integers (+ start 1) end))))

(defun infix-funcall (argl function arg2)
"Apply the function to the two arguments"
(funcall function argl arg2))
```

Consider the first three grammar rules, which are the only nonlexical rules. The first
says that when two NPs are joined by a conjunction, we assume the translation of
the conjunction will be a function, and the translation of the phrase as a whole is
derived by calling that function with the translations of the two NPs as arguments.
The second rule says that a single noun (whose translation should be a number)
translates into the singleton list consisting of that number. The third rule is similar
to the first, but concerns joining Ns rather than NPs. The overall intent is that the
translation of an NP will always be a list of integers, representing the songs to play.

As for the lexical rules, the conjunction "and" translates to the union function,
"without" translates to the function that subtracts one set from another, and "to"
translates to the function that generates a list of integers between two end points.
The numbers "0" to "9" translate to themselves. Note that both lexical rules like
"CONJ -> and" and nonlexical rules like "NP -> (N . .)" can have functions as
their semantic translations; in the first case, the function will just be returned as the
semantic translation, whereas in the second case the function will be applied to the
list of constituents.

Only minor changes are needed to par s e to support this kind of semantic processing.
As we see in the following, we add a sem argument to extend - pa r se and arrange
to pass the semantic components around properly. When we have gathered all the
right-hand-side components, we actually do the function application. All changes
are marked with We adopt the convention that the semantic value .i 1 indicates
failure, and we discard all such parses.

``` lisp
(defun parse (words)
"Bottom-up parse, returning all parses of any prefix of words.
This version has semantics."
(unless (null words)

(mapcan #'(lambda (rule)
(extend-parse (rule-lhs rule) (rule-sem rule)
(list (first words)) (rest words) nil))
(lexical-rules (first words)))))

(defun extend-parse (Ihs sem rhs rem needed)
"Look for the categories needed to complete the parse.
This version has semantics."
(if (null needed)

;; If nothing is needed, return this parse and upward extensions,
;; unless the semantics fails
(let ((parse (make-parse rtree (new-tree Ihs sem rhs) :rem rem)))

(unless (null (apply-semantics (parse-tree parse)))
(cons parse
(mapcan
#'(lambda (rule)

(extend-parse (rule-lhs rule) (rule-semrule)
(list (parse-tree parse)) rem
(rest (rule-rhs rule))))

(rules-starting-with Ihs)))))
;; otherwise try to extend rightward
(mapcan

#*(lambda (p)
(if (eq (parse-lhs p) (first needed))
(extend-parse Ihs sem (appendl rhs (parse-tree p))
(parse-rem p) (rest needed))))

(parse rem))))
```

We need to add some new functions to support this:

``` lisp
(defun apply-semantics (tree)
"For terminal nodes, just fetch the semantics.
Otherwise, apply the sem function to its constituents."
(if (terminal-tree-p tree)
(tree-sem tree)
(setf (tree-sem tree)
(apply (tree-sem tree)
(mapcar #'tree-sem (tree-rhs tree))))))

(defun terminal-tree-p (tree)
"Does this tree have a single word on the rhs?"
(and (length=1 (tree-rhs tree))

(atom (first (tree-rhs tree)))))
```

``` lisp
(defun meanings (words)
"Return all possible meanings of a phrase. Throw away the syntactic part."
(remove-duplicates (mapcar #'tree-sem (parser words)) :test #'equal))
```

Here are some examples of the meanings that the parser can extract:

``` text
> (meanings '(1 to 5 without 3))
((1 2 4 5))

> (meanings '(1 to 4 and 7 to 9))
((123478 9))

> (meanings '(1 to 6 without 3 and 4))
((12 4 5 6)
(1 2 5 6))
```

The example "(1 to 6 without 3 and 4)" is ambiguous. The first reading corresponds
to "((1 to 6) without 3) and 4/' while the second corresponds to "(1 to 6)
without (3 and 4)." The syntactic ambiguity leads to a semantic ambiguity - the two
meanings have different lists of numbers in them. However, it seems that the second
reading is somehow better, in that it doesn't make a lot of sense to talk of adding 4 to
a set that already includes it, which is what the first translation does.

We can upgrade the lexicon to account for this. The following lexicon insists
that "and" conjoins disjoint sets and that "without" removes only elements that were
already in the first argument. If these conditions do not hold, then the translation
will return nil, and the parse will fail. Note that this also means that an empty list,
such as "3 to 2," will also fail.

The previous grammar only allowed for the numbers 0 to 9. We can allow larger
numbers by stringing together digits. So now we have two rules for numbers: a
number is either a single digit, in which case the value is the digit itself (the i dent i ty
function), or it is a number followed by another digit, in which case the value is 10
times the number plus the digit. We could alternately have specified a number to be
a digit followed by a number, or even a number followed by a number, but either of
those formulations would require a more complex semantic interpretation.

``` lisp
(use

'((NP -> (NP CONJ NP) infix-funcall)
(NP -> (N) list)
(NP -> (N . .) infix-funcall)
(. -> (DIGIT) identity)
(N -> (N DIGIT) 10*N+D)
(P -> to integers)
(CONJ -> and union*)
(CONJ -> without set-diff)
(DIGIT -> 1 1) (DIGIT -> 2 2) (DIGIT -> 3 3)
```

``` lisp
(DIGIT -> 4 4) (DIGIT -> 5 5) (DIGIT -> 6 6)
(DIGIT -> 7 7) (DIGIT -> 8 8) (DIGIT -> 9 9)
(DIGIT -> 0 0)))

(defun union* (x y) (if (null (intersection . y)) (append . y)))
(defun set-diff (. y) (if (subsetp y .) (set-difference . y)))
(defun 10*N-^D (N D) (+ (* 10 N) D))
```

With this new grammar, we can get single interpretations out of most reasonable
inputs:

``` text
> (meanings '(1 to 6 without 3 and 4))
((1 2 5 6))

> (meanings '(1 and 3 to 7 and 9 without 5 and 6))
((13 4 7 9))

> (meanings '(1 and 3 to 7 and 9 without 5 and 2))
((134679 2))

> (meanings '(1 9 8 to 2 0 D)
((198 199 200 201))

> (meanings '(1 2 3))
(123 (123))
```

The example "1 2 3" shows an ambiguity between the number 123 and the list (123),
but all the others are unambiguous.

### 19.6 Parsing with Preferences

One reason we have unambiguous interpretations is that we have a very limited
domain of interpretation: we are dealing with sets of numbers, not lists. This is
perhaps typical of the requests faced by a CD player, but it does not account for
all desired input. For example, if you had a favorite song, you couldn't hear it
three times with the request "1 and 1 and 1" under this grammar. We need some
compromise between the permissive grammar, which generated all possible parses,
and the restrictive grammar, which eliminates too many parses. To get the "best"
interpretation out of an arbitrary input, we will not only need a new grammar, we
will also need to modify the program to compare the relative worth of candidate
interpretations. In other words, we will assign each interpretation a numeric score,
and then pick the interpretation with the highest score.

We start by once again modifying the rule and tree data types to include a score
component. As with the sem component, this will be used to hold first a function to
compute a score and then eventually the score itself.

``` lisp
(defstruct (rule (:type list)
(:constructor
rule (Ihs -> rhs &optional sem score)))
Ihs -> rhs sem score)

(defstruct (tree (itype list) (rinclude rule) (:copiernil)
(:constructor new-tree (Ihs sem score rhs))))
```

Note that we have added the constructor function rul e. The intent is that the sem
and score component of grammar rules should be optional. The user does not have
to supply them, but the function use will make sure that the function rul e is called
to fill in the missing sem and score values with ni 1.

``` lisp
(defun use (grammar)
"Switch to a new grammar."
(clear-memoize 'rules-starting-with)
(clear-memoize 'lexical-rules)
(length (setf *grammar*

(mapcar #'(lambda (r) (apply #'rule r))
grammar))))
```

Now we modify the parser to keep track of the score. The changes are again minor,
and mirror the changes needed to add semantics. There are two places where we
put the score into trees as we create them, and one place where we apply the scoring
function to its arguments.

``` lisp
(defun parse (words)
"Bottom-up parse, returning all parses of any prefix of words.
This version has semantics and preference scores."
(unless (null words)

(mapcan #'(lambda (rule)

(extend-parse
(rule-lhs rule) (rule-sem rule)
(rule-score rule) (list (first words))
(rest words) nil))

(lexical-rules (first words)))))

(defun extend-parse (Ihs sem score rhs rem needed)
"Look for the categories needed to complete the parse.
This version has semantics and preference scores."
(if (null needed)

If nothing is needed, return this parse and upward extensions,
;; unless the semantics fails
(let ((parse (make-parse :tree (new-tree Ihs sem score rhs)

:rem rem)))
(unless (null (apply-semantics (parse-tree parse)))
```

``` lisp
(apply-scorer (parse-tree parse))
(cons parse
(mapcan
#'(lambda (rule)

(extend-parse
(rule-lhs rule) (rule-sem rule)
(rule-score rule) (list (parse-tree parse))
rem (rest (rule-rhs rule))))

(rules-starting-with Ihs)))))
otherwise try to extend rightward
(mapcan
#*(lambda (p)
(if (eq (parse-lhs p) (first needed))

(extend-parse Ihs sem score
(appendl rhs (parse-tree p))
(parse-rem p) (rest needed))))

(parse rem))))
```

Again we need some new functions to support this. Most important is appl y - scorer,
which computes the score for a tree. If the tree is a terminal (a word), then the function
just looks up the score associated with that word. In this grammar all words have
a score of 0, but in a grammar with ambiguous words it would be a good idea to
give lower scores for infrequently used senses of ambiguous words. If the tree is
a nonterminal, then the score is computed in two steps. First, all the scores of the
constituents of the tree are added up. Then, this is added to a measure for the tree
as a whole. The rule associated with each tree will have either a number attached to
it, which is added to the sum, or a function. In the latter case, the function is applied
to the tree, and the result is added to obtain the final score. Asa final special case, if
the function returns nil, then we assume it meant to return zero. This will simplify
the definition of some of the scoring functions.

``` lisp
(defun apply-scorer (tree)
"Compute the score for this tree."
(let ((score (or (tree-score tree) 0)))

(setf (tree-score tree)
(if (terminal-tree-p tree)
score

Add up the constituent's scores,
;; along with the tree's score
(+ (sum (tree-rhs tree) #'tree-score-or-0)

(if (numberp score)
score

(or (apply score (tree-rhs tree)) 0)))))))
```

Here is an accessor function to pick out the score from a tree:

``` lisp
(defun tree-score-or-O (tree)

(if (numberp (tree-score tree))
(tree-score tree)
0))
```

Here is the updated grammar. First, I couldn't resist the chance to add more features
to the grammar. I added the postnominal adjectives "shuffled," which randomly
permutes the list of songs, and "reversed," which reverses the order of play. I also
added the operator "repeat," as in "1 to 3 repeat 5," which repeats a list a certain
number of times. 1 also added brackets to allow input that says explicitly how it
should be parsed.

``` lisp
(use

'((NP -> (NP CONJ NP) infix-funcall infix-scorer)
(NP -> (N . .) infix-funcall infix-scorer)
(NP -> (.) list)
(NP ([ NP ]) arg2)
(NP (NP ADJ) rev-funcal1 rev-scorer)
(NP -> (NP OP N) infix-funcall)
(N -> (D) identity)
(N (N D) 10*N+D)
(P -> to integers prefer<)

([ -> [ [)
(] -> ] ])
(OP -> repeat repeat)
(CONJ -> and append prefer-disjoint)
(CONJ -> without set-difference prefer-subset)
(ADJ -> reversed reverse inv-span)
(ADJ -> shuffled permute prefer-not-singleton)
(D -> 1 1) (D -> 2 2) (D -> 3 3) (D -> 4 4) (D -> 5 5)
(D -> 6 6) (D -> 7 7) (D -> 8 8) (D -> 9 9) (D -> 0 0)))
```

The following scoring functions take trees as inputs and compute bonuses or penalties
for those trees. The scoring function pref er<, used for the word "to," gives a
one-point penalty for reversed ranges: "5 to 1" gets a score of -1, while "1 to 5" gets
a score of 0. The scorer for "and," prefer-di s joi nt, gives a one-point penalty for
intersecting lists: "1 to 3 and 7 to 9" gets a score of 0, while "1 to 4 and 2 to 5" gets -1.
The "x without y" scorer, prefer-subset, gives a three-point penalty when the y list
has elements that aren't in the . list. It also awards points in inverse proportion to the
length (in words) of the . phrase. The idea is that we should prefer to bind "without"
tightly to some small expression on the left. If the final scores come out as positive
or as nonintegers, then this scoring component is responsible, since all the other
components are negative intgers. The "x shuffled" scorer, prefer-not-singleton,
is similar, except that there the penalty is for shuffling a list of less than two songs.

``` lisp
(defun prefer< (x y)
(if (>= (sem X) (sem y)) -1))

(defun prefer-disjoint (x y)
(if (intersection (sem x) (sem y)) -1))

(defun prefer-subset (x y)
(+ (inv-span x) (if (subsetp (sem y) (sem x)) 0 -3)))

(defun prefer-not-singleton (x)
(+ (inv-span x) (if (< (length (sem x)) 2) -4 0)))

The inf i x-scorer and rev-scorer functionsdon'taddanythingnew,theyjustassure
that the previously mentioned scoring functions will get applied in the right place.

(defun infix-scorer (argl scorer arg2)
(funcall (tree-score scorer) argl arg2))

(defun rev-scorer (arg scorer) (funcall (tree-score scorer) arg))
```

Here are the functions mentioned in the grammar, along with some useful utilities:

``` lisp
(defun arg2 (al a2 &rest a-n) (declare (ignore al a-n)) a2)

(defun rev-funcall (arg function) (funcall function arg))

(defun repeat (list n)
"Append list . times."
(if (= . 0)

nil
(append list (repeat list (- . 1)))))

(defun span-length (tree)
"How many words are in tree?"
(if (terminal-tree-p tree) 1

(sum (tree-rhs tree) #'span-length)))

(defun inv-span (tree) (/ 1 (span-length tree)))

(defun sem (tree) (tree-sem tree))

(defun integers (start end)
"A list of all the integers in the range [start...end]inclusive.
This version allows start > end."
(cond ((< start end) (cons start (integers (+ start 1) end)))

((> start end) (cons start (integers (- start 1) end)))
(t (list start))))

(defun sum (numbers &optional fn)
"Sum the numbers, or sum (mapcar fn numbers)."
(if fn

(loop for X in numbers sum (funcall fn x))
(loop for X in numbers sum x)))
```

``` lisp
(defun permute (bag)
"Return a random permutation of the given input list. "
(if (null bag)

nil
(let ((e (random-elt bag)))
(cons e (permute (remove e bag rcount 1 :test #*eq))))))

We will need a way to show off the preference rankings:

(defun all-parses (words)
(format t "~%Score Semantics^ZBT^a" words)
(format t "~% = --251 -~%")
(loop for tree in (sort (parser words) #*> :key#'tree-score)

do (format t "~5,lf ~9a~25T''a~%" (tree-score tree) (tree-sem tree)
(bracketing tree)))
(values))

(defun bracketing (tree)
"Extract the terminals, bracketed with parens."
(cond ((atom tree) tree)

((length=1 (tree-rhs tree))
(bracketing (first (tree-rhs tree))))
(t (mapcar #'bracketing (tree-rhs tree)))))
```

Now we can try some examples:

``` text
> (all-parses '(1 to 6 without 3 and 4))
Score Semantics (1 TO 6 WITHOUT 3 AND 4)

0.3 (1 2 5 6) ((1 TO 6) WITHOUT (3 AND 4))
-0.7 (1 2 4 5 6 4) (((1 TO 6) WITHOUT 3) AND 4)
> (all -parses '(1 and 3 to 7 and 9 without 5 and 6))
Score Semantics (1 AND 3 TO 7 AND 9 WITHOUT 5 AND 6)

0.2 (1 3 4 7 9) (1 AND (((3 TO 7) AND 9) WITHOUT (5 AND 6)))
0.1 (1 3 4 7 9) (((1 AND (3 TO 7)) AND 9) WITHOUT (5 AND 6))
0.1 (1 3 4 7 9) ((1 AND ((3 TO 7) AND 9)) WITHOUT (5 AND 6))
-0.8 (1 3 4 6 7 9 6) ((1 AND (((3 TO 7) AND 9) WITHOUT 5)) AND 6)
-0.8 (1 3 4 6 7 9 6) (1 AND ((((3 TO 7) AND 9) WITHOUT 5) AND 6))
-0.9 (1 3 4 6 7 9 6) ((((1 AND (3 TO 7)) AND 9) WITHOUT 5) AND 6)
-0.9 (1 3 4 6 7 9 6) (((1 AND ((3 TO 7) AND 9)) WITHOUT 5) AND 6)
-2.0 (1 3 4 5 6 7 9) ((1 AND (3 TO 7)) AND (9 WITHOUT (5 AND 6)))
-2.0 (1 3 4 5 6 7 9) (1 AND ((3 TO 7) AND (9 WITHOUT (5 AND 6))))
-3.0 (1 3 4 5 6 7 9 6) (((1 AND (3 TO 7)) AND (9 WITHOUT 5)) AND 6)
-3.0 (1 3 4 5 6 7 9 6) ((1 AND (3 TO 7)) AND ((9 WITHOUT 5) AND 6))
-3.0 (1 3 4 5 6 7 9 6) ((1 AND ((3 TO 7) AND (9 WITHOUT 5))) AND 6)
<a id='page-676'></a>

-3.0 (1 3 4 5 6 7 9 6) (1 AND (((3 TO 7) AND (9 WITHOUT 5)) AND 6))
-3.0 (13 4 5 6 7 9 6) (1 AND ((3 TO 7) AND ((9 WITHOUT 5) AND 6)))

> (all -parses '(1 and 3 :o 7 and 9 without 5 and 2))
Score Semantics (1 AND 3 TO 7 AND 9 WITHOUT 5 AND 2)

0.2 (1 3 4 6 7 9 2) ((1 AND (((3 TO 7) AND 9) WITHOUT 5)) AND 2)
0.2 (1 3 4 6 7 9 2) (1 AND ((((3 TO 7) AND 9) WITHOUT 5) AND 2))
0.1 (1 3 4 6 7 9 2) ((((1 AND (3 TO 7)) AND 9) WITHOUT 5) AND 2)
0.1 (1 3 4 6 7 9 2) (((1 AND ((3 TO 7) AND 9)) WITHOUT 5) AND 2)
-2.0 (1 3 4 5 6 7 9 2) (((1 AND (3 TO 7)) AND (9 WITHOUT 5)) AND 2)
-2.0 (1 3 4 5 6 7 9 2) ((1 AND (3 TO 7)) AND ((9 WITHOUT 5) AND 2))
-2.0 (1 3 4 5 6 7 9) ((1 AND (3 TO 7)) AND (9 WITHOUT (5 AND 2)))
-2.0 (1 3 4 5 6 7 9 2) ((1 AND ((3 TO 7) AND (9 WITHOUT 5))) AND 2)
-2.0 (1 3 4 5 6 7 9 2) (1 AND (((3 TO 7) AND (9 WITHOUT 5)) AND 2))
-2.0 (1 3 4 5 6 7 9 2) (1 AND ((3 TO 7) AND ((9 WITHOUT 5) AND 2)))
-2.0 (1 3 4 5 6 7 9) (1 AND ((3 TO 7) AND (9 WITHOUT (5 AND 2))))
-2.8 (1 3 4 6 7 9) (1 AND (((3 TO 7) AND 9) WITHOUT (5 AND 2)))
-2.9 (1 3 4 6 7 9) (((1 AND (3 TO 7)) AND 9) WITHOUT (5 AND 2))
-2.9 (1 3 4 6 7 9) ((1 AND ((3 TO 7) AND 9)) WITHOUT (5 AND 2))
```

In each case, the preference rules are able to assign higher scores to more reasonable
interpretations. It turns out that, in each case, all the interpretations with positive
scores represent the same set of numbers, while interpretations with negative scores
seem worse. Seeing all the scores in gory detail may be of academic interest, but what
we really want is something to pick out the best interpretation. The following code
is appropriate for many situations. It picks the top scorer, if there is a unique one,
or queries the user if several interpretations tie for the best score, and it complains
if there are no valid parses at all. The query-user function may be useful in many
applications, but note that meani ng uses it only as a default; a program that had some
automatic way of deciding could supply another ti e-breaker function to meani ng.

``` lisp
(defun meaning (words &optional (tie-breaker #'query-user))
"Choose the single top-ranking meaning for the words."
(let* ((trees (sort (parser words) #*> :key #'tree-score))

(best-score (if trees (tree-score (first trees)) 0))
(best-trees (delete best-score trees
:key #*tree-score :test-not #'eql))
(best-sems (delete-duplicates (mapcar #'tree-sem best-trees)
.-test #'equal)))

(case (length best-sems)
(0 (format t "~&Sorry. I didn't understand that.") nil)
(1 (first best-sems))
(t (funcall tie-breaker best-sems)))))
```

``` lisp
(defun query-user (choices &optiona1
(header-str "~&Please pick one:")
(footer-str "~&Your choice? "))

"Ask user to make a choice."
(format *query-io* header-str)
(loop for choice in choices for i from 1 do

(format *query-io* "~&~3d: ~a" i choice))
(format *query-io* footer-str)
(nth (- (read) 1) choices))
```

Here we see some final examples:

``` text
> (meaning '(1 to 5 without 3 and 4))
(1 2 5)

> (meaning '(1 to 5 without 3 and 6))
(12 4 5 6)

> (meaning '(1 to 5 without 3 and 6 shuffled))
(64125)

> (meaning '([ 1 to 5 without C 3 and 6 ] ] reversed))
(5 4 2 1)

> (meaning '(1 to 5 to 9))

Sorry. I didn't understand that.
NIL

> (meaning '(1 to 5 without 3 and 7 repeat 2))
Please pick one:

1: (12 4 5 7 12 4 5 7)
2: (12 4 5 7 7)
Your choice? 1
(12 4 5 7 12 4 5 7)

> (all-parses '(1 to 5 without 3 and 7 repeat 2))
Score Semantics (1 TO 5 WITHOUT 3 AND 7 REPEAT 2)

0.3 (12 4 5 7 12 4 5 7) ((((1 TO 5) WITHOUT 3) AND 7) REPEAT 2)
0.3 (12 4 5 7 7) (((1 TO 5) WITHOUT 3) AND (7 REPEAT 2))
-2.7 (12 4 5 12 4 5) (((1 TO 5) WITHOUT (3 AND 7)) REPEAT 2)
-2.7 (12 4 5) ((1 TO 5) WITHOUT ((3 AND 7) REPEAT 2))
-2.7 (12 4 5) ((1 TO 5) WITHOUT (3 AND (7 REPEAT 2)))
```

This last example points out a potential problem: I wasn't sure what was a good
scoring function for "repeat," so I left it blank, it defaulted to 0, and we end up
with two parses with the same score. This example suggests that "repeat" should
probably involve inv-span like the other modifiers, but perhaps other factors should
be involved as well. There can be a complicated interplay between phrases, and it

is not always clear where to assign the score. For example, it doesn't make much
sense to repeat a "without" phrase; that is, the bracketing (. without (y repeat
.)) is probably a bad one. But the scorer for "without" nearly handles that already.
It assigns a penalty if its right argument is not a subset of its left. Unfortunately,
repeated elements are not counted in sets, so for example, the list (1 2 3 1 2 3) is a
subset of (1 2 3 4). However, we could change the scorer for "without" to test for
sub-bag-. (not a built-in Common Lisp function) instead, and then "repeat" would
not have to be concerned with that case.

### 19.7 The Problem with Context-Free Phrase-Structure Rules

The fragment of English grammar we specified in section 19.2 admits a variety of
ungrammatical phrases. For example, it is equally happy with both "I liked her" and
"me liked she." Only the first of these should be accepted; the second should be
ruled out. Similarly, our grammar does not state that verbs have to agree with their
subjects in person and number. And, since the grammar has no notion of meaning,
it will accept sentences that are semantically anomalous (or at least unusual), such
as "the table liked the man."

There are also some technical problems with context-free grammars. For example,
it can be shown that no context-free grammar can be written to account for the
language consisting of just the strings ABC, AABBCC, AAABBBCCC, and so forth,
where each string has an equal number of As, Bs, and Cs. Yet sentences roughly of
that form show up (admittedly rarely) in natural languages. An example is "Robin
and Sandy loved and hated Pat and Kim, respectively." While there is still disagreement
over whether it is possible to generate natural languages with a context-free
grammar, clearly it is much easier to use a more powerful grammatical formalism.
For example, consider solving the subject-predicate agreement problem. It is possible
to do this with a context-free language including categories like singular-NP,
plural-NP, singular-VP, and plural-VP, but it is far easier to augment the grammatical
formahsm to allow passing features between constituents.

It should be noted that context-free phrase-structure rules turned out to be very
useful for describing programming languages. Starting with Algol 60, the formalism
has been used under the name Bflcfcus-Nflwr Form (BNF) by computer scientists. In this
book we are more interested in natural languages, so in the next chapter we will see a
more powerful formalism known as unification grammar that can handle the problem
of agreement, as well as other difficulties. Furthermore, unification grammars allow a
natural way of attaching semantics to a parse.

### 19.8 History and References

There is a class of parsing algorithms known as chart parsers that explicitly cache
partial parses and reuse them in constructing larger parses. Barley's algorithm (1970)
is the first example, and Martin Kay (1980) gives a good overview of the field and
introduces a data structure, the chart, for storing substrings of a parse. Winograd
(1983) gives a complex (five-page) specification of a chart parser. None of these
authors have noticed that one can achieve the same results by augmenting a simple
(one-page) parser with memoization. In fact, it is possible to write a top-down parser
that is even more succinct. (See exercise 19.3 below.)

For a general overview of natural language processing, my preferences (in order)
are Allen 1987, Winograd 1983 or Gazdar and Mellish 1989.

### 19.9 Exercises

▣ **Exercise 19.2 [m-h]** Experiment with the grammar and the parser. Find sentences
it cannot parse correctly, and try to add new syntactic rules to account for them.

▣ **Exercise 19.3 [m-h]** The parser works in a bottom-up fashion. Write a top-down
parser, and compare it to the bottom-up version. Can both parsers work with the
same grammar? If not, what constraints on the grammar does each parsing strategy
impose?

▣ **Exercise 19.4 [h]** Imagine an interface to a dual cassette deck. Whereas the CD
player had one assumed verb, "play," this unit has three explicit verb forms: "record,"
"play," and "erase." There should also be modifiers "from" and "to," where the object
of a "to" is either 1 or 2, indicating which cassette to use, and the object of a "from"
is either 1 or 2, or one of the symbols PHONO, CD, or AUX. It's up to you to design
the grammar, but you should allow input something like the following, where I have
chosen to generate actual Lisp code as the meaning:

``` text
> (meaning '(play 1 to 5 from CD shuffled and
record 1 to 5 from CD and 1 and 3 and 7 from 1))

(PROGN (PLAY '(15 2 3 4) :FROM 'CD)
(RECORD '(12345) :FROM 'CD)
(RECORD '(1 3 7) :FROM .))
```

This assumes that the functions play and record take keyword arguments (with
defaults) for : from and : to. You could also extend the grammar to accommodate an
automatic timer, with phrases like "at 3:00."

▣ **Exercise 19.5 [m]** In the definition of permute, repeated here, why is the :test
#'eq needed?

``` lisp
(defun permute (bag)
"Return a random permutation of the given input list. "
(if (null bag)

nil
(let ((e (random-elt bag)))
(cons e (permute (remove e bag :count 1 :test #'eq))))))
```

▣ **Exercise 19.6 [m]** The definition of permute takes 0{n^). Replace it by an 0 (n)
algorithm.

### 19.10 Answers

**Answer 19.1**

``` lisp
(defun parser (words)
"Return all complete parses of a list of words."
(let* ((table (make-array (+ (length words) 1) :initial-element 0))

(parses (parse words (length words) table)))
(mapcar #'parse-tree (complete-parses parses))))

(defun parse (words num-words table)
"Bottom-up parse, returning all parses of any prefix of words."
(unless (null words)

(let ((ans (aref table num-words)))

(if (not (eq ans 0))
ans
(setf (aref table num-words)

(mapcan #*(lambda (rule)

(extend-parse (rule-lhs rule)
(list (firstwords))
(rest words) nil
(- num-words 1) table))

(lexical-rules (first words))))))))
```

``` lisp
(defun extend-parse (Ihs rhs rem needed num-words table)
"Look for the categories needed to complete the parse."
(if (null needed)

If nothing is needed, return this parse and upward extensions
(let ((parse (make-parse :tree (new-tree Ihs rhs) :rem rem)))
(cons parse
(mapcan
#*(lambda (rule)

(extend-parse (rule-lhs rule)
(list (parse-tree parse))
rem (rest (rule-rhs rule))
num-words table))

(rules-starting-with Ihs))))
otherwise try to extend rightward
(mapcan
#'(lambda (p)
(if (eq (parse-lhs p) (first needed))

(extend-parse Ihs (appendl rhs (parse-tree p))
(parse-rem p) (rest needed)
(length (parse-rem p)) table)))

(parse rem num-words table))))
```

It turns out that, for the Lisp system used in the timings above, this version is no
faster than normal memoization.

**Answer 19.3** Actually, the top-down parser is a little easier (shorter) than the

bottom-up version. The problem is that the most straightforward way of imple

menting a top-down parser does not handle so-called left recursive rules - rules of the

form(X -> (X ...)). This includes rules we've used, like (NP -> (NP and NP)).

The problem is that the parser will postulate an NP, and then postulate that it is of

the form (NP and NP), and that the first NP of that expression is of the form (NP and

NP), and so on. An infinite structure of NPs is explored before even the first word is

considered.

Bottom-up parsers are stymied by rules with null right-hand sides: (X -> ()) .
Note that I was careful to exclude such rules in my grammars earlier.

``` lisp
(defun parser (words &optional (cat *S))
"Parse a list of words; return only parses with no remainder."
(mapcar #*parse-tree (complete-parses (parse words cat))))

(defun parse (tokens start-symbol)
"Parse a list of tokens, return parse trees and remainders."
(if (eq (first tokens) start-symbol)

(list (make-parse rtree (first tokens) :rem (rest tokens)))
(mapcan #*(lambda (rule)
(extend-parse (Ihs rule) nil tokens (rhs rule)))
(rules-for start-symbol))))
```

``` lisp
(defun extend-parse (Ihs rhs rem needed)
"Parse the remaining needed symbols."
(if (null needed)

(list (make-parse :tree (cons Ihs rhs) :rem rem))
(mapcan
#'(lambda (p)
(extend-parse Ihs (append rhs (list (parse-tree p)))
(parse-rem p) (rest needed)))
(parse rem (first needed)))))

(defun rules-for (cat)
"Return all the rules with category on Ihs"
(find-all cat ^grammar* :key #'rule-lhs))
```

**Answer 19.5** If it were omitted, then : tes t would default to #'eql, and it would be
possible to remove the "wrong" element from the list. Consider the list (1.0 1.0) in
an implementation where floating-point numbers are eql but not eq. if random-el t
chooses the first 1.0 first, then everything is satisfactory - the result Ust is the same
as the input list. However, if random-el t chooses the second 1.0, then the second

1.0will be the first element of the answer, but remove will remove the wrong 1.0! It
will remove the first 1.0, and the final answer will be a list with two pointers to the
second 1.0 and none to the first. In other words, we could have:

``` text
> (member (first x) (permute x) .-test #'eq)
NIL
```

**Answer 19.6 **

``` lisp
(defun permute (bag)

"Return a random permutation of the bag."
It is done by converting the bag to a vector, but the
result is always the same type as the input bag.

(let ((bag-copy (replace (make-array (length bag)) bag))
(bag-type (if (listp bag) 'list (type-of bag))))
(coerce (permute-vector! bag-copy) bag-type)))

(defun permute-vector! (vector)
"Destructively permute (shuffle) the vector."
(loop for i from (length vector) downto 2 do

(rotatef (aref vector (-i D)
(aref vector (random i))))
vector)
```

The answer uses rotatef, a relative of setf that swaps 2 or more values. That is,
(rotatef a b) is like:

``` lisp
(let ((temp a))
(setf a b)
(setf b temp)
nil)
Rarely, rotatef is used with more than two arguments, (rotatef a b c) is like:
(let ((temp a))
(setf a b)
(setf b c)
(setf c temp)
nil)
```

repository: casouri/paip-lisp

repo_name: casouri/paip-lisp


text:
Current Testing......

# ~~Tacotron2~~ Tacotron1.5 Kor ver.

## Materials
1. Audio files.
2. A JSON file containing the pronunciation for the audio file. The file name and text are the key and value, respectively.
3. Python 3.x and Tensorflow environment. This code is only tested in Python 3.6 and Tensorflow 1.7.

## How to use
### Generating pattern files.

    python Pattern_Generate.py -r 'recognition.json' -af 'audio_files_path' -pf 'export_pattern_files_path'

If you set 'pattern_Files_Path' of hyper parameter, PF arg is optional.

### Set the parameters in Hyper_Parameters.py

### Run

    python Tacotron1_5.py -e 'extract_folder' -m 'mode' -t 'time' -s 'string'

options:
-e: extract folder for the graph summary, checkpoint, and result. Required.

-m: mode. 'train' or 'test'. Required.

-t: When mode is train, how often to run tests and save the checkpoint. Default is '1000'

-s: In test, the sentence which will be tested. Default is '올해 겨울은 참 유난히도 길었습니다.'

## To do
1. Change Griffin-lim to Wavenet for Tacotron2.

branch_name: refs/heads/master

extension: md

license_type: permissive


text:
# Fitness Tracker

![Liscense](https://img.shields.io/badge/license-MIT-blue.svg)

## Description

This app allows a user to keep track of workouts or continue an existing workout to stay organized and reach their goals faster.

## Table Of Contents:

-[Installation](#Installation)
 -[Usage](#Usage)
 -[Liscense](#Liscense)
 -[Contributing](#Contributing)
 -[Tests](#Tests)
 -[Questions](#Questions)

## Installation

npm i - to install dependencies, and npm start - to connect to the server,

## Usage

Deployed App: [Fitness Tracker](https://github.com/amoseman1/fitnessTracker)

## Liscense

For more information about the liscense chosen, follow the link below:
[Liscense](https://opensource.org/liscenses/MIT)

## Contributing

Amy Moseman -
NodeJS
Express
MongoDB
Mongoose
Heroku

## Tests

N/A

## Questions

If you have any questions about this repo, open an issue or contact me directly at<EMAIL_ADDRESS>

You can find more of my work at Github: [amoseman1](https://github.com/amoseman1/)

[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg)](code_of_conduct.md)

license: MIT

branch_name: refs/heads/main


text:
# FSharp.Units

[![Build FSharp.Units](https://github.com/putridparrot/FSharp.Units/actions/workflows/dotnet-core.yml/badge.svg)](https://github.com/putridparrot/FSharp.Units/actions/workflows/dotnet-core.yml)
[![NuGet version (FSharp.Units)](https://img.shields.io/nuget/v/FSharp.Units.svg?style=flat-square)](https://www.nuget.org/packages/FSharp.Units/)
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/putridparrot/FSharp.Units/blob/master/LICENSE.md)
[![GitHub Releases](https://img.shields.io/github/release/putridparrot/FSharp.Units.svg)](https://github.com/putridparrot/FSharp.Units/releases)
[![GitHub Issues](https://img.shields.io/github/issues/putridparrot/FSharp.Units.svg)](https://github.com/putridparrot/FSharp.Units/issues)

The main aim for this project was to produce conversion functions for the various units of measurement (listed below). The code and the unit tests
are auto-generated by the UnitCodeGenerator tool. Hence any changes need to made within the definitions file.

The code is written in the style of F# if you're after something aimed at C# checkout [PutridParrot.Units](https://github.com/putridparrot/PutridParrot.Units).

Package available via [nuget](https://www.nuget.org/packages/FSharp.Units/)

### Unit conversions also available for

[C#](https://github.com/putridparrot/PutridParrot.Units)
[Dart](https://github.com/putridparrot/DartUnits)
[Go](https://github.com/putridparrot/GoUnits)
[Java](https://github.com/putridparrot/JavaUnits)
[Python](https://github.com/putridparrot/PyUnits)
[Rust](https://github.com/putridparrot/RustUnits)
[Swift](https://github.com/putridparrot/SwiftUnits)
[TypeScript](https://github.com/putridparrot/unit-conversions)

### Example

Example of usage:

```
let fahrenheit = C.toFahrenheit 12.<C>

let celsius = C.create someValue
```

Each unit of measure then includes functions to convert to each for example, converting each Temperature unit of measure to each other Temperature - it also includes a function to take a value and apply a unit of measure to it.

### Angle

	* Degrees (deg)
	* Gradians (grad)
	* Milliradians (mrad)
	* Minute Of Arc (arcmin)
	* Radians (rad)
	* Seconds Of Arc (arcseconds)

### Area

	* Acres (acre)
	* Hectares (hectare)
	* Square Feet (feet2)
	* Square Inches (inch2)
	* Square Kilometres (km2)
	* Square Metres (m2)
	* Square Miles (mile2)
	* Square Yards (yard2)

### Data Storage

	* Bits (b)
	* Gigabits (Gb)
	* Gigabytes (GB)
	* Kibibits (kibibit)
	* Kilobits (k)
	* Kilobytes (KB)
	* Mebibits (mebibit)
	* Megabits (Mb)
	* Megabytes (MB)
	* Terabits (Tb)
	* Terabytes (TB)

### Data Transfer Rate

	* Bits Per Second (bps)
	* GigaBits Per Second (Gbps)
	* GigaBytes Per Second (GBps)
	* Kibibits Per Second (Kibitps)
	* KiloBits Per Second (kbps)
	* KiloBytes Per Second (kBps)
	* Mebibits Per Second (Mibit)
	* MegaBits Per Second (Mbps)
	* MegaBytes Per Second (MBps)
	* TeraBits Per Second (Tbps)
	* TeraBytes Per Second (TBps)

### Energy

	* Btu (btu)
	* Calories (cal)
	* Electronvolts (eV)
	* Foot Pounds (ftlb)
	* Joules (J)
	* Kilocalories (kCal)
	* Kilojoules (kJ)
	* Kilowatt Hours (kWh)
	* US Therms (ustherm)
	* Watt Hours (Wh)

### Force

	* Dynes (dyn)
	* Kilogram-force (kp)
	* Newtons (N)
	* Poundals (pdl)

### Frequency

	* Gigahertz (GHz)
	* Hertz (Hz)
	* Kilohertz (kHz)
	* Megahertz (MHz)

### Fuel Economy

	* Kilometre Per Litre (kml)
	* Litres Per 100 Kilometres (l100km)
	* Miles Per Gallon (mpg)
	* US Miles Per Gallon (usmpg)

### Length

	* Centimetres (cm)
	* Feet (ft)
	* Inches (inch)
	* Kilometres (km)
	* Metres (m)
	* Miles (mile)
	* Millimetres (mm)
	* Nautical Miles (NM)
	* Yards (yard)

### Luminous Energy

	* LumenHour (lmh)
	* LumenMinute (lmmin)
	* LumenSecond (lms)
	* Talbot (T)

### Magnetomotive Force

	* Ampere-turns (AT)
	* Gilberts (Gi)

### Mass

	* Carats (ct)
	* Grams (g)
	* Kilograms (kg)
	* Milligrams (mg)
	* Ounces (oz)
	* Pounds (lb)
	* Stones (stone)
	* Tonnes (tonne)

### Power

	* Mechanical Horse Power (hp)
	* Metric Horse Power (ps)

### Pressure

	* Atmospheres (atm)
	* Bars (b)
	* Pascals (Pa)
	* Psi (psi)
	* Torrs (Torr)

### Speed

	* Feet Per Second (fps)
	* Kilometres Per Hour (kph)
	* Knots (knot)
	* Metres Per Second (mps)
	* Miles Per Hour (mph)

### Temperature

	* Celsius (C)
	* Fahrenheit (F)
	* Kelvin (K)
	* Rankine (R)

### Time

	* Centuries (century)
	* Days (day)
	* Decades (decade)
	* Hours (hour)
	* Microseconds (microsecond)
	* Milliseconds (millisecond)
	* Minutes (minute)
	* Months (month)
	* Nanoseconds (nanosecond)
	* Seconds (second)
	* Weeks (week)
	* Years (year)

### Volume

	* Cubic Feet (feet3)
	* Cubic Inches (inch3)
	* Cubic Metres (m3)
	* Fluid Ounces (floz)
	* Gallons (gal)
	* Kilolitres (kl)
	* Litres (l)
	* Millilitres (ml)
	* Oil Barrels (oilbarrel)
	* Pints (pt)
	* Quarts (qt)
	* Tablespoons (tbsp)
	* Teaspoons (tsp)
	* US Cups (uscup)
	* US Fluid Ounces (usfloz)
	* US Gallons (usgal)
	* US Pints (uspt)
	* US Quarts (usqt)
	* US Tablespoons (ustbsp)
	* US Teaspoons (ustsp)

### Apps

The "My Unit Conversions" app. (for Android, iOS and Windows) uses the C# (PutridParrot.Units) version of this library and can be obtained from the following stores/locations.

[![Get it on Google Play](https://apps.putridparrot.com/Images/googleplay153x46.png)](https://play.google.com/store/apps/details?id=com.putridparrot.MyUnitConversion&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1)
[![Download on the Apple Store](https://apps.putridparrot.com/Images/applestore153x46.png)](https://apps.apple.com/app/my-unit-conversion/id1600275661)
[![Available on Fire](https://apps.putridparrot.com/Images/fire153x46.png)](https://www.amazon.co.uk/MTBSOFTWARE-LIMITED-My-Unit-Conversion/dp/B09RTBBGNM/)
[![Available on Windows](https://apps.putridparrot.com/Images/MS_864X312.svg)](https://apps.microsoft.com/store/detail/my-unit-conversion/9NK6CTDN0L2L)

The Mac version of the app. uses this Swift package and can be obtained from the following location

[![Download on the Apple Store](https://apps.putridparrot.com/Images/applestore153x46.png)](https://apps.apple.com/app/my-unit-conversion/id1600275661)

gha_language: F#

gha_license_id: MIT


text:
---
title: A nice title
subtitle: A nice subtitle
author: Author Authorsson
date: \today
---

# A section

## A subsection

* This is
* a nice
* bulleted
* list

## Another subsection

```
def there_is_some():
    syntax = 'Highlighting'
    for python in this:
        template()
```

## Evaluate Python code

```
>>> 3 + 9
>>> 2**15
>>> val = 'Na'
>>> 5 * val
```

## And finally

### Sub-subsections

* Appear as
* nice boxes

---

* Horizontal lines
* always force
* a new slide

repository: hadisfr/md-lecture

repo_name: hadisfr/md-lecture


text:
# gradle-commit-checker-plugin

[![Build Status](https://travis-ci.org/ksoichiro/gradle-commit-checker-plugin.svg?branch=master)](https://travis-ci.org/ksoichiro/gradle-commit-checker-plugin)
[![Build status](https://ci.appveyor.com/api/projects/status/rom2rsf2j56f01bs?svg=true)](https://ci.appveyor.com/project/ksoichiro/gradle-commit-checker-plugin)
[![Coverage Status](https://coveralls.io/repos/ksoichiro/gradle-commit-checker-plugin/badge.svg?branch=master&service=github)](https://coveralls.io/github/ksoichiro/gradle-commit-checker-plugin?branch=master)

Gradle plugin to check commits in a branch to avoid large diff in a pull requests.

```console
$ ./gradlew checkCommit
:checkCommit FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':plugin:checkCommit'.
> Your branch includes too much changes. Please check if those changes are not mistake but intentional. If your branch includes multiple features, consider separate them into multiple branches / pull requests.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 11.791 secs
```

## Usage

Apply plugin:

```gradle
plugins {
    id 'com.github.ksoichiro.commit.checker' version '0.1.1'
}
```

Execute check:

```
./gradlew checkCommit
```

> Note that this plugin uses git command.
Please install git wherever you execute this task.

If you want to run it on each 'check's, set it to dependent task:

```gradle
check.dependsOn 'checkCommit'
```

## Configuration

```gradle
commitChecker {
    // Change this property to the main branch of your project.
    // Default is 'master'.
    mainBranch 'develop'

    // Change this property to the number that is max size you can allow for a pull request size.
    // Default is 1000.
    changedLinesThreshold 100

    // Change this property to true if you want to make the violations to build error.
    // Default is false. (Just showing a message)
    failOnChangesExceedsThreshold true

    // Change this property to whatever you want to show if there are any violations.
    messageForLargeChanges "Too large changes!"

    // Change this property if you want to change
    // the working directory for executing git commands.
    workDir = project.file("foo/bar")
}
```

## License

    Copyright 2015 Soichiro Kashima

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

repository: ksoichiro/gradle-commit-checker-plugin

repo_name: ksoichiro/gradle-commit-checker-plugin


text:
---
title: What is Hydrophonics
author: Vikas Gaikwad
date: 2020-10-10 20:30:00 +0800
categories: [Hydroponics, Episodes]
tags: [hydroponics,soilless farming]
pin: true
comments: true
---

##### SOILLESS FARMING

![title](https://cdn.foodhospitality.in/wp-content/uploads/2020/05/11143035/hydroponics.jpg)

Hello Folks,

I am starting new detailed blog series on new Urban Farming Technologies this has proven their need, importance and the future oppourtunities across the globe.

This blogging series will be more of sharing my practical experiences, my experiements and mistakes I did during the journey of building my Hydroponics System.

We all know importance of the Neurtrious foods in our daily life.

Lets try to understand insights of this Urban Farming Technology:

# **What is Hydroponics/Soilless Farming ?**

Most of us have heared a buzz words like "**Hydroponics**" or "**Soilless**" farming

When we tell people that we grow our daily produces using hydroponics, we usually get something close to this response:

*“Sounds cool…sounds like it has something to do with health food maybe? What even is it?”*

For all the hydro-curious folks out there, I am trying to explain in simple terms

**Put simply:** Hydroponics is a way to skip the soil,sub in a different material to support the roots of the plant, and grow crops directly in nutrients-rich water.

In Hydroponics there is no need of **Soil** to grow crops, In traditional farming Soil is used as supportive element to hold the roots of the plants and plants get the required nutrients from the soil.

Where as In Hydroponics plant absorbs all the required neutrients directly from the water and grows faster than the soil.

A simple setup of **Nutrient film technique**(NFT) or Hydroponics Systems shown in below image

![SETUP]( https://thehomesteadinghippy.com/wp-content/uploads/2014/04/hydroponic-system-diagram.jpg )

# **How it is different than the Traditional Farming ?**

As we all know how the Farmer prodces the crops, vegitables and all other yields which we need on the daily basis, we all know India is the Nation of Agricultural Land **"Krushi Pradhan Desh"** and in traditional farming 3 important elements are required
   - Huge Land Area
   - Plenty of Water
   - Fertilizer and Pestecides to protect crop from insects and disease

Talking about Hydroponics,

This seemingly subtle shift in how we make food (skipping the soil, that is) is actually revolutionary –– it allows growers to produce food anywhere in the world, at any time of the year, and to net higher yields with fewer resources.

Where as in Hydroponics System Plants are grown in the nutrients based water within a controlled and enclosed environment where plant don't need to strugle to get the required nutrients from the water.

This system focuses on controling the pH of the water, Electrical conductivity, Humidity, Temperature, Pressure,Lighting conditions and nutrients requirment of the yields.

- **Fresh water.** Were talking primo,filtered stuff with a balanced pH. Most plants like water with a pH level around 6 to 6.5.

- **Oxygen:** Roots will take the dissolved oxygen from the water.

- **Root Support:** Even though you don’t need soil, your plant’s roots still need a little something to hold on to. Typical materials include vermiculite,perlite, peat moss, coconut fiber and rockwool. Stay away from materials that might compact(like sand) or that don’t retainany moisture (like gravel).

- **Nutrients:** Plant is going to need plenty of ***magnesium,phosphorus, calcium,*** and other nutrients to stay healthy and productive –– just like plants growing in the ground need healthy soil and fertilizer.

- **Light:** Light is the source of energy like we get the D-vitamin from the Sun light, plant also need the light spectrum to grow.

# **What all crops we can grow using Hydrophonics?**
It is best suited for all kinds of vegitables like Tomatoes,Lettuce,Cucumber,Spring onions,Peppers,Spinach,Basil,Coriander and many more...
## Advantages, Disadvantages of Hydroponics compared to Soil based farming ?

**Advantages :**
- No huge land investment and Soil is not required,no need of pestecides and fertilizers.
- Yields can be produced **27x7** across the year in almost 80-90% less water compared with soil.
- Can be able to fulfill the demand by automating the systems and plants can be grown in a very controlled and managed environments.
- Less Man power more automation invloved.

**Disadvantes :**
- Initial setup cost is more.
- Need the precise control and monitoring of the various parameters like pH, EC, temperature, humidity and Nutrients levels as per the types of plants.

# **Hydrophonics the Future of Farming**

As the world population continues to grow, the challenge is to produce more food whilst being more sustainable. To assist with this, more technologies are coming into play. Hydroponic technology, which allows producers to grow plants without soil.

In 2015, the United Nations predicted that the world population will grow to 9.6bn by 2050 and 70% of the population will live in cities.

Future of this field will be like a shining sun in upcoming time.

All the countries have already taken the active initiatives and number of Tech startups across the globe are producing the fresh organic yields.

It is a Billion Dollar Industry In India, at present Agriculture is contributing at 14-18% of total GDP, seems to have plenty of oppourtunities in near-future.

Have a look at High-Tech farming

Stay tuned for next blog to understand the seedling process in Hydroponics.

gha_language: HTML


text:
# @projectsophon/df-plugin-dev-server

An ESBuild server for Dark Forest plugin development.

## Installation

You can install the command globally using:

```bash
npm i -g @projectsophon/df-plugin-dev-server
```

## Usage

Once installed, you should have access to the command:

```bash
df-plugin-dev-server
```

You can see the supported flags by running:

```bash
df-plugin-dev-server

Start a Dark Forest plugin development server.

Options:
  --help     Show help                                                 [boolean]
  --version  Show version number                                       [boolean]
  --dir      The directory to load     [deprecated: use --glob instead] [string]
  --ext      Extensions to process      [deprecated: use --glob instead] [array]
  --glob     Glob for finding plugins   [array] [default: ["plugins/*.(js|ts)"]]
```

And then run the server:

```bash
df-plugin-dev-server
ESBuild for /Users/user/sophon-plugins/plugins on port 2221
Development server started on http://<IP_ADDRESS>:2222/
```

## Adblock & Security

I noticed that Brave Browser's built-in Adblock stops any requests to `<IP_ADDRESS>`, so you'll need to disable that if you are building plugins against https://zkga.me directly.

You'll also need to "Allow Insecure Content" since this development server doesn't provide an HTTPS certificate.

## Plugins

The easiest way to load plugins while developing would be to use something like this in the Dark Forest UI:

```js
// This maps to ./plugins/PluginTemplate.js or ./plugins/PluginTemplate.ts by default
export { default } from "http://<IP_ADDRESS>:2222/PluginTemplate.js";
```

However, Dark Forest plugins are cached, so you'd need to do some sort of cache busting each time you make a change. Luckily, we've taken care of that for you! To get free cache busting, you can add `?dev` to the end of your plugin URL.

```js
// Notice the ?dev
export { default } from "http://<IP_ADDRESS>:2222/PluginTemplate.js?dev";
```

Doing the above will proxy your plugin through a cache busting plugin!

## Docker image installation and running

From main directory you can execute commands to build and start docker image:

To build & run without getting prompted for docker output simply run (with -d):

`docker-compose -f docker-compose.yml up -d --build --remove-orphans`

To run an existing image without building, remove `--build --remove-orphans`:

`docker-compose -f docker-compose.yml up -d`

To stop you should use `stop`. To stop and delete use `down`:

```bash
docker-compose -f docker-compose.yml stop
docker-compose -f docker-compose.yml down
```

To only build the docker image:

`docker-compose -f docker-compose.yml build `

If your image is already built, you can use the `docker` command directly:

```bash
docker start plugin_server
docker stop plugin_server
```

### Security notes for docker containers

Docker is working on another layer meaning your internet connection from docker containers is bridged through your network interface by default. Starting this container with default configuration using commands from above opens port to this docker container to any incoming IP subnet existing (bind <IP_ADDRESS>). Default system firewall configuration will not prevent access from outside world if your router does not block ports by default. KEEP THIS IN MIND. Storing vulnerable data inside container is not recommended with this configuration. You should edit docker network of `plugin_server` to make it harden. The easiest way is to set flag `--internal` for specific docker network, to prevent access from other computers.

## License

MIT

repository: crypto-forks/df-plugin-dev-server

repo_name: crypto-forks/df-plugin-dev-server


text:
# plaid

[![CI](https://github.com/telcoin/plaid/workflows/CI/badge.svg)](https://github.com/telcoin/plaid/actions?query=workflow%3ACI)

An unofficial Rust client library for the [Plaid API].

### Example

1. Add the following to your `Cargo.toml`:

   ```toml
   [dependencies]
   plaid = { git = "https://github.com/telcoin/plaid.git", tag = "v0.4.0" }
   tokio = { version = "0.2", features = ["full"] }
   ```

1. Obtain your API credentials from: https://dashboard.plaid.com/team/keys

1. Get started with this example `main.rs`:

   ```rust
    #[tokio::main]
    async fn main() -> Result<(), Box<dyn std::error::Error>> {
        // or use `plaid::Client::from_env()?`
        let client = plaid::Client::new(
            "your_client_id",
            "your_client_secret",
            plaid::Environment::Sandbox,
        );

        // TODO: use the Link flow instead; https://plaid.com/docs/link/#link-flow
        let public_token = client.sandbox_create_public_token().await?.public_token;

        let access_token = client
            .exchange_public_token(&public_token)
            .await?
            .access_token;

        let _accounts = client.accounts(&access_token).await?.accounts;

        Ok(())
    }
   ```

[plaid api]: https://plaid.com/

repository: kurtbuilds/plaid

repo_name: kurtbuilds/plaid


text:
# Spree Klarna Invoice

[![Build Status](https://secure.travis-ci.org/futhr/spree_klarna_invoice.png?branch=master)](http://travis-ci.org/futhr/spree_klarna_invoice)
[![Dependency Status](https://gemnasium.com/futhr/spree_klarna_invoice.png)](https://gemnasium.com/futhr/spree_klarna_invoice)
[![Coverage Status](https://coveralls.io/repos/futhr/spree_klarna_invoice/badge.png?branch=master)](https://coveralls.io/r/futhr/spree_klarna_invoice)

Spree extenstion for Klarna Invoice Payment Method. Makes it possible to invoice customers with Klarna's services. Read more on [Klarna][1].

Based on Klarna-ruby it is using the old Klarna API. There is a newer version and I intend to fork klarna-ruby and update it with the [Klarna API 2.0][2].

## Requirements

* Based on *[klarna-ruby][3]* library

## Installation

In your `Gemfile`:

```ruby
gem 'spree_klarna_invoice', github: 'futhr/spree_klarna_invoice'
```

Then run from the command line:

    bundle install
    rails g spree_klarna_invoice:install
    rake db:migrate

## Todo

__High Prio__

* Refactor for Spree 2.0
* Write tests
* Update klarna-ruby for [Klarna API 2.0][2]

__Completed__

* ~~Auto capture~~
* ~~Send invoice via email~~
* ~~Send invoice via mail~~
* ~~Production mode testing~~

## Contributing

In the spirit of [free software][4], **everyone** is encouraged to help improve this project.

Here are some ways *you* can contribute:

* by using prerelease versions
* by reporting [bugs][5]
* by suggesting new features
* by writing [translations][7]
* by writing or editing documentation
* by writing specifications
* by writing code (*no patch is too small*: fix typos, add comments, clean up inconsistent whitespace)
* by refactoring code
* by resolving [issues][5]
* by reviewing patches

Starting point:

* Fork the repo
* Clone your repo
* Run `bundle install`
* Run `bundle exec rake test_app` to create the test application in `spec/test_app`
* Make your changes and follow this [Style Guide][8]
* Ensure specs pass by running `bundle exec rspec spec`
* Submit your pull request

Copyright (c) 2013 Emil Karlsson, released under the [New BSD License][6]

[1]: http://klarna.com
[2]: https://docs.klarna.com/en/rest-api
[3]: https://github.com/futhr/klarna-ruby
[4]: http://www.fsf.org/licensing/essays/free-sw.html
[5]: https://github.com/futhr/spree_klarna_invoice/issues
[6]: https://github.com/futhr/spree_klarna_invoice/tree/master/LICENSE.md
[7]: http://www.localeapp.com/projects/4913
[8]: https://github.com/thoughtbot/guides


text:
---
layout: post
title: Independent Project - PredictedIt - Project Notes
tags: predictedit notes
excerpt_separator: <!--more-->
---

## Project Overview
I have a personal interest in politics as well as economics. I find I am
especially intrigued by the idea of markets to predict outcomes, and in the
past I've played around with placing political bets on the website PredictIt.org.

I would love to be able to practice my data analysis skills on the PredictIt
market data, and even learn a bit about quantitative trading without wading
into the rats nest that is the stock market. Unfortunately, the PredictIt API is pretty
minimal, so for this project I am setting out to archive data from PredictIt using the cheapest, abstracted-AWS services I can find; structure the data and make it accessible to others in a cheap,
but scalable, microservices architecture; Analyze the data myself and potentially practice
applying some quant-trading algorithms along the way.

<!--more-->

## Project Goals
* Learn how to build and release an AWS-based architecture
* Practice data acquisition, cleaning, and structuring
* Practice data analysis
* Learn a bit about common quantitative training techniques
* Archive PredictIt pricing data and make it easily accessible for others

## Requirements
* Minimize costs
* Limit cloud resources to AWS because:
  + We are an AWS shop at work, so this aids professional development
  + I am planning to take the AWS Certified Developer - Associate Certification Exam
* Make the data I archive easily accessible and ensure access is scalable
* Follow data fault-tolerance and security-best practices

## POC Architecture:

TODO(nadir.sidi): Add a lucid-chart diagram here

## ToDo:

### Data Acquisition
* Review the existing PredictIt API endpoints using Postman
* Write a Python Lambda function to hit the API and stash the data
* Set-Up a deployment pipeline
  + Set-up AWS CodeBuild with hooks to Github repo with Lambda
  + Learn about CloudWatch SAM files to handle deployment from S3 artifact

### Data Storage
* Determine initial partition-scheme for stashing PredictIt data
* Investigate transforming the data to store into a DB
* Write a Athena query to read data directly from S3
  + Is is bad practice to write a API that hits the Athena schema-on-read directly?

### Data Access
* Investigate querying data from Athenta

{% include archive.html %}


text:
---
layout: default
---

# 1994-12-13 - Re: Authentication vs encryption: CPs on the web

## Header Data

From: Adam Shostack<EMAIL_ADDRESS>To<EMAIL_ADDRESS>(Hal)

Message Hash: badc28862a665b3c5d923f37b9dd12c5193fa41a7aa533b233ad150103825beb

Message ID<EMAIL_ADDRESS>Reply To<EMAIL_ADDRESS>UTC Datetime: 1994-12-13 18:52:50 UTC

Raw Date: Tue, 13 Dec 94 10:52:50 PST

## Raw message

```
{% raw  %}From: Adam Shostack<EMAIL_ADDRESS>Date: Tue, 13 Dec 94 10:52:50 PST
To<EMAIL_ADDRESS>(Hal)
Subject: Re: Authentication vs encryption: CPs on the web
In-Reply-To<EMAIL_ADDRESS>Message-ID<EMAIL_ADDRESS>MIME-Version: 1.0
Content-Type: text/plain

	With all due respect, I disagree with your assessment.
Anonymity is a job, and we should build small tools to do jobs.  It is
my feeling that building anonymity into the web will make the
protocols more complex than they need to be.

	There is no anonymity in mail, but we have anonymous mail of
varying privacy.  I suspect mixmaster will greatly enhance that.  To
get privacy in the web, build a web remailer on top of the CERN or TIS
HHTPd proxies.  Encrypt between you & the proxy, let the proxy go out.

Adam

| This is IMO the standard cypherpunks wish list as applied to the WWW.
| But it does not seem to match up with either the commercial or
| institutional interests which are driving the standards process.  I
| hope those CP's who are involved in these efforts can work to spotlight
| the need for individual privacy.  We should give as much power, choice,
| and control as possible to the individual end-users of the web.
| Otherwise privacy is going to be very difficult to maintain in this
| world of electronic commerce.
|
| Hal Finney
|<EMAIL_ADDRESS>
--
"It is seldom that liberty of any kind is lost all at once."
						       -Hume

{% endraw %}
```

## Thread

+ Return to [December 1994](/archive/1994/12)

+ Return to "[Adam Shostack <adam@bwh.harvard.edu>](/authors/adam_shostack_adam_at_bwh_harvard_edu_)"
+ Return to "[Hal <hfinney@shell.portal.com>](/authors/hal_hfinney_at_shell_portal_com_)"

+ 1994-12-13 (Tue, 13 Dec 94 09:44:50 PST) - [Authentication vs encryption: CPs on the web](/archive/1994/12/c71f18a5e525d4c6e86f844769f4d2bfb102c802155f59a8d71134216afc2126) - _Hal<EMAIL_ADDRESS>  + 1994-12-13 (Tue, 13 Dec 94 10:52:50 PST) - Re: Authentication vs encryption: CPs on the web - _Adam Shostack<EMAIL_ADDRESS>    + 1994-12-13 (Tue, 13 Dec 94 12:29:36 PST) - [Re: Authentication vs encryption: CPs on the web](/archive/1994/12/34df4951547567eb6d2e97ea8d4b902166fca9dc53abfb999e4b7612d3fbae6f) - _Hal<EMAIL_ADDRESS>


text:
# Valentine: A Common Lisp wrapper for the Bullet Physics Library

## Notes

* You can build the bindings. You will need SWIG and g++.

* The CLOS interface doesn't work yet. There are problems with package locks and methods with different numbers of arguments.

## To build:

* find a work directory

* type: git clone https://github.com/bulletphysics/bullet3.git

* make and enter a build directory

* type: cmake <path to bullet repo> -G "Unix Makefiles" -DINSTALL_LIBS=ON -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=ON -DBUILD_EXTRAS=OFF
  (If you are not building for Unix...I don't know what to do for you.)

* type: make -j <number of cores you have>

* type: sudo make install
  (Enter your password)

* cd to ~/quicklisp/local-projects

* type: git clone git@github.com:BradWBeer/valentine.git

* enter the valentine directory and type: make clean all

* start up your local lisp

* in the repl type: (ql:quicklisp :valentine)

* use valentine...oh, all the symbols are private right now so be sure to use valentine::<symbol>

* report any bugs...I bet there's a lot of them

* have fun!

repository: BradWBeer/valentine

repo_name: BradWBeer/valentine


text:
# Readme Generator
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
  ## Description
With our new knowledge in node.js, we are creating a readme to have our future projects look more professional and attractive.
  ## Table of Contents

  * [Installation](#installation)
  * [usage](#usage)
  * [License](#license)
  * [contributors](#contributors)
  * [Test](#test)
  * [Contact](#contact)
  # Installation
  To run the installation, use the following code:
  npm install & npm i -y
  # usage
  Use gitclone to have access to the file and the use of node index.js
  # License
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

  # Contributors
  Kevin Hidalgo, taught by John and Dan
  # Test
  npm test
  # Contact
  Moving forward, if you have questions or concerns feel free to contact me at the following given communcations:

  GitHub:

  github.com/Kevinrhidalgo

  Email

<EMAIL_ADDRESS>
# ReadMe Image
![screenshot](https://user-images.githubusercontent.com/78196245/115098605-e83b1500-9efe-11eb-8ace-a013f0c89e94.jpg)

# GitHub Url
https://github.com/kevinrhidalgo/Homework-7-CreatingThePerfectReadeMe
# Example Video Demonstration
 ![nodejs](https://user-images.githubusercontent.com/78196245/115098562-ac07b480-9efe-11eb-91cb-1989fe428b93.gif)
https://drive.google.com/file/d/199EWV2rOEYGGLAxsApiT3TjaZOFTxKG9/view?usp=sharing


text:
MHR Component Headers
=====================

The Master Health Record has summary information in each entry header which varies by component. This is the information that is displayed (using the entryheader.js directive).

#### 1 - Medications.

+ Medication name
+ When/how often it is taken
+ Indication
+ Active/Inactive

#### 2 - Test Results/Labs and Radiology?

+ Test name
+ Date

#### 3 - Encounters.

+ Encounter name
+ Location/organization name where encounter took place
+ Date of encounter

#### 4 - Vital Signs.

+ Vital name
+ Vital value
+ Date

#### 5 - Immunizations.

+ Immunization name
+ Date of immunization(s)

#### 6 - Allergies.

+ Date
+ Name
+ Reaction type

#### 7 - Conditions.

+ Problem
+ Date of diagnosis

#### 8 - Procedures.

+ Procedure name
+ Date

#### 9 - Social History.

+ Instead of date use 'current/active' and 'past/inactive'


text:
---
title: "To the states!"
---
For all the hubbub about the Supreme Court's ruling in _Kelo v. City of New
London_ that eminent domain could be applied to cases where "economic
development" was the public use in question, the response of the state
legislatures [has been
swift](http://www.castlecoalition.org/legislation/states/index.asp). The
decision did not prevent states from making their own laws regarding the scope
of eminent domain, and public opposition to the ruling has been widspread and
bipartisan. An [article](http://www.usatoday.com/news/nation/2005-08-02
-eminent-domain_x.htm?csp=34) in _USA TODAY_ detailed the states' response and
had this to say:

> In Washington, U.S. Sen. John Cornyn, R-Texas, said his office received more
calls from constituents angry about this case than it did for the Supreme
Court ruling that limited displays of the Ten Commandments on public property

...

"We don't like anybody messing with our dogs, our guns, our hunting rights or
trying to take property from us," says [Alabama] state Sen. Jack Biddle, a
sponsor of the law.

The [Castle Coalition](http://www.castlecoalition.org) is a great resource for
eminent domain issues and activism if you're so inclined.


text:
# budget-tracker
![](https://img.shields.io/badge/License-MIT-blue.svg)
## Description
Budget Tracker API is an Express-based, progressive web application (PWA) designed to allow users to track their budget, whether internet service is available or not.

 ## Link to Deployed Application
* [Budget Tracker](https://nameless-fjord-00851.herokuapp.com)
### User Story
* AS AN avid traveler
* I WANT to be able to track my withdrawals and deposits with or without a data/internet connection
* SO THAT my account balance is accurate when I am traveling

## Table of Contents
* [Installation](#installation)
* [Usage](#usage)
* [License](#license)
* [Contributing](#contributing)
* [Questions](#questions)

## Link to Github Repository
* [budget-tracker](https://github.com/jeffwjohn/budget-tracker)

![Screenshot](public/images/screenshot.png)

### Installation
Follow the deployed application link: https://nameless-fjord-00851.herokuapp.com. From here, use the app online, and/or click the circled plus symbol in the url bar to install the PWA to your device for use offline.

### Usage
Type the name of a transaction, the amount, and click to either add or subtract the funds from your budget. A record of the transaction is kept, and reflected in the dynamic graph below the inputs.

### License
MIT

### Contributing
Budget Tracker API is an open source project that was built from cloned, front-end starter code at the University of Texas Web Development Bootcamp, and anyone is encouraged to contribute by cloning or forking the code and working to improve its function and versatility.

### Questions

##### Interested in other projects from this developer? Visit the following GitHub page:
https://github.com/jeffwjohn

##### Send any questions to the following email address:
<EMAIL_ADDRESS>

repository: jeffwjohn/budget-tracker

repo_name: jeffwjohn/budget-tracker


text:
# Cohen: 'Anybody Who Watches Fox News Watches It Too Much' -- Hannity, Ingraham Trump's 'Co-Conspirators' | Breitbart

Published at: **2019-11-03T19:08:37+00:00**

Author: **Pam Key**

Original: [Breitbart](https://www.breitbart.com/clips/2019/11/03/cohen-anybody-who-watches-fox-news-watches-it-too-much-hannity-ingraham-trumps-co-conspirators/)

During an appearance on Sunday’s broadcast of MSNBC’s “Weekends,” Rep. Steve Cohen (D-TN) said Fox News hosts Sean Hannity and Laura Ingraham were “co-conspirators” of President Donald Trump.
Cohen said, “Anybody who watches Fox News watches it too much. And these people watch it and they just eat it up and buy all of that stuff. Hannity and what’s her name, Laura Ingraham or whatever and saying that Vindman was a traitor or dual citizenship, dual alliances and Dershowitz sat there and listened like a quisling, those people are in on it they are coconspirators with Trump.”

        Follow Pam Key on Twitter @pamkeyNEN

license: Unlicense

repository: dsadlollioygjmzvcxv/tdc-exported

repo_name: dsadlollioygjmzvcxv/tdc-exported


text:
# node-obj-auto-persist

Simple, automatic, file-system object persistence for NodeJS.

This component returns a JS object from a JSON file and watches the object for changes which are then written back to the file. This allows node applications a simple way of persisting data across multiple executions and restarts.

The following app simply echos out how many times it has been run. Modifying the `data` object automatically persists the changes to the file system.

```javascript
var persist = require('obj-auto-persist'),
    data = persist(require('path').resolve('./data.json'));

if (!data.run) {
    data.run = 1;
} else {
    data.run++;
}

console.log('This app has been run ' + data.run + ' times.');
```

license: ISC

repository: chrisakers/node-obj-auto-persist

repo_name: chrisakers/node-obj-auto-persist


text:
Given a binary search tree and a number `n`, find two numbers in the tree that sums up to `n`.

# Example
## Example1
```
Input:
{4,2,5,1,3}
3
Output: [1,2] (or [2,1])
Explanation:
binary search tree:
    4
   / \
  2   5
 / \
1   3
```
Example2
```
Input:
{4,2,5,1,3}
5
Output: [2,3] (or [3,2])
```
# Notice
Without any extra space.

url: https://raw.githubusercontent.com/vincent507cpu/Comprehensive-Algorithm-Solution/04e01e49622457f09af2e1133954f043c0c92cb9/LintCode/ladder 02 two pointers/旧/689. Two Sum IV - Input is a BST/readme.md


text:
# SAPI Explorer

**A blockchain explorer for SmartCash.**

## Quick Start

To get started you only need to connect to a SAPI server;

Each node is a server, so you can pool the servers or choose your own;

You can check our Swagger for SAPI (SmartCash Decentralized API) calls:
https://editor.swagger.io/

Import the swagger.json file that is in the root folder to see all API calls.

To list the servers you must use:

https://sapi.smartcash.cc/v1/smartnode/list

Filter by actives nodes then you can random servers:

http://<IP_ADDRESS>:8080/v1/smartnode/list

```sh

sudo apt install npm
sudo npm install node
git clone https://github.com/SmartCash/sapiexplorer
cd sapi_explorer
npm install
npm start
```
Add a start script on reboot.
```
crontab -e
@reboot sleep 30 && cd /home/user/sapi_explorer && /usr/bin/npm start
control x y to save
```


text:
xPlay utilizes Nunito font family for typography. Nunito Sans with the font weights 400, 400i and 600 is used as the base font, while Nunito with font weight of 600 is used for headings. These fonts are not included in the npm package and should be imported from Google Fonts or a similar CDN.

HTML Import

    <xmp>
    <link href="https://fonts.googleapis.com/css?family=Nunito+Sans:400,400i,700|Nunito:600" rel="stylesheet">
    </xmp>

CSS Import

    <xmp>

    </xmp>

repository: cubefuse/xplay-ui

repo_name: cubefuse/xplay-ui


text:
---
title: "SIMPsON: Interface SQUID Para Gerenciamento de Perfis"
collection: publications
permalink: /publication/SIRC-paper1
excerpt: 'Access control in computer networks is an increasingly necessary al-ternative and present in companies and educational institutions, after all, it be-comes ideal to have tools that can manage and monitor access to the Internet,quickly and intuitively. Therefore, we present the SIMPsOn tool, which uses theSquid tool integrated to an intuitive graphical interface'
date: 2017-11-07
venue: 'XIV Simpósio de Informática do Centro Universitário Franciscano – SIRC 2017'
paperurl: 'http://brendasalenave.github.io/files/SIRC-2017-3.pdf'

---
Access control in computer networks is an increasingly necessary al-ternative and present in companies and educational institutions, after all, it be-comes ideal to have tools that can manage and monitor access to the Internet,quickly and intuitively. Therefore, we present the SIMPsOn tool, which uses theSquid tool integrated to an intuitive graphical interface

[Download paper here](https://onedrive.live.com/?authkey=%21AJpNrbdBRn6322E&cid=7BBF4A05076CD56B&id=7BBF4A05076CD56B%211416415&parId=7BBF4A05076CD56B%211417225&o=OneUp)

Recommended citation: TAVARES, T. N. ; GARCIA, VINÍCIUS FÜLBER ; **SANTANA, B. S.** ; LUCCA, L. P. ; DONATO, M. M. ; SILVA, N. C. B. ; ROCHA, A. M. . SIMPSON: Interface SQUID Para Gerenciamento de Perfis. In: XIV Simpósio de Informática, 2017, Santa Maria. Anais XIV Simpósio de Informática, 2017.


text:
EffictiveRBM
============

EffictiveRBM is a python version restricted boltzmann machine tools for solve problems or build more complex model. The effictive means this is a fast rbm tools, it accelerate by cython and multi-process. It has been used to build the autoencoder model which descript by Hinton.

## How to Use
First, initialize an RBM with the desired number of visible, hidden units and process number.
Then train the rbm model with Iterator and params which descript in rbm.py
```python
rbm = ParallelRBM(self.converter.dimensionality, 1000, 5)
rbm.train(DefaultBatchIterator(100, self.converter.train_images), max_epochs = 20, batch = 100)
```

## Dependencies
- [NumPy](http://www.numpy.org): normal computing
- [Scipy](http://www.scipy.org/): faster sigmoid computing

## Optional dependencies
- [Cython](http://www.cython.org): Only necessary to run the faster version. Version 0.17.1 or higher.
- [matplotlib](http://matplotlib.sourceforge.net/): For plotting some data

## Reference

* [A Practical guide to training restricted Boltzmann machines](http://www.cs.toronto.edu/~hinton/absps/guideTR.pdf), by Geoffrey Hinton.
* [Reducing the Dimensionality of data with neural networks](http://www.cs.toronto.edu/~hinton/science.pdf), by Geoffrey Hinton.
* [Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~lisa/pointeurs/TR1312.pdf), by Yoshua Bengio.

## License
The MIT License (MIT)

repository: colinsongf/EffictiveRBM

repo_name: colinsongf/EffictiveRBM