--- layout: post title: "Can types replace validation?" description: "With some examples in C#." date: 2022-08-22 5:57 UTC tags: [Software Design] image: "/content/binary/validation-as-a-function-from-data-to-type.png" image_alt: "An arrow labelled 'validation' pointing from a document to the left labelled 'Data' to a box to the right labelled 'Type'." --- {% include JB/setup %}
{{ page.description }}
In a comment to my article on ASP.NET validation revisited Maurice Johnson asks:
"I was just wondering, is it possible to use the type system to do the validation instead ?
"What I mean is, for example, to make all the ReservationDto's field a type with validation in the constructor (like a class name, a class email, and so on). Normally, when the framework will build ReservationDto, it will try to construct the fields using the type constructor, and if there is an explicit error thrown during the construction, the framework will send us back the error with the provided message.
"Plus, I think types like "email", "name" and "at" are reusable. And I feel like we have more possibilities for validation with that way of doing than with the validation attributes.
"What do you think ?"
I started writing a response below the question, but it grew and grew so I decided to turn it into a separate article. I think the question is of general interest.
I'm all in favour of using the type system for encapsulation, but there are limits to what it can do. We know this because it follows from the halting problem.
I'm basing my understanding of the halting problem on my reading of The Annotated Turing. In short, given an arbitrary computer program in a Turing-complete language, there's no general algorithm that will determine whether or not the program will finish running.
A compiler that performs type-checking is a program, but typical type systems aren't Turing-complete. It's possible to write type checkers that always finish, because the 'programming language' they are running on - the type system - isn't Turing-complete.
Normal type systems (like C#'s) aren't Turing-complete. You expect the C# compiler to always arrive at a result (either compiled code or error) in finite time. As a counter-example, consider Haskell's type system. By default it, too, isn't Turing-complete, but with sufficient language extensions, you can make it Turing-complete. Here's a fun example: Typing the technical interview by Kyle Kingsbury (Aphyr). When you make the type system Turing-complete, however, termination is no longer guaranteed. A program may now compile forever or, practically, until it times out or runs out of memory. That's what happened to me when I tried to compile Kyle Kingsbury's code example.
How is this relevant?
This matters because understanding that a normal type system is not Turing-complete means that there are truths it can't express. Thus, we shouldn't be surprised if we run into rules or policies that we can't express with the type system we're given. What exactly is inexpressible depends on the type system. There are policies you can express in Haskell that are impossible to express in C#, and so on. Let's stick with C#, though. Here are some examples of rules that are practically inexpressible:
Hillel Wayne provides more compelling examples in the article Making Illegal States Unrepresentable.
Depending on how many times you've been around the block, you may find the above list naive. You may, for example, say that it's possible to express that an integer is positive like this:
public struct NaturalNumber : IEquatable<NaturalNumber> { private readonly int i; public NaturalNumber(int candidate) { if (candidate < 1) throw new ArgumentOutOfRangeException( nameof(candidate), $"The value must be a positive (non-zero) number, but was: {candidate}."); this.i = candidate; } // Various other members follow...
I like introducing wrapper types like this. To the inexperienced developer this may seem redundant, but using a wrapper like this has several advantages. For one, it makes preconditions explicit. Consider a constructor like this:
public Reservation( Guid id, DateTime at, Email email, Name name, NaturalNumber quantity)
What are the preconditions that you, as a client developer, has to fulfil before you can create a valid Reservation
object? First, you must supply five arguments: id
, at
, email
, name
, and quantity
. There is, however, more information than that.
Consider, as an alternative, a constructor like this:
public Reservation( Guid id, DateTime at, Email email, Name name, int quantity)
This constructor requires you to supply the same five arguments. There is, however, less explicit information available. If that was the only available constructor, you might be wondering: Can I pass zero as quantity
? Can I pass -1
?
When the only constructor available is the first of these two alternatives, you already have the answer: No, the quantity
must be a natural number.
Another advantage of creating wrapper types like NaturalNumber
is that you centralise run-time checks in one place. Instead of sprinkling defensive code all over the code base, you have it in one place. Any code that receives a NaturalNumber
object knows that the check has already been performed.
There's a word for this: Encapsulation.
You gather a coherent set of invariants and collect it in a single type, making sure that the type always guarantees its invariants. Note that this is an important design technique in functional programming too. While you may not have to worry about state mutation preserving invariants, it's still important to guarantee that all values of a type are valid.
It's debatable whether the above NaturalNumber
class really uses the type system to model what constitutes valid data. Since it relies on a run-time predicate, it falls in the category of types Hillel Wayne calls predicative. Such types are easy to create and compose well, but on the other hand fail to take full advantage of the type system.
It's often worthwhile considering if a constructive design is possible and practical. In other words, is it possible to make illegal states unrepresentable (MISU)?
What's wrong with NaturalNumber
? Doesn't it do that? No, it doesn't, because this compiles:
new NaturalNumber(-1)
Surely it will fail at run time, but it compiles. Thus, it's representable.
The compiler gives you feedback faster than tests. Considering MISU is worthwhile.
Can we model natural numbers in a constructive way? Yes, with Peano numbers. This is even possible in C#, but I wouldn't consider it practical. On the other hand, while it's possible to represent any natural number, there is no way to express -1 as a Peano number.
As Hillel Wayne describes, constructive data types are much harder and requires a considerable measure of creativity. Often, a constructive model can seem impossible until you get a good idea.
"a list can only be of even length. Most languages will not be able to express such a thing in a reasonable way in the data type."
Such a requirement may look difficult until inspiration hits. Then one day you may realise that it'd be as simple as a list of pairs (two-tuples). In Haskell, it could be as simple as this:
newtype EvenList a = EvenList [(a,a)] deriving (Eq, Show)
With such a constructive data model, lists of uneven length are unrepresentable. This is a simple example of the kind of creative thinking you may need to engage in with constructive data modelling.
If you feel the need to object that Haskell isn't 'most languages', then here's the same idea expressed in C#:
public sealed class EvenCollection<T> : IEnumerable<T> { private readonly IEnumerable<Tuple<T, T>> values; public EvenCollection(IEnumerable<Tuple<T, T>> values) { this.values = values; } public IEnumerator<T> GetEnumerator() { foreach (var x in values) { yield return x.Item1; yield return x.Item2; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }
You can create such a list like this:
var list = new EvenCollection<string>(new[] { Tuple.Create("foo", "bar"), Tuple.Create("baz", "qux") });
On the other hand, this doesn't compile:
var list = new EvenCollection<string>(new[] { Tuple.Create("foo", "bar"), Tuple.Create("baz", "qux", "quux") });
Despite this digression, the point remains: Constructive data modelling may be impossible, unimagined, or impractical.
Often, in languages like C# we resort to predicative data modelling. That's also what I did in the article ASP.NET validation revisited.
That was a long rambling detour inspired by a simple question: Is it possible to use types instead of validation?
In order to address that question, it's only proper to explicitly state assumptions and definitions. What's the definition of validation?
I'm not aware of a ubiquitous definition. While I could draw from the Wikipedia article on the topic, at the time of writing it doesn't cite any sources when it sets out to define what it is. So I may as well paraphrase. It seems fair, though, to consider the stem of the word: Valid.
Validation is the process of examining input to determine whether or not it's valid. I consider this a (mostly) self-contained operation: Given the data, is it well-formed and according to specification? If you have to query a database before making a decision, you're not validating the input. In that case, you're applying a business rule. As a rule of thumb I expect validations to be pure functions.
Validation, then, seems to imply a process. Before you execute the process, you don't know if data is valid. After executing the process, you do know.
Data types, whether predicative like NaturalNumber
or constructive like EvenCollection<T>
, aren't processes or functions. They are results.
Sometimes an algorithm can use a type to infer the validation function. This is common in statically typed languages, from C# over F# to Haskell (which are the languages with which I'm most familiar).
In a way you can think of the type system as a domain-specific language (DSL) for defining validation functions. It's not perfectly suited for that task, but often good enough that many developers reach for it.
Consider the ReservationDto
class from the ASP.NET validation revisited article where I eventually gave up on it:
public sealed class ReservationDto { public LinkDto[]? Links { get; set; } public Guid? Id { get; set; } [Required, NotNull] public DateTime? At { get; set; } [Required, NotNull] public string? Email { get; set; } public string? Name { get; set; } [NaturalNumber] public int Quantity { get; set; } }
It actually tries to do what Maurice Johnson suggests. Particularly, it defines At
as a DateTime?
value.
> var json = "{ \"At\": \"2022-10-11T19:30\", \"Email\"<EMAIL_ADDRESS>\"Quantity\": 1}"; > JsonSerializer.Deserialize<ReservationDto>(json) ReservationDto { At=[11.10.2022 19:30:00]<EMAIL_ADDRESS>Id=null, Name=null, Quantity=1 }
A JSON deserializer like this one uses run-time reflection to examine the type in question and then maps the incoming data onto an instance. Many XML deserializers work the same way.
What happens if you supply malformed input?
> var json = "{ \"At\": \"foo\", \"Email\"<EMAIL_ADDRESS>\"Quantity\": 1}"; > JsonSerializer.Deserialize<ReservationDto>(json) System.Text.Json.JsonException:↩ The JSON value could not be converted to System.Nullable`1[System.DateTime].↩ Path: $.At | LineNumber: 0 | BytePositionInLine: 26.↩ [...]
(I've wrapped the result over multiple lines for readability. The ↩
symbol indicates where I've wrapped the text. I've also omitted a stack trace, indicated by [...]
. I'll do that repeatedly throughout this article.)
What happens if we try to define ReservationDto.Quantity
with NaturalNumber
?
> var json = "{ \"At\": \"2022-10-11T19:30\", \"Email\"<EMAIL_ADDRESS>\"Quantity\": 1}";
> JsonSerializer.Deserialize<ReservationDto>(json)
System.Text.Json.JsonException:↩
The JSON value could not be converted to NaturalNumber.↩
Path: $.Quantity | LineNumber: 0 | BytePositionInLine: 67.↩
[...]
While JsonSerializer is a sophisticated piece of software, it's not so sophisticated that it can automatically map 1
to a NaturalNumber
value.
I'm sure that you can configure the behaviour with one or more JsonConverter objects, but this is exactly the kind of framework Whack-a-mole that I consider costly. It also suggests a wider problem.
What happens if input to a validation function is malformed? You may want to report the errors to the caller, and you may want to report all errors in one go. Consider the user experience if you don't: A user types in a big form and submits it. The system informs him or her that there's an error in the third field. Okay, correct the error and submit again. Now there's an error in the fifth field, and so on.
It's often better to return all errors as one collection.
The problem is that type-based validation doesn't compose well. What do I mean by that?
It's fairly clear that if you take a simple (i.e. non-complex) type like NaturalNumber
, if you fail to initialize a value it's because the input is at fault:
> new NaturalNumber(-1) System.ArgumentOutOfRangeException: The value must be a positive (non-zero) number, but was: -1.↩ (Parameter 'candidate') + NaturalNumber..ctor(int)
The problem is that for complex types (i.e. types made from other types), exceptions short-circuit. As soon as one exception is thrown, further data validation stops. The ASP.NET validation revisited article shows examples of that particular problem.
This happens when validation functions have no composable way to communicate errors. When throwing exceptions, you can return an exception message, but exceptions short-circuit rather than compose. The same is true for the Either monad: It short-circuits. Once you're on the failure track you stay there and no further processing takes place. Errors don't compose.
The naive take on validation is to answer the question: Is that data valid or invalid? Notice the binary nature of the question. It's either-or.
This is true for both predicative data and constructive data.
For constructive data, the question is: Is a candidate value representable? For example, can you represent -1 as a Peano number? The answer is either yes or no; true or false.
This is even clearer for predicative data, which is defined by a predicate. (Here's another example of a natural number specification.) A predicate is a function that returns a Boolean value: True or false.
It's possible to compose Boolean values. The composition that we need in this case is Boolean and, which is also known as the all monoid: If all values are true, the composed value is true; if just one value is false, the composed value is false.
The problem is that during composition, we lose information. While a single false value causes the entire aggregated value to be false, we don't know why. And we don't know if there was only a single false value, or if there were more than one. Boolean all short-circuits on the first false value it encounters, and stops processing subsequent predicates.
In logic, that's all you need, but in data validation you often want to know what's wrong with the data.
Fortunately, this is a solved problem. Use applicative validation, an example of which I supplied in the article An applicative reservation validation example in C#.
This changes focus on validation. No longer is validation a true/false question. Validation is a function from less-structured data to more-structured data. Parse, don't validate.
Can types replace validation?
In some cases they can, but I think that the general answer is no. Granted, this answer is partially based on capabilities of current deserialisers. JsonSerializer.Deserialize short-circuits on the first error it encounters, and the same does aeson's eitherDecode.
While that's the current state of affairs, it may not have to stay like that forever. One might be able to derive an applicative parser from a desired destination type, but I haven't seen that done yet.
It sounds like a worthwhile research project.
Comments
This slightly reminds me of Zod which is described as "TypeScript-first schema validation with static type inference".
The library automatically infers a type that matches the validation - in a way it blurs this line between types and validation by making them become one.
Of course, once you have that infered type there is nothing stopping you using it without the library, but that's something code reviews could catch. It's quite interesting though.


ROSHN
Visualization
Logout
National
International
Both
From
To
Oops! Something went wrong.
{{$ctrl.error ? $ctrl.error : "Unexpected error"}}
Invalid Email or Password!
Login


Enterprise edition: $99 a month
unlimited accounts, unlimited screens, unlimited components, unlimited bandwidth, unlimited storage, unlimited advertisers, unlimited SignagePlayers, unlimited campaigns, unlimited users, unlimited business, unlimited branding, unlimited... everything!
keep me posted on news, events and product introductions
Enterprise edition status
Manage your subscription


On the anniversary of my first month at MS, I took my first meeting with a Sr. Vice President. I'm told that's a big deal. One colleague who'd been at MS for a few years said, "Wow. You must be important. I expect that the first time I'll be in a meeting with a Sr. VP will be at my firing." In my case, it's not that I'm important (I'm not) that got me involved with such a meeting; it's that I have recently been asked to participate in a project that needed to meet with the VP to clarify some review feedback . Or, in other words, it was a pretty pedestrian "here's what we've come up with since the last time we met" kind of meeting. What made it interesting was that it was with a Eric.
Imagine a company run as a strict meritocracy that's one of the most important and profitable in it's industry. Now imagine that this company has been around for a while and has acquired tens of thousands of employees in a multi-layered hierarchy, with only the best and the brightest surviving and the best of the best rising to the top. That's MS. Billg is layer 1. Eric is at layer 4 w/ a small number of peers. I'm at layer 9 or, as I like to call it, "the bottom." By all rights, that means that Eric should be "5" smarter than me, and I can see him fitting comfortably into that category.
Had Eric wanted to shred us, I'm sure he could have. Luckily, it was a nice, calm, productive meeting w/ him cutting quickly to the main points (in spite of the fact that he was reading and making notes on our handouts while still listening to our presentation). He also make some pretty interesting comments, especially considering how little time I'm guessing he's had to think about the problem space. At least one comment put me on a path that I like much better than the one I was on (although we'll see how he feels about it at the next review). The comment that startled me most, however, was when he said that he read my site. If this is my last post from inside the big house, you'll know how much he liked it. : )


CHAPTER 27
STATE FUNCTIONS AND RESPONSIBILITIES
Part I. General Provisions
Section
27-1 Functions of statewide concern
27-2 Assignment of functions by governor; report
27-3 Rights and powers transferred; bond obligations
27-4 Offenses and penalties not affected; suits and actions
27-5 Modification to preserve federal aid or bond
obligations
27-6 Extended state information and services provided
27-7 Departmental data sharing
Part II. Schools
27-11 Planning, construction, and improvements of public
school facilities and grounds; custodial and janitorial
services for public schools; transportation of school
children
27-12, 13 Repealed
27-14 Transfer of real property
27-15 Repealed
Part III. Health
27-21, 21.1, 21.2, 21.3 Repealed
27-21.4 Transfer of real property
27-21.5 Repealed
27-21.6 Functions reassigned to the counties
27-22, 22.5, 22.7, 23, 24 Repealed
Part IV. Junior Police
27-26 Junior police officer training programs
Part V. Highways; Parks; Historical Sites
27-31 Maintenance of state highways
27-32 Maintenance of state parks
Part VI. Review
27-36 Repealed
Part VII. Technology
27-41 Special advisor for technology development
27-41.1 Definitions
27-42 Repealed
27-43 Office of enterprise technology services; chief
information officer; information technology steering
committee; establishment; responsibilities
27-43.5 Additional duties of the chief information officer
relating to security of government information
27-43.6 Additional duties of the chief information officer
relating to independent verification and validation of
information technology projects of the executive branch
27-44 Electronic data set availability; updates
27-44.1 State liability for data sets
27-44.2 Data set licensing
27-44.3 Data set policies and procedures
27-45 Broadband-related permits; automatic approval
Part VIII. Hawaii Performance Partnerships Board
27-51 Hawaii performance partnerships board; establishment
27-52 Duties of the board
27-53 Annual report
27-54 Data collection relating to the well-being of Hawaii's
children and families
Cross References
Uniform electronic transactions act, see chapter 489E.


When I came across Salvia Divinorum, I was very interested since I remember seeing it advertised on various websites (quick note, I'm a somewhat experienced drug user myself. I've done weed, opium, acid, ecstacy, and shrooms) I read reports and decided to try it, but after a while I gave up hope until a friend of mine said 'What's something cool I should try?' So I suggested Salvia, and he ordered a half ounce online and sure enough it arrived.
He said it looked like dry leaves. He tried it out before me and said it didn't work. He described to me how/how much he smoked, and obviously it wasn't working right.
So last night, Me, C, and M were in my basement and we rigged a bong out of a 2 liter bottle. This was about 12:30 at night. We smoked about 5 bong pack each. We were all sober at the time, with a good mindset. M said he really didn't like what his body felt, maybe his body was rejecting it. So he sat down and after a few minutes felt better. While he was sitting, C and I kept smoking bong packs.
I kept getting this really, REALLY odd sensation that I had to 'declare borders' and make 'distance measurements'. This is very odd to describe but here goes: where I was sitting, I felt like there was this force field behind me and I had to figure out where the rest of the force field was. C was noticing the same thing as well.  I took it off and it seemed to liven up the mood I was having. M joined us again and started smoking some more. He didn't feel anything, but C and I were having the oddest mind trip. No melting walls or anything like that. I'd say I was having a pure mind trip, no visuals or anything like that but I was having the rest of the trip properties, not sure if what you say makes sense, or hard to make sense of what other people are saying, having no idea what's going on, stuff like that. Time set for right about now was 1:20 AM.
Anyways, we felt bummed, we were all psyched beforehand now we were bummed. I asked if C would loan me some of the salvia, I wanted to try some more by myself. He gave me a TON...I thought it looked like more than a quarter of MJ. So C and M left, and I went into my room.  Time: 1:32 AM.
One bowl: gone. Nothing much
Two bowls: gone. Starting to get the mind trip
Three bowls: gone. Good mind trip
Four bowls through 6: gone. Wow.
Brain's starting to have a mind of it's own. Time: 1:37.
Bowl number 7: gone.
My Pink Floyd: Back Catalogue poster (if you've ever seen it, it's the one of all the naked women sitting by a pool with the album covers painted on their backs) starts to move, the women are conversing with each other...I don't hear anything, but their mouths are moving. The album covers are alive.
Bowls 8 and 9: gone. Wow.
IT WORKS! SWEET! The music became so ambient that I really connected with it. It was resonating throughout my room and my head. And for the weirdest reason, my nose felt very runny. Has this happened to anyone?
Anyways the trip started getting really cool now. My room grew dark. My walls glowed a faint purple, as if my entire room were decorated with black lights. But my ceiling. Wow. It turned into this brightly colored, swirly fractal vortex, constantly changing colors, having so many textures, it looked like it was just a few inches below my ceiling, just spinning there.
This continued for a few minutes more. As it was going on, the vortex expanded and grew in and out, through the ceiling (I saw it in the ceiling, as if the ceiling became transparent), it moved from side to side, shrank, and then went back to it's original shape. Then it stopped spinning, and then started spinning backwards.
Right about now, Dark Side Of The Moon was at Money, David Gilmour was still singing, his guitar solo hadn't happened yet. As he was singing, all of a sudden his face appeared through the vortex in a SUPER colorful bubble and it started spinning slowly with the vortex. Oddly, his face started out young and started to age as it circled with the vortex. Then it disappeared. Then suddenly the rest of Pink Floyd's members heads started appearing in bubbles, one after the other, growing young to old and disappearing.
Then all of a sudden the vortex died out. It just seemed to vanish. My room was bright, as if my overhead light was just turned on, them it turned blue, and everything in my room started growing these red spots. It's not like red spots appeared on top of things, it was like they were inside everything and tried to push their ways out. I saw the materials being pushed out of the way of the red spots.
I looked over to the wall to my right and it turned a very pale pink. It looked like it was covered in some sort of goo. I reached over to touch it, and it started to ripple, as if I dropped a stone in water. My entire room started to ripple (well, just my walls and carpet, my bed and dresser were mysteriously fine). Then the place where I touched started to grow out. This pale goo turned into what looked like a building, then more 'buildings' were sprouting up and shrinking back to nothing at a surprisingly fast rate (I'd say about 10 seconds).
Then the oddest thing happened. If anyone's ever played Mortal Kombat 2, you'd remember 'The Living Forest', the level with the talking trees. Those talking trees were on my ceiling. I turned my head for one second, I looked back, and they were there. It surprised the hell out of me, but didn't really scare me. Also, if you've ever watched Sesame Street, you'd probably recognize those alien creatures with the big mouths that kept going 'yyyyep yep yep yep yep yep yep. Uh huh uh huh uh huh uh huh.' Those trees were doign that yep yep uh uh thing for like 5 minutes. There were about 10 trees. 9 of them were 'yep yep uh huh', and one was always talking to me about my love for weed (yup I'm a pothead). Then that one started going 'yep yep uh huh' and a different tree started talking normally to me about my love for acid.
Then suddenly the trees started shrinking, my walls stopped melting, and my room was back to its original shape.  I looked around. I was fine. I looked at my clock, this trip was about 25 minutes long, it was almost 2 AM. Not at any point in time was I scared, my mind never was screwing with me. In fact I barely had any thoughts at all, most of it was 'wow that's awesome!'
I had an absolute blast with salvia. Most people need a sitter, I am a very strong willed person, so I can handle myself. But I can see why some people would be scared of their experience. But be warned, people. This can be too much.
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


--- title: Open Model Project layout: default bodyClass: page-home ---
We Have A Podcast! |
The Open Model Project podcast is available now on your favorite podcasting app. |
{{ service.content | markdownify | strip_html | truncate: 100 }}


As seen in a previous post, Reinforcement Learning (RL) is a very rich and active research area in Machine Learning; it is defined in the very excellent book Reinforcement Learning: An Introduction as "computational approach to learning from interaction". It is a technique of choice to learn a sequence of actions for a given task.
We have seen the basics algorithms of RL for Planning, which means given a full model of an environment, how can we compute the optimal Value or Policy.
In this post, we are going to go through the Learning algorithms of Reinforcement Learning when the environment is unknown, and we try to estimate optimal policies from experience, namely, for finite state spaces:
- TD(0)
- Every Visit Monte Carlo
- $TD(\lambda)$
and for large state spaces:
- TD(0)
- Every Visit Monte Carlo
- $TD(\lambda)$
The Learning Scenario - a refresher:
Let's first go briefly through the learning scenario in RL. There are two entities in this scenario: the agent and the environment. Both entities interact through actions, states and rewards. The agent performs an action, which has an influence on the environment, and he receives two types of information: his current state in the environment and a reward corresponding to his action in the given state he was in, and the defined goal. The ultimate objective of the agent is to optimize his sequence of action, the policy.
Useful Definitions
Let's suppose we have a set of time points at which the agent interacts with the environment, namely Decision Epochs - most likely discrete in our case-; it will be noted \( {0, 1, ..., T} \). \( T\), the Horizon, might be finite or infinite. We now can introduce some concepts inherent to RL.
Markov Decision Process
The environment can be modelled through a Markov Decision Process. It is defined by:
- A countable set of States \( \mathcal{S} \)
- A countable set of Actions \( \mathcal{A} \)
- A transition Probability function: $$ \begin{align*} P & : & \mathcal{S} \times \mathcal{A} \times \mathcal{S} \longrightarrow & [0 ,1] \\ & & (s', a, s) \longmapsto & P(s_{t+1} = s' \vert s_t = s, a_t = a) \end{align*} $$ the probability that the agent will be in state \( s' \) at \( t+1 \) when in state \( s \) at time \( t \) and performing action \( a \). We will note the probability of this outcome \( P_{(s, s')}^a\).
- \( R^{a}_{(s, s')} \) is the expected immediate reward received after transitioning from state \( s \) to state \( s' \), due to action \( a \)
- \( \gamma \in [0, 1]\) the discount factor; it determines the value at time \( t \) of the future rewards from \( t+1 \) to \( T \). It is usually \( < 1 \), it models the fact that an immediate reward is better than an uncertain reward in the future. Insuring that it is strictly inferior to 1 also ensures that the sum is finite with an infinite horizon.
The future states and rewards are independent of the past, given the present. Let's precise that in our case, the states are fully observable.
Policy
A policy in this context is a map from states to probability distributions over actions \( \pi : S \rightarrow P(A=a \vert \mathcal{S}) \).
Return
Let's denote \( r_t = R^{a_t}_{(s_t, s_{t+1})}\) the reward for taking the action \( a \) at time \( t \) from state \(s_t \) to state \( s_{t+1} \), to make the notations slightly lighter. Then:- The Return is defined as: \( R_t = \sum_{k=0}^{N-1}r_{t+k+1}\),
- The Discounted Return is defined as: \( R_t = \sum _{k=0}^{T-1}\gamma^{k} r_{t+k+1}\) ,
Value Function
The Value Function gives an estimate of "how good" - in terms of expected return- it is for the agent to be in a given state, or to perform a given action in a given state.
- The Value Function for a given policy \( \pi \) is defined as: \( \forall s, V^{\pi }(s) = \mathbb{E}[R_t \vert s_t=s] \). It is the expected return when starting in state \(s\) and following \(pi\) thereafter.
- We can also define the Action Value Function for policy \( \pi \) as: \( Q^{\pi}(s, a) = \mathbb{E}_{\pi} [R_t \vert s_t = s, a_t = a]\)
- The Optimal Value Function is defined as: \( \forall s \in \mathcal{S}, V^{*}(s)=\max \limits _{\pi}V^{\pi }(s) \),
- The Optimal Action-Value Function is defined as: \( \forall (s,a) \in \mathcal{S} \times \mathcal{A}, Q^{*}(s, a )=\max \limits_{\pi}Q^{\pi }(s, a) \).
Now is probably a good time to mention this property, which will be essential in our peregrinations: $$ \begin{align*} \forall s \in \mathcal{S}, V^{*}(s) = \max \limits_{a \in \mathcal{A}} \sum_{s' \in \mathcal{S}} P_{(s,s')}^a [R_{(s,s')}^a + \gamma V^{*}(s')] \end{align*} $$ This equation is called the Bellman's optimality equation. This can be proven using the recursive relation in the definition of the Value Function and Return.
A policy is optimal if it has maximal value \( \forall s \in \mathcal{S}\). We can write this as: $$ \begin{align*} \forall s \in \mathcal{S}, \pi^{*}(s) = \arg \max \limits_{a \in \mathcal{A}} Q^{*} (s,a) \end{align*}$$
Monte Carlo methods
In this section, we'll see how Monte Carlo methods can be used for learning the state-value function for a given policy. Monte Carlo methods in general consist of running an experience \(n\) times and averaging the results - if \(n\) is large enough, the average of these results should converge towards its expected value; in the context of reinforcement learning, it consists of averaging the returns observed after visits to a state.
Suppose we wish to estimate \(v_{\pi}(s)\), the value of a state \(s\) under policy \(\pi\), given a set of episodes obtained by following \(\pi\) and passing through \(s\). Each occurrence of state \(s\) in an episode is called a visit to \(s\). Of course, \(s\) may be visited multiple times in the same episode; let us call the first time it is visited in an episode the first visit to \(s\). The first-visit MC method estimates \(v_{\pi}(s)\) as the average of the returns following first visits to s, whereas the every-visit MC method averages the returns following all visits to \(s\). These two Monte Carlo (MC) methods have slightly different theoretical properties. Every-visit MC extends more naturally to function approximation and eligibility traces.
Policy Evaluation /
If a model is not available, then it is particularly useful to estimate action values (the values of state– action pairs) rather than state values. With a model, state values alone are sufficient to determine a policy; one simply looks ahead one step and chooses whichever action leads to the best combination of reward and next state. Without a model, however, state values alone are not sufficient. One must explicitly estimate the value of each action in order for the values to be useful in suggesting a policy. Thus, one of our primary goals for Monte Carlo methods is to estimate q∗. To achieve this, we first consider the policy evaluation problem for action values.
$TD(0)$
TD learning is a combination of Monte Carlo ideas and dynamic programming (DP) ideas, that we saw in the previous reinforcement learning post. TD methods learn from experience without a model of the environment's dynamics. Like DP, TD methods update estimates based in part on other learned estimates, without waiting for a final outcome (they bootstrap).
We'll start with policy evaluation (prediction), or estimating the value function for a given policy, and then we'll continue with control problem (finding an optimal policy).
As pseudo code is usually very clarifying for most algorithms, here it is of the Policy Iteration (this may not display well on navigators that are not Chrome - trying to find an alternative, but for now this will do):
\begin{algorithm} \caption{Policy Iteration} \begin{algorithmic} \PROCEDURE{Policy-Iteration}{$\pi_0, \mathcal{S}, \mathcal{A}, P, r, \theta, \gamma$} \STATE $\pi \leftarrow \pi_0$ \STATE $\Delta \leftarrow 0$ \WHILE{$ \Delta < \theta $} \COMMENT {Policy Evaluation} \STATE {$\Delta \leftarrow 0$} \FOR{$s \in \mathcal{S}$} \STATE {$v \leftarrow V(s)$} \STATE {$V(s) \leftarrow \max \limits_{a} \sum_{s'} P_{(s, s')}^a [R_{(s, s')}^a + \gamma V(s')]$} \STATE {$\Delta \leftarrow \max(\vert v - V(s)\vert)$} \ENDFOR \ENDWHILE \STATE {policyStable $\leftarrow$ \TRUE} \COMMENT {Policy Improvement} \FOR{$s \in \mathcal{S}$} \STATE {$b \leftarrow \pi (s)$} \STATE {$\pi(s) \leftarrow \arg\max \limits_{a} \sum_{s'} P_{(s, s')}^a [R_{(s,s')}^a + \gamma V(s')]$} \IF{$b \neq \pi(s)$} \STATE policyStable $\leftarrow$ \FALSE \ENDIF \ENDFOR \IF{policyStable} \COMMENT {If algorithm has converged} \STATE stop \ELSE \STATE Go to Policy Evaluation \ENDIF \RETURN $\pi$ \ENDPROCEDURE \end{algorithmic} \end{algorithm}
This pseudocode is from Reinforcement Learning: An Introduction. The policy iteration algorithm generates a sequences of policies with non-decreasing performance, which means that the value at iteration \( k+1 \) cannot be smaller than the value function at iteration \(k\).
The proof of convergence of this algorithm can be obtained through the Bellman Operator and using its Monotonicity property.
In order to get a more pragmatic idea on how to implement this, and how the two algorithms differ, let's have a look how this algorithm is implemented in practice. There is some very readable code available here , but here is my take on the Python code. Let's first install the OpenAI Gym in Python by simply doing:
sudo pip install gym
Then we are going to use the Frozen Lake environment in the OpenAI Gym; it is a pretty simple environment, with a small state set and a small action set.
import numpy as np
from gym.envs.toy_text import FrozenLakeEnv, CliffWalkingEnv
import time
env = FrozenLakeEnv()
Here is a simple-to-read code for Policy Iteration:
def policy_iteration(env, theta=0.000001, discount_factor=0.9999):
"""
Policy Iteration Algorithm. Alternates Policy Evaluation Step with Policy Improvement Step.
The notations are from Reinforcement Learning: An Introduction, by Sutton et al.
:param env: OpenAI environment. In this environment, env.P is a dictionary with two keys - state, action- that
contains the transition probabilities of the environment, the next state and the reward for each
possible pair (state, action) in a tuple.
:param theta: float, threshold for convergence
:param discount_factor: float, discount factor, should be <1 for convergence.
:return: tuple(np.array([n_states x n_actions]), float), (policy,V) , the optimal policy, and optimal value function
"""
# Set initial policy
policy = np.ones([env.nS, env.nA]) / (env.nA * env.nS)
while True: # As long as the policy is the same as the previous one, we haven't converged.
# Policy Evaluation Step
##################################
# Set Value function to 0
V = np.zeros(env.nS)
converged = False
while not converged:
delta = 0
for s in range(env.nS): # For each state compute and store Value
v = 0
for a, action_probability in enumerate(policy[s]):
for p, next_state, rt, flag in env.P[s][a]:
# Compute Value
v += action_probability * p * (rt + discount_factor * V[next_state])
# Update Delta for this state
delta = max(delta, np.abs(v - V[s]))
V[s] = v
# When the Value Function doesn't change much anymore, we have converged for the policy evaluation step
if delta < theta:
converged = True
# Policy Improvement Step
##################################
# Flag to check convergence introduced in Sutton et al.
policy_stable = True
# Go through all states
for s in range(env.nS):
# Get the best action for this state under current policy
a_opt = np.argmax(policy[s])
# Get the action that maximizes the value
action_values = np.zeros(env.nA)
for a in range(env.nA): # Computes Action Values in order to obtain the best action
for p, next_state, rt, flag in env.P[s][a]:
action_values[a] += p * (rt + discount_factor * V[next_state])
# Compute the greedy policy
best_a = np.argmax(action_values)
if a_opt != best_a: # Check if the policy from previous step is different from the current one
policy_stable = False
policy[s] = np.eye(env.nA)[best_a] # Update the current policy for next Policy Evaluation step
# If the policy is stable we've found an optimal policy. Return it
if policy_stable:
return policy, V
This should give something like this for the Frozen Lake Environment, and the displayed default parameters:
Policy Iteration: Starting.... Executed in 0.0664029121399 seconds Policy: [[ 1. 0. 0. 0.] [ 0. 0. 0. 1.] [ 0. 0. 0. 1.] [ 0. 0. 0. 1.] [ 1. 0. 0. 0.] [ 1. 0. 0. 0.] [ 1. 0. 0. 0.] [ 1. 0. 0. 0.] [ 0. 0. 0. 1.] [ 0. 1. 0. 0.] [ 1. 0. 0. 0.] [ 1. 0. 0. 0.] [ 1. 0. 0. 0.] [ 0. 0. 1. 0.] [ 0. 1. 0. 0.] [ 1. 0. 0. 0.]]
Value Iteration
The main issue with Policy Iteration is that it involves multiple sweepings of the state space \( \mathcal{S} \), which may be problematic with very large state spaces. The idea in Value Iteration (VI) is to truncate the Policy Evaluation after one sweep. This basically means using the Bellman's optimality equation as an update rule: $$ \begin{align*} \forall s \in \mathcal{S}, V_{k+1}(s) = \max \limits_{a} \sum_{s' \in \mathcal{S}} P_{(s,s')}^a [R_{(s,s')}^a + \gamma V_{k}(s')] \end{align*} $$ It can be proven that the Bellman equation admits a fixed point in \( V\), and this tells us that at every iteration, the value gets closer to its optimal value. Hence, at each iteration, the algorithms returns a greedy policy.
Here is the pseudo code for the VI algorithm:
\begin{algorithm} \caption{Value Iteration} \begin{algorithmic} \PROCEDURE{Value-Iteration}{$\pi_0, \mathcal{S}, \mathcal{A}, P, r, \theta, \gamma$} \STATE $V \leftarrow 0$ \STATE $\Delta \leftarrow 0$ \WHILE{$ \Delta < \theta $} \STATE {$\Delta \leftarrow 0$} \FOR{$s \in \mathcal{S}$} \STATE {$v \leftarrow V(s)$} \STATE {$V(s) \leftarrow \max \limits_{a} \sum_{s'} P_{(s, s')}^a [R_{(s, s')}^a + \gamma V(s')]$} \STATE {$\Delta \leftarrow \max(\vert v - V(s)\vert)$} \ENDFOR \ENDWHILE \FOR{$s \in \mathcal{S}$} \STATE {$\pi(s) \leftarrow \arg\max \limits_{a} \sum_{s'} P_{(s, s')}^a [R_{(s,s')}^a + \gamma V(s')]$} \ENDFOR \RETURN $\pi$ \ENDPROCEDURE \end{algorithmic} \end{algorithm}
This algorithm converges in polynomial time, monotonically and is robust to uncertainty.
For these who are interested in proofs, the proof of convergence relies on proving that the optimal value is a fixed point in the Bellman equation. This is relatively straightforward to prove through the Bellman Operator and Banach Fixed Point Theorem, which we won't detail in this post, but you can take a look here .
A simple-to-read code for Value iteration is:
def value_iteration(env, theta=0.0000001, discount_factor=0.99):
"""
Value Iteration Algorithm.
The notations are from Reinforcement Learning: An Introduction, by Sutton et al.
:param env: OpenAI environment. In this environment, env.P is a dictionary with two keys - state, action- that
contains the transition probabilities of the environment, the next state and the reward for each
possible pair (state, action) in a tuple.
:param epsilon: float, threshold for convergence
:param discount_factor: float, discount factor, should be <1 for convergence.
:return: tuple(np.array([n_states x n_actions]), float), (policy,V) , the optimal policy, and optimal value function
"""
# Initialize value function
values = np.zeros(env.nS)
converged = False
while not converged:
# Stopping condition
delta = 0
# Go through all states
for s in range(env.nS): # Go through all states
# Find the best action
actions = np.zeros(env.nA) # Initialize actions vector
for a in range(env.nA): # Go through all actions
for p, next_state, rt, flag in env.P[s][a]: # Compute each action value
actions[a] += p * (rt + discount_factor * values[next_state])
# Get the value of best action
best_action_value = np.max(actions)
# Update delta for this state
delta = max(delta, np.abs(best_action_value - values[s]))
# Update value function
values[s] = best_action_value
# Convergence criteria
if delta < theta:
converged = True
# Determine optimal policy through value function
policy = np.zeros([env.nS, env.nA])
for s in range(env.nS):
# Get best actions for each state
actions = np.zeros(env.nA)
for a in range(env.nA):
for p, next_state, rt, flag in env.P[s][a]:
actions[a] += p * (rt + discount_factor * values[next_state])
best_action = np.argmax(actions)
# Get optimal policy with an indicator matrix
policy[s, best_action] = 1.0
return policy, values
This function should give this output for the Frozen Lake environment and the given default parameters:
Value Iteration: Starting.... Executed in 0.0293328762054 seconds Policy: [[ 1. 0. 0. 0.] [ 0. 0. 0. 1.] [ 0. 0. 0. 1.] [ 0. 0. 0. 1.] [ 1. 0. 0. 0.] [ 1. 0. 0. 0.] [ 1. 0. 0. 0.] [ 1. 0. 0. 0.] [ 0. 0. 0. 1.] [ 0. 1. 0. 0.] [ 1. 0. 0. 0.] [ 1. 0. 0. 0.] [ 1. 0. 0. 0.] [ 0. 0. 1. 0.] [ 0. 1. 0. 0.] [ 1. 0. 0. 0.]]
We can see that both algorithms converge towards the same policy. The Policy Iteration takes more time than the value iteration for the same value of \( \theta \). But if you increase \( \theta \), you will still get the same optimal policy, and in fewer iterations (and time) than the Value Iteration algorithm. I encourage some playing with the parameters!!! You can find this code on my Github .
Linear Programming
For these of you who are familiar (and into) Optimization, the Bellman equation defines an Linear Programming optimization problem (linear objective function and linear constraints).
$$ \begin{align*} & \underset{V}{\text{minimize}} & & \sum_{s\in \mathcal{S}} \alpha (s) V(s)\\ & \text{subject to} & & \forall s \in \mathcal{S}, \forall a \in \mathcal{A}, V(s) \geq R_{(s,s')}^a + \gamma \sum_{s' \in \mathcal{S}} P_{(s,s')}^a V(s') \end{align*} $$\( \alpha \) can be interpreted as a probability to be in state \( s \). The number of rows (constraints) of this problem is \( \vert S \vert \vert A \vert \), and the number of columns (variables) \( \vert S \vert \). The algorithms solving LPs usually have a complexity depending on the number of rows of the problem, so we can use the dual formulation of this problem.
$$ \begin{align*} & \underset{\lambda}{\text{maximize}} & & \sum_{s\in \mathcal{S}, a \in \mathcal{A}} \lambda (s, a) R(s, a)\\ & \text{subject to} & & \forall s' \in \mathcal{S}, \sum_{a \in \mathcal{A}} \lambda (s', a) = \alpha (s') + \gamma \sum_{s \in \mathcal{S}, a \in \mathcal{A}} P_{(s,s')}^a \lambda (s, a) \\ & & & \forall s \in \mathcal{S}, \forall a \in \mathcal{A}, \lambda (s, a) \geq 0 \end{align*} $$The first constrains ensures that we are maximizing the return, and the second constraint makes sure that \( \lambda \) is a discounted sum of probabilities. The number of rows (constraints) of this problem is now \( \vert S \vert \), and the number of columns (variables) \( \vert S \vert \vert A \vert \), which is much more favorable here.
Conclusion
The two DP methods we presented here operate in sweeps through the state set. It is also interesting to note that they update an estimate based on another estimate, which boils down to bootstrapping. This is actually very interesting, since many other techniques in RL use bootstrapping, even when the environment is unknown.
Both of these methods require to store and update the Value Function at each iteration, but this can be improved by using Asynchronous DP; for instance, Asynchronous Value Iteration will update the Value for one state at each iteration, prioritizing some states for back-up. This method takes fewer state updates to converge than the previous two methods.
Finally, the Linear Programming approach is more direct, but can become rapidly intractable for larger states sets.
Here is a -non-exhaustive- table to sum it up. The \( \epsilon \) refers to an \( \epsilon \) approximation of \( V^{\pi}\), and \( r_{max} \geq \left \| r \right \|_{\infty}\).
| Algorithm | Policy Iteration | Value Iteration | Linear Programming |
|---|---|---|---|
| Complexity | \( \mathcal{O} (\vert \mathcal{S} \vert ^3)\) | \( \mathcal{O} (\vert \mathcal{A}\vert \vert \mathcal{S} \vert ^2)\) | Depends on the algorithms used to maximize the dual problem |
| Convergence rate | See “Improved and Generalized Upper Bounds on the Complexity of Policy Iteration” by B. Scherrer |
|
Depends on the algorithms used to maximize the dual problem |
| Pro | Converges in a finite number of iterations | Computationally efficient | Worst case convergence guarantees are better than DP counterparts |
| Cons | Each iteration requires a full policy estimate | Convergence is only asymptotic | Impractical for a very large number of states |
You can leave comments down here, or contact me through the contact form of this blog if you have questions or remarks on this post!


This service allows users to register for an account on the cloud infrastructure.
See other files in the parent directory for information and links to services running on this machine.


Train
Number of train dataset :
1000
1
42000
Save model
Train
Load Model
Model :
Model weights :
Load model
Test
Number of test dataset :
10
1
28000
Test and download csv
Single Test
Test image ID :
?
View
Label :


Users updating from Proximity 4.0 or later versions may choose to stay with their current MonetDB installation (MonetDB 4.6.2) or update to MonetDB Mars (4.20 for Linux/Mac OS X, 4.18.2 for Windows). The later MonetDB versions provide some performance improvements, but as the underlying database formats are not compatible, using these versions also requires converting existing databases to the newer format. See “Updating MonetDB Databases” later in this appendix for instructions on converting MonetDB 4.6.2 databases for use with MonetDB Mars.
See “Running the MonetDB database server” in Chapter 2, Getting Started with Proximity for information on using the MonetDB server with Proximity. Full MonetDB documentation is available from CWI’s website at monetdb.cwi.nl/projects/monetdb/MonetDB/Version4/Documentation/index.html.
Installing MonetDB for Linux/Mac OS X platforms
You must have administrator privileges (either by using
sudo
or being logged in as “root”)
to install MonetDB.
Change directories to /usr/local
.
> cd /usr/local
The Linux/Mac OS X binary distribution of MonetDB is not relocatable.
Extract the distribution. You must have a version of tar (e.g., GNU tar) that supports long file names.
> tar xvfz path-to-tarfile
/monet-mars-distr-platform
.tgz
where platform
reflects your operating system.
Change permissions for the Monet-mars/var
directory to permit write access.
>cd /usr/local/Monet-mars
>chmod -R a+w var
Installing MonetDB for Windows platforms
The Windows version of the MonetDB sever requires Windows 2000 Professional or later. You must be logged in as a user with administrator privileges to install MonetDB.
If you have an older version of MonetDB already installed on your
system, remove the following DLL files from the
C:\WINDOWS\System32\
directory:
libstream.dll
libmutils.dll
libMonetODBCs.dll
libMonetODBS.dll
libMapi.dll
Extract the installation files using WinZip or an equivalent application.
Run the Microsoft installer for MonetDB,
monet-mars-distr-win.msi
, by
double-clicking the file name
to start the installation wizard. Follow the instructions to install
the MonetDB server in the desired location. The default installation
directory is C:\Program Files\CWI\MonetDB
.
Proximity does not require the MonetDB ODBC driver. You can unselect this option on the third page of the installation wizard if you plan to only use MonetDB to serve Proximity databases. You can ignore warnings that “installation will fail if this component is not installed” if you are not installing the MonetDB ODBC driver; this warning refers to installing the MonetDB ODBC driver without having other required software already installed.
Your choice of installing MonetDB for “Just me” versus “All users” affects only whether MonetDB is added to the Start Menu for the current user or for all users. In all cases MonetDB stores its databases in
C:\\Documents and Settings\
username
\Application Data\MonetDB4\dbfarm\
where username
is the login name for the
current user.
Run Mserver.bat (located in the installation directory).
> C:\\Documents and Settings\username
\Application Data\MonetDB4\dbfarm\Mserver.bat
where username
is the login name of the
current user.
This creates the required directory hierarchy for MonetDB data files.
Substitute the appropriate path if you installed the Monet
server someplace other than the default location.
Enter quit();
at the Monet server prompt to
quit the server (note the parentheses and semi-colon).
[Optional] Add the MonetDB installation directory to
PATH
.


One of my goals for 2019 is to speak at 2-3 conferences. I am happy to report that I successfully completed my first conference speaking engagement on Saturday, February 9, 2019 at DevFest KC on the campus of the University of Missouri-Kansas City!
Read More →I mentioned in a previous post that I took the non-traditional road to becoming a software engineer by attending a coding bootcamp, and that I did manage to learn a few tech-ish things. Well, I also learned quite a few non-tech things during the course of the program.
Read More →I spent my morning with Dr. Shirley Davis in an amazing diversity & inclusion workshop hosted by Nonprofit Connect at the Kauffman Foundation Conference Center in Kansas City, Missouri. We broke down the difference between diversity and inclusion, why you need both, and how to achieve both in an organization.
Read More →I didn’t take the college road to becoming a software engineer. I went to college to become a rocket scientist, and I hold a B.S. in Physics for my efforts. Although aerospace engineering hasn’t become a reality for me as of yet, I am not particularly dismayed.
Read More →I gave up New Year’s resolutions two years ago in favor of mantras. Previous years proved to me that I wasn’t working on anything I “resolved” to do.
Read More →


This inspection ensures that the signatures of a public API do not expose any unstable (internal, experimental) types. For example, if a method returns an experimental class, the method itself is considered experimental because incompatible changes of the type (deletion or move to another package) lead to incompatible method signature changes.
Use the list below to specify which annotations mark an unstable API.


WOFF2 Google Font
File loaded from Google Font
And in the naked light I saw ten thousand people, maybe more.
People talking without speaking, people hearing without listening.
People writing songs that voices never shared, no one dared disturb the sound of silence.
— The sound of silence
Made by neoFelhz with love.


修改自 Cinemachine.CinemachineInputProvider 原来的脚本会自动 enable InputAction，这里把这个功能删除。 应该添加到 ViewController 的 FreeLookVC 以重载输入。 不手动添加也可以（TiyaViewController 会自动添加），但可能会有一个（没有实际影响的）Error Log。
More...
|
| virtual float | GetAxisValue (int axis) |
| | Implementation of AxisState.IInputAxisProvider.GetAxisValue(). Axis index ranges from 0...2 for X, Y, and Z. Reads the action associated with the axis. More...
|
| |
|
| int | PlayerIndex = -1 |
| | Leave this at -1 for single-player games. For multi-player games, set this to be the player index, and the actions will be read from that player's controls More...
|
| |
| InputActionReference | XYAxis |
| | Vector2 action for XY movement More...
|
| |
| InputActionReference | ZAxis |
| | Float action for Z movement More...
|
| |
|
| InputAction | ResolveForPlayer (int axis, InputActionReference actionRef) |
| | In a multi-player context, actions are associated with specific players This resolves the appropriate action reference for the specified player. More...
|
| |
|
virtual void | OnDisable () |
| |
修改自 Cinemachine.CinemachineInputProvider 原来的脚本会自动 enable InputAction，这里把这个功能删除。 应该添加到 ViewController 的 FreeLookVC 以重载输入。 不手动添加也可以（TiyaViewController 会自动添加），但可能会有一个（没有实际影响的）Error Log。
◆ GetAxisValue()
| virtual float Sarachan.UniTiya.TiyaView.VCInputProvider.GetAxisValue |
( |
int |
axis | ) |
|
|
virtual |
Implementation of AxisState.IInputAxisProvider.GetAxisValue(). Axis index ranges from 0...2 for X, Y, and Z. Reads the action associated with the axis.
- Parameters
-
- Returns
- The current axis value
◆ ResolveForPlayer()
| InputAction Sarachan.UniTiya.TiyaView.VCInputProvider.ResolveForPlayer |
( |
int |
axis, |
|
|
InputActionReference |
actionRef |
|
) |
| |
|
protected |
In a multi-player context, actions are associated with specific players This resolves the appropriate action reference for the specified player.
Because the resolution involves a search, we also cache the returned action to make future resolutions faster.
- Parameters
-
| axis | Which input axis (0, 1, or 2) |
| actionRef | Which action reference to resolve |
- Returns
- The cached action for the player specified in PlayerIndex
◆ PlayerIndex
| int Sarachan.UniTiya.TiyaView.VCInputProvider.PlayerIndex = -1 |
Leave this at -1 for single-player games. For multi-player games, set this to be the player index, and the actions will be read from that player's controls
◆ XYAxis
| InputActionReference Sarachan.UniTiya.TiyaView.VCInputProvider.XYAxis |
Vector2 action for XY movement
◆ ZAxis
| InputActionReference Sarachan.UniTiya.TiyaView.VCInputProvider.ZAxis |
Float action for Z movement
The documentation for this class was generated from the following file:
- Runtime/TiyaView/VCInputProvider.cs


Multi-track Piano-roll¶
-
class
pypianoroll.
Multitrack
(filepath=None, tracks=None, tempo=120.0, downbeat=None, beat_resolution=24, name='unknown')[source]¶ A multi-track piano-roll container
-
tracks
¶ list – List of
pypianoroll.Track
objects.
-
tempo
¶ np.ndarray, shape=(num_time_step,), dtype=float – Tempo array that indicates the tempo value (in bpm) at each time step. Length is the number of time steps.
-
downbeat
¶ np.ndarray, shape=(num_time_step,), dtype=bool – Downbeat array that indicates whether the time step contains a downbeat, i.e. the first time step of a bar. Length is the number of time steps.
-
beat_resolution
¶ int – Resolution of a beat (in time step).
-
name
¶ str – Name of the multi-track piano-roll.
Initialize the object by one of the following ways: - parsing a MIDI file - loading a .npz file - assigning values for attributes
Notes
When filepath is given, ignore arguments tracks, tempo, downbeat and name.
Parameters: - filepath (str) – File path to a MIDI file (.mid, .midi, .MID, .MIDI) to be parsed or a .npz file to be loaded.
- beat_resolution (int) – Resolution of a beat (in time step). Will be assigned to beat_resolution when filepath is not provided. Default to 24.
- tracks (list) – List of
pypianoroll.Track
objects to be added to the track list when filepath is not provided. - tempo (int or np.ndarray, shape=(num_time_step,), dtype=float) – Tempo array that indicates the tempo value (in bpm) at each time step. Length is the number of time steps. Will be assigned to tempo when filepath is not provided. If an integer is provided, it will be first converted to a numpy array. Default to 120.0.
- downbeat (list or np.ndarray, shape=(num_time_step,), dtype=bool) – Downbeat array that indicates whether the time step contains a downbeat, i.e. the first time step of a bar. Length is the number of time steps. Will be assigned to downbeat when filepath is not provided. If a list of indices is provided, it will be viewed as the time step indices of the down beats and converted to a numpy array. Default is None.
- name (str) – Name of the multi-track piano-roll. Default to ‘unknown’.
-
append_track
(track=None, pianoroll=None, program=0, is_drum=False, name='unknown')[source]¶ Append a multitrack.Track instance to the track list or create a new multitrack.Track object and append it to the track list.
Parameters: - track (pianoroll.Track) – A
pypianoroll.Track
instance to be appended to the track list. - pianoroll (np.ndarray, shape=(num_time_step, 128)) – Piano-roll matrix. First dimension represents time. Second dimension represents pitch. Available datatypes are bool, int, float.
- program (int) – Program number according to General MIDI specification [1]. Available values are 0 to 127. Default to 0 (Acoustic Grand Piano).
- is_drum (bool) – Drum indicator. True for drums. False for other instruments. Default to False.
- name (str) – Name of the track. Default to ‘unknown’.
References
[1] https://www.midi.org/specifications/item/gm-level-1-sound-set
- track (pianoroll.Track) – A
-
binarize
(threshold=0)[source]¶ Binarize the piano-rolls of all tracks. Pass the track if its piano-roll is already binarized.
Parameters: threshold (int or float) – Threshold to binarize the piano-rolls. Default to zero.
-
check_validity
()[source]¶ Raise an error if any invalid attribute found.
Raises: TypeError
– If an attribute has an invalid type.ValueError
– If an attribute has an invalid value (of the correct type).
-
clip
(lower=0, upper=127)[source]¶ Clip the piano-rolls by an lower bound and an upper bound specified by lower and upper, respectively.
Parameters: - lower (int or float) – The lower bound to clip the piano-roll. Default to 0.
- upper (int or float) – The upper bound to clip the piano-roll. Default to 127.
-
copy
()[source]¶ Return a copy of the object.
Returns: copied – A copy of the object. Return type: pypianoroll.Multitrack object
-
get_active_length
()[source]¶ Return the maximal active length (i.e. without trailing silence) of the piano-rolls (in time step).
Returns: active_length – The maximal active length (i.e. without trailing silence) of the piano-rolls (in time step). Return type: int
-
get_active_pitch_range
()[source]¶ Return the overall active pitch range of the piano-rolls.
Returns: - lowest (int) – The lowest active pitch of the piano-rolls.
- highest (int) – The lowest highest pitch of the piano-rolls.
-
get_downbeat_steps
()[source]¶ Return a list of indices of time steps that contain downbeats.
Returns: downbeat_steps – Indices of time steps that contain downbeats. Return type: list
-
get_empty_tracks
()[source]¶ Return the indices of tracks with empty piano-rolls.
Returns: empty_track_indices – List of the indices of tracks with empty piano-rolls. Return type: list
-
get_maximal_length
()[source]¶ Return the maximal length of the piano-rolls along the time axis (in time step).
Returns: maximal_length – The maximal length of the piano-rolls along the time axis (in time step). Return type: int
-
get_merged_pianoroll
(mode='sum')[source]¶ Return a merged piano-roll.
Parameters: mode ({'sum', 'max', 'any'}) – Indicate the merging function to apply along the track axis. Default to ‘sum’.
- In ‘sum’ mode, the piano-roll of the merged track is the summation of the collected piano-rolls. Note that for binarized piano-roll, integer summation is performed.
- In ‘max’ mode, for each pixel, the maximal value among the collected piano-rolls is assigned to the merged piano-roll.
- In ‘any’ mode, the value of a pixel in the merged piano-roll is True if any of the collected piano-rolls has nonzero value at that pixel; False if all piano-rolls are inactive (zero-valued) at that pixel.
Returns: merged – The merged piano-rolls. Return type: np.ndarray, shape=(num_time_step, 128)
-
get_num_downbeat
()[source]¶ Return the number of down beats. The return value is calculated based solely on downbeat.
Returns: num_bar – The number of down beats according to downbeat. Return type: int
-
get_num_track
()[source]¶ Return the number of tracks.
Returns: num_track – The number of tracks. Return type: int
-
get_stacked_pianorolls
()[source]¶ Return a stacked multi-track piano-roll. The shape of the return np.ndarray is (num_time_step, 128, num_track).
Returns: stacked – The stacked piano-roll. Return type: np.ndarray, shape=(num_time_step, 128, num_track)
-
is_binarized
()[source]¶ Return True if the pianorolls of all tracks are already binarized. Otherwise, return False.
Returns: is_binarized – True if all the collected piano-rolls are already binarized; otherwise, False. Return type: bool
-
load
(filepath)[source]¶ Load a .npz file. Supports only files previously saved by
pypianoroll.Multitrack.save()
.Notes
Previous values of attributes will all be cleared.
Parameters: filepath (str) – The path to the .npz file.
-
merge_tracks
(track_indices=None, mode='sum', program=0, is_drum=False, name='merged', remove_merged=False)[source]¶ Merge piano-rolls of tracks specified by track_indices. The merged track will have program number as given by program and drum indicator as given by is_drum. The merged track will be appended at the end of the track list.
Parameters: - track_indices (list) – List of indices that indicates which tracks to merge. If None, default to merge all tracks.
- mode ({'sum', 'max', 'any'}) –
Indicate the merging function to apply along the track axis. Default to ‘sum’.
- In ‘sum’ mode, the piano-roll of the merged track is the summation of the collected piano-rolls. Note that for binarized piano-roll, integer summation is performed.
- In ‘max’ mode, for each pixel, the maximal value among the collected piano-rolls is assigned to the merged piano-roll.
- In ‘any’ mode, the value of a pixel in the merged piano-roll is True if any of the collected piano-rolls has nonzero value at that pixel; False if all piano-rolls are inactive (zero-valued) at that pixel.
- program (int) – Program number to be assigned to the merged track. Available values are 0 to 127.
- is_drum (bool) – Drum indicator to be assigned to the merged track.
- name (str) – Name to be assigned to the merged track. Default to ‘merged’.
- remove_merged (bool) – True to remove the merged tracks from the track list. False to keep them. Default to False.
-
pad_to_same
()[source]¶ Pad shorter piano-rolls with zeros at the end along the time axis to the length of the piano-roll with the maximal length.
-
parse_midi
(filepath, mode='sum', algorithm='normal', binarized=False, compressed=True, collect_onsets_only=False, collect_midi_info=False, threshold=0, first_beat_time=None)[source]¶ Parse a MIDI file.
Parameters: - filepath (str) – The path to the MIDI file.
- mode ({'sum', 'max', 'any'}) – Indicate the merging function to apply to duplicate notes. Default to ‘sum’.
- algorithm ({'normal', 'strict', 'custom'}) –
Indicate the method used to get the location of the first beat. Notes before it will be dropped unless an incomplete beat before it is found (see Notes for details). Default to ‘normal’.
- The ‘normal’ algorithm estimate the location of the first beat by
pretty_midi.PrettyMIDI.estimate_beat_start()
. - The ‘strict’ algorithm set the first beat at the event time of the first time signature change. If no time signature change event found, raise a ValueError.
- The ‘custom’ algorithm take argument first_beat_time as the location of the first beat.
- The ‘normal’ algorithm estimate the location of the first beat by
- binarized (bool) – True to binarize the parsed piano-rolls before merging duplicate notes. False to use the original parsed piano-rolls. Default to False.
- compressed (bool) – True to compress the pitch range of the parsed piano-rolls. False to use the original parsed piano-rolls. Deafault to True.
- collect_onsets_only (bool) – True to collect only the onset of the notes (i.e. note on events) in all tracks, where the note off and duration information are dropped. False to parse regular piano-rolls.
- collect_midi_info (bool) – True to collect additional information in the MIDI file and return in a dictionary format. False to collect and return nothing.
- threshold (int or float) – Threshold to binarize the parsed piano-rolls. Only effective when binarized is True. Default to zero.
- first_beat_time (float) – The location (in sec) of the first beat. Required and only effective when using ‘custom’ algorithm.
Returns: midi_info – Contains additional information of the parsed MIDI file as fallows.
- first_beat_time (float) : the location (in sec) of the first beat
- incomplete_beat_at_start (bool) : indicate whether there is an incomplete beat before first_beat_time
- num_time_signature_change (int) : the number of time signature change events
- time_signature (str) : the time signature (in ‘X/X’ format) if there is only one time signature events. None if no time signature event found
- tempo (float) : the tempo value (in bpm) if there is only one tempo change events. None if no tempo change event found
Return type: dict
Notes
If an incomplete beat before the first beat is found, an additional beat will be added before the (estimated) beat start time. However, notes before the (estimated) beat start time for more than one beat are dropped.
-
parse_pretty_midi
(pm, mode='sum', algorithm='normal', binarized=False, skip_empty_tracks=True, collect_onsets_only=False, threshold=0, first_beat_time=None)[source]¶ Parse a
pretty_midi.PrettyMIDI
object.Parameters: - pm (pretty_midi.PrettyMIDI object) – The
pretty_midi.PrettyMIDI
object to be parsed. - mode ({'sum', 'max', 'any'}) – Indicate the merging function to apply to duplicate notes. Default to ‘sum’.
- algorithm ({'normal', 'strict', 'custom'}) –
Indicate the method used to get the location of the first beat. Notes before it will be dropped unless an incomplete beat before it is found (see Notes for details). Default to ‘normal’.
- The ‘normal’ algorithm estimate the location of the first beat by
pretty_midi.PrettyMIDI.estimate_beat_start()
. - The ‘strict’ algorithm set the first beat at the event time of the first time signature change. If no time signature change event found, raise a ValueError.
- The ‘custom’ algorithm take argument first_beat_time as the location of the first beat.
- The ‘normal’ algorithm estimate the location of the first beat by
- binarized (bool) – True to binarize the parsed piano-rolls before merging duplicate notes. False to use the original parsed piano-rolls. Default to False.
- skip_empty_tracks (bool) – True to remove tracks with empty piano-rolls and compress the pitch range of the parsed piano-rolls. False to retain the empty tracks and use the original parsed piano-rolls. Deafault to True.
- collect_onsets_only (bool) – True to collect only the onset of the notes (i.e. note on events) in all tracks, where the note off and duration information are dropped. False to parse regular piano-rolls.
- threshold (int or float) – Threshold to binarize the parsed piano-rolls. Only effective when binarized is True. Default to zero.
- first_beat_time (float) – The location (in sec) of the first beat. Required and only effective when using ‘custom’ algorithm.
Notes
If an incomplete beat before the first beat is found, an additional beat will be added before the (estimated) beat start time. However, notes before the (estimated) beat start time for more than one beat are dropped.
- pm (pretty_midi.PrettyMIDI object) – The
-
plot
(filepath=None, mode='separate', track_label='name', normalization='standard', preset='default', cmaps=None, tick_loc=None, xtick='auto', ytick='octave', xticklabel='on', yticklabel='auto', direction='in', label='both', grid='both', grid_linestyle=':', grid_linewidth=0.5)[source]¶ Plot the piano-rolls or save a plot of them.
Parameters: - filepath (str) – The filepath to save the plot. If None, default to save nothing.
- mode ({'separate', 'stacked', 'hybrid'}) –
Plotting modes. Default to ‘separate’.
- In ‘separate’ mode, all the tracks are plotted separately.
- In ‘stacked’ mode, a color is assigned based on cmaps to the piano-roll of each track and the piano-rolls are stacked and plotted as a colored image with RGB channels.
- In ‘hybrid’ mode, the drum tracks are merged into a ‘Drums’ track, while the other tracks are merged into an ‘Others’ track, and the two merged tracks are then plotted separately.
- track_label ({'name', 'program', 'family', 'off'}) – Add track name, program name, instrument family name or none as labels to the track. When mode is ‘hybrid’, all options other than ‘off’ will label the two track with ‘Drums’ and ‘Others’.
- normalization ({'standard', 'auto', 'none'}) –
The normalization method to apply to the piano-roll. Default to ‘standard’. If pianoroll is binarized, use ‘none’ anyway.
- For ‘standard’ normalization, the normalized values are given by N = P / 128, where P, N is the original and normalized piano-roll, respectively
- For ‘auto’ normalization, the normalized values are given by N = (P - m) / (M - m), where P, N is the original and normalized piano-roll, respectively, and M, m is the maximum and minimum of original piano-roll, respectively.
- If ‘none’, no normalization will be applied to the piano-roll. In this case, the values of pianoroll should be in [0, 1] in order to plot it correctly.
- preset ({'default', 'plain', 'frame'}) –
Preset themes for the plot.
- In ‘default’ preset, the ticks, grid and labels are on.
- In ‘frame’ preset, the ticks and grid are both off.
- In ‘plain’ preset, the x- and y-axis are both off.
- cmaps (tuple or list) –
List of matplotlib.colors.Colormap instances or colormap codes.
- When mode is ‘separate’, each element will be passed to each
call of
matplotlib.pyplot.imshow()
. Default to (‘Blues’, ‘Oranges’, ‘Greens’, ‘Reds’, ‘Purples’, ‘Greys’). - When mode is stacked, a color is assigned based on cmaps to the piano-roll of each track. Default to (‘hsv’).
- When mode is ‘hybrid’, the first (second) element is used in the ‘Drums’ (‘Others’) track. Default to (‘Blues’, ‘Greens’).
- When mode is ‘separate’, each element will be passed to each
call of
- tick_loc (tuple or list) – List of locations to put ticks. Availables elements are ‘bottom’, ‘top’, ‘left’ and ‘right’. If None, default to (‘bottom’, ‘left’).
- xtick ({'auto', 'beat', 'step', 'off'}) – Use beat number or step number as ticks along the x-axis, or automatically set to ‘beat’ when beat_resolution is given and set to ‘step’, otherwise. Default to ‘auto’.
- ytick ({'octave', 'pitch', 'off'}) – Use octave or pitch as ticks along the y-axis. Default to ‘octave’.
- xticklabel ({'on', 'off'}) – Indicate whether to add tick labels along the x-axis. Only effective when xtick is not ‘off’.
- yticklabel ({'auto', 'name', 'number', 'off'}) – If ‘name’, use octave name and pitch name (key name when is_drum is True) as tick labels along the y-axis. If ‘number’, use pitch number. If ‘auto’, set to ‘name’ when ytick is ‘octave’ and ‘number’ when ytick is ‘pitch’. Default to ‘auto’. Only effective when ytick is not ‘off’.
- direction ({'in', 'out', 'inout'}) – Put ticks inside the axes, outside the axes, or both. Default to ‘in’. Only effective when xtick and ytick are not both ‘off’.
- label ({'x', 'y', 'both', 'off'}) – Add label to the x-axis, y-axis, both or neither. Default to ‘both’.
- grid ({'x', 'y', 'both', 'off'}) – Add grid to the x-axis, y-axis, both or neither. Default to ‘both’.
- grid_linestyle (str) – Will be passed to
matplotlib.axes.Axes.grid()
as ‘linestyle’ argument. - grid_linewidth (float) – Will be passed to
matplotlib.axes.Axes.grid()
as ‘linewidth’ argument.
Returns: - fig (matplotlib.figure.Figure object) – A
matplotlib.figure.Figure
object. - axs (list) – List of
matplotlib.axes.Axes
object.
-
remove_tracks
(track_indices)[source]¶ Remove tracks specified by track_indices.
Parameters: track_indices (list) – List of indices that indicates which tracks to remove.
-
save
(filepath, compressed=True)[source]¶ Save to a (compressed) .npz file, which can be later loaded by
pypianoroll.Multitrack.load()
.Notes
To reduce the file size, the collected piano-rolls are first converted to instances of scipy.sparse.csc_matrix, whose component arrays are then collected and saved to the .npz file.
Parameters: - filepath (str) – The path to write the .npz file.
- compressed (bool) – True to save to a compressed .npz file. False to save to a uncompressed .npz file. Default to True.
-
to_pretty_midi
(constant_tempo=None)[source]¶ Convert to a
pretty_midi.PrettyMIDI
instance.Notes
- Only constant tempo is supported by now.
- The velocities of the converted piano-rolls are cliiped into [0, 127], i.e. values below 0 and values beyond 127 are replaced by 127 and 0, respectively.
Parameters: constant_tempo (int) – The constant tempo value of the output object. If None, default to use the first element of tempo Returns: pm – The converted pretty_midi.PrettyMIDI
instance.Return type: pretty_midi.PrettyMIDI object
-


WITNESS LIST Higher Education Excellence Funding Committee May 22, 2002 -10:00A Higher Education Excellence Funding ON: Brown, Don (Texas Higher Education Coordinating Board), TX Ratliff, Lt. Governor Bill (Self), TX


func
Azure Functions Core Tools: Develop and test Azure Functions locally.
Local functions can connect to live Azure services, and can deploy a function app to an Azure subscription.
More information: home page
- Create a new functions project:
func init project
- Create a new function:
func new
- Run functions locally:
func start
- Publish your code to a function app in Azure:
func azure functionapp publish function
- Download all settings from an existing function app:
func azure functionapp fetch-app-settings function
- Get the connection string for a specific storage account:
func azure storage fetch-connection-string storage_account


dygraphs JavaScript Library
code.google.com/p/dygraphs
The dygraphs JavaScript library produces produces interactive, zoomable charts of time series based on CSV files.
The DateGraph library depends on two other JS libraries: MochiKit and PlotKit. Rather than tracking down copies of these libraries, I recommend using a packed version of dygraphs that combines all three libraries into a single JS file. Either grab this file from dygraph project's downloads page or create it yourself by checking out a copy of the code and running:
./generate-combined.sh
The combined JS file is now in dygraph-combined.js
. Here's a basic example to get things started:
| HTML | Output | |
|---|---|---|

    |
In order to keep this example self-contained, the second parameter is a function that returns CSV data. These lines must begin with a date in the form YYYYMMDD. In most applications, it makes more sense to include a CSV file instead. If the second parameter to the constructor is a string, it will be interpreted as the path to a CSV file. The DateGraph will perform an XMLHttpRequest to retrieve this file and display the data when it becomes available. Make sure your CSV file is readable and serving from a place that understands XMLHttpRequest's! In particular, you cannot specify a CSV file using "file:///"
. Here's an example: (data from Weather Underground)
| HTML | Output | |
|---|---|---|

    |
Click here to view the temperatures.csv
file. There are a few things to note here:
null
, the labels were taken from the first line of the data instead. The first line of temperatures.csv
is Date,High,Low
.These last two problems can be fixed by specifying the appropriate options in the fourth parameter to the DateGraph constructor. To set the number of days for a moving average, use the rollPeriod option. To set the range of the y-axis, use the valueRange option. Here's how it's done:
| HTML | Output | |
|---|---|---|

    |
A rolling average can be set using the text box in the lower left-hand corner of the graph (the showRoller attribute is what makes this appear).
Another significant feature of the dygraphs library is the ability to display error bars around data series. One standard deviation must be specified for each data point. A +/-n sigma band will be drawn around the data series at that point. If a moving average is being displayed, DateGraph will compute the standard deviation of the average at each point. (i.e. σ = sqrt((σ_1^2 + σ_2^2 + ... + σ_n^2)/n))
Here's a demonstration. There are two data series. One is N(100,10)
with a standard deviation of 10 specified at each point. The other is N(80,20)
with a standard deviation of 20 specified at each point. The CSV file was generated using Octave and can be viewed here.
| HTML | Output | |
|---|---|---|

    |
Things to note here:
This chart shows monthly closes of the Dow Jones Industrial Average, both in nominal and real (i.e. adjusted for inflation) dollars. The shaded areas show its monthly high and low. CPI values with a base from 1982-84 are used to adjust for inflation.
These are the options that can be passed in through the fourth parameter of the DateGraph constructor.
| Name | Sample Value | Description |
|---|---|---|
| rollPeriod | 7 |
Number of days over which to average data. Discussed extensively above. |
| showRoller | true |
Should the rolling average period text box be shown? Default is false. |
| colors | ['red', '#00FF00'] |
List of colors for the data series. These can be of the form "#AABBCC" or "rgb(255,100,200)" or "yellow", etc. If not specified, equally-spaced points around a color wheel are used. |
| colorSaturation | 1.0 |
If colors is not specified, saturation of the automatically-generated data series colors. (0.0-1.0, default: 1.0) |
| colorValue | 0.5 |
If colors is not specified, value of the data series colors, as in hue/saturation/value. (0.0-1.0, default 0.5) |
| clickCallback | function(e,date){ alert(date); } |
A function to call when a data point is clicked. The function should take two arguments, the event object for the click and the date that was clicked. (default null) |
| errorBars | false |
Does the data contain standard deviations? Setting this to true alters the input format (see above). (default false) |
| strokeWidth | 2.0 |
Width of the data lines. This can be used to increase the contrast or some graphs. (default 1.0) |
| dateWindow | [(new Date('2006-01-01')).valueOf(), |
Initially zoom in on a section of the graph. Is of the form [earliest, latest], where earliest/latest are millis since epoch. By default, the full range of the input is shown. |
| valueRange | [10, 110] |
Explicitly set the vertical range of the graph to [low, high]. By default, some clever heuristics are used (see above). |
| minTickSize | 1
| The difference between ticks on the y-axis can be greater than or equal to this, but no less. If you set it to 1, for instance, you'll never get nonintegral gaps between ticks. |
| labelsSeparateLines | true |
Put
 between lines in the label string. Often used in conjunction with labelsDiv. (default false) |
| labelsDiv | document.getElementById('foo') |
Show data labels in an external div, rather than on the graph. (default null) |
| labelsKMB | true |
Show K/M/B for thousands/millions/billions on y-axis (default false). |
| padding | {left: 40, right: 30, |
Adds extra pixels of padding around the graph. Sometimes a dygraph gets clipped by surrounding text (see the Demo at the top of this page). Setting this property appropriately will fix this problem. |
Any options you specify also get passed on to PlotKit's Renderer class. DateGraph will override some of these (e.g. strokeColor), but others may be useful. The padding
property is an example of this.
Here are a few problems that I've frequently run into while using the dygraphs library.
YYYYMMDD,series1,series2,...
. If you're specifying the
names of each data series in the CSV file itself, make sure that you pass
null
as the third parameter to the DateGraph constructor to let
the library know that. And if you set the errorBars
property,
make sure you alternate data series and standard deviations.
tag. This applies to the CSS text-align
property as well. If you
want to center a DateGraph, put it inside a table with "align=center"
set.colors
property or name the data series
using the third parameter of the DateGraph constructor, make sure the number
of data series agree in all places: colors
, third parameter and
in each line of the CSV file itself.dateWindow
property to a date. It expects
milliseconds since epoch, which can be obtained from a JavaScript Date
object's valueOf method.Created May 9, 2008 by Dan Vanderkam


Next, we derive the linearized version of Eq. (77). The
perturbation in electromagnetic field causes perturbation in both distribution
function and particle orbits
,
, and
. Thus we write
|
(81) |
|
(82) |
|
(83) |
|
(84) |
and substitute this into Eq. (77), we obtain
|
(85) |
The zero order equation is
|
(86) |
The first order equation is
|
(87) |
Define
|
(88) |
which is the unperturbed orbit propagator, then Eq. (87) is
written as
|
(89) |
which agrees with Eq. (21) in Porcelli's paper[1].
At this point, I would like to discuss the equilibrium distribution function.
We know that functions of constants of the motion are solutions to the kinetic
equation. Noting that
,
, and are
constants of the motion in equilibrium field. Then
is a solution to the kinetic equation Eq.
(77). Noting that the right-hand side of Eq. (89)
contains partial derivative with respect to variables
, we would like to transform the partial derivatives with
respect to
to one with respect to
. The right-hand side of Eq.
(89) can be written term by term as
Using these results, Eq. (89) is written as
which can be arranged in the form
|
(93) |
which agrees with Eq. (22) in Porcelli's paper[1]. Next, we
need to express
,
, and
in terms of the perturbed electromagnetic field. Let us first
consider the coefficient befor the
term
in Eq. (93). We note that Eq. (35) takes the following
form:
|
(94) |
whose linearized version is (noting that
,
, and is time independent, thus
,
,
and
are all zeros)
|
(95) |
where
. Using
(Note that
here denotes total time derivative along the
unperturbed orbit, instead of the perturbed orbit ) in Eq. (95) gives
|
(97) |
where, for notation ease, we have defined
|
(98) |
Equation (97) agrees with Eq. (30) in Porcelli's
paper[1]. The right-hand side of Eq. (97)
provides the desired expression for the coefficent before the
term of Eq. (93).
The first order equation of Eq. (52) is written as (Noting that we
are considering toroidal symmetrical equilibrium, thus terms such as
,
, and
are all zeros.)
|
(99) |
Using this in the Euler equation (43), we obtain
|
(100) |
Note that
|
(101) |
then
Using this in Eq. (100), we obtain
|
(102) |
which can be further written as
|
(103) |
|
(104) |
The right-hand side of Eq. (104) gives desired expression for the
coefficient before the term
of Eq.
(93). The linearized version of Eq. (32)
|
(105) |
is written as
|
(106) |
Noting that
,
, the above
equation is written as
|
(107) |
|
(108) |
|
(109) |
|
(110) |
|
(111) |
Eq. (111) agrees with Eq. (31) in Porceli's paper. The right-hand
side of Eq. (111) provide the desired expression for the coefficient
before
term in Eq. (93). Using Eqs.
(97), (104), and (111), Eq. (93) is
finally written as
|
(112) |
YouJun Hu
2014-05-19


Get Help Now!
Our highly trained staff can help you find a drug or alcohol rehab program
your name
your phone
your email
Please tell us how we can help
Welcome to Addiction Treatment Services
This is a sample text to show you the possibilities here
Addiction Treatment and Drug Rehab Centers
Drug rehab and addiction treatment programs are affordably offered to individuals suffering from drug addiction and alcoholism at The Watershed. We are a leading drug and alcohol rehab center that provides personalized substance abuse therapy programs, tailored by experts to meet your individual drug rehabilitation needs. Our drug rehab, addiction treatment centers, drug detox, dual diagnosis rehab and addiction treatment programs utilize the most effective techniques to restore health and happiness.
We have combined excellence and compassion with all the necessary disciplines to address the disease of addiction in a drug rehab center
to help you achieve recovery. Our goal is to provide the most cost effective drug and alcohol treatment with the highest level of care. You have many options when choosing a drug rehab or alcohol treatment center. We feel that by maintaining affordable addiction treatment services combined with the best quality care, we will be able to reach more individuals suffering from this life threatening disease.
Drug and Alcohol treatment Center Information
The Watershed can help you successfully and safely detox from drug or alcohol addiction, and offer you effective treatment at our addiction treatment centers.
We will teach you how to find recovery from the diseases of alcoholism and drug addiction. We are here to help you get sober and stay sober.
Drug Abuse and Alcoholism are diseases that affect every city, town and county in America; it affects teens, adults, males, females, and families. Alcohol and drug treatment can save your life!


This is an Angular static HTML file with CSS and JavaScript, served from a local web root. Click on the button below to send a message to the backend. It will respond and send a message back to the UI.


By far the easiest way to write parser is by matching input text as terminal nodes and then composing a tree of terminal and non-terminal nodes. Terminal nodes, the leaf nodes, actually match the input text, while Non-Terminal nodes are composed using Terminal nodes.
If values can be composed together to create higher ordered values, as in Terminal nodes and Non-Terminal nodes, then, the same can be modeled with functions. That is, we define simple functions and compose them together to create a higher order function. The simple functions, called terminal parsers, match input text.
I guess that is enough of theory, let us look at an example:
<IP_ADDRESS> [07/Mar/2004:16:05:49] GET,/index.html,401,1234
Above line is pulled out of a log file. There is a format to this line, with following components: (ip, timestamp, comma-separated-values)
parsing ip
Format of ip is: <int>"."<int>"."<int>"."<int>, which can be parsed as:
ydelimit = parsec.Atom(".")
yip := parsec.And(
nil, // Nodify
parsec.Int(),
ydelimit, parsec.Int(),
ydelimit, parsec.Int(),
ydelimit, parsec.Int(),
)
- parsec.Atom() will try to match the input text with ., which is the argument passed to construct the Atom parser.
- parsec.Int() returns a parser that will match the input text for integer. It is same as constructing parser with parsec.Token(`-?[0-9]+`, "INT")
- Atom, Int, Token are some of the standard parser constructors supplied by goparsec.
- Subsequently, we can combine the terminal parsers using And combinator.
- The first argument, passed as nil here, is for supplying a callback function. Arguments to And combinator tells us that, it shall first try to match an integer, and then a ., and then an integer, and then a ., and then an integer, and then a ., and then an integer.
- After every match, the cursor in the input text will move forward, but only if there is a match.
Nodify
What happens after all the parsers supplied to the And combinator succeed in matching the input text ?
The first argument, called Nodify callback, if not nil, will be dispatched. The signature of Nodify is:
type Nodify func(nodes []ParsecNode) node ParsecNode
The array nodes carry a node item for each matching parser supplied to the And combinator. In this case, len(nodes) will be 7. Nodify callback is user supplied function and it is up to the user to decide what to do with nodes, and finally a node item returned. This node item, typed as ParsecNode, can be anything; it is just an alias for interface{}.
If our application is going to consume the ip as string, then we can use the Nodify callback to do some interesting stuff:
tostring := func(nodes []ParsecNode) node ParsecNode {
s := ""
for _, node := range nodes {
s += node.(*Terminal).Value
}
return s
}
yip := parsec.And(
tostring,
parsec.Int(),
ydelimit, parsec.Int(),
ydelimit, parsec.Int(),
ydelimit, parsec.Int(),
)
Here we are extracting the value of each terminal and concatenating it to create the full ip address and return the string as ParsecNode.
timestamp
For time-stamp, we can't match the string as it is because other log lines, in the same file, will have different time-stamp values. But the time-stamp has a pattern: \[[0-9]{2}/[a-zA-Z]{3}/[0-9]{4}:[0-9]{2}:[0-9]{2}:[0-9]{2}\]
ytm := parsec.Token(
`\[[0-9]{2}/[a-zA-Z]{3}/[0-9]{4}:[0-9]{2}:[0-9]{2}:[0-9]{2}\]`,
"TIMESTAMP")
ytm can parse any time-stamp in the log file as long as it follows the same pattern.
comma-separated-values
Parsing comma separated values can be more complex, but that gives us the opportunity to learn more about parsec.
vector2scalar := func(nodes []parsec.ParsecNode) parsec.ParsecNode {
return notes[0]
}
concat := func(nodes []parsec.ParsecNode) parsec.ParsecNode {
s := nodes[0].(string)
s = s[1 : len(s)-1]
return s
}
ystr := parsec.And(concat, parsec.String())
yatom := parsec.Token("[a-zA-Z][a-zA-Z0-9_\.-]+", "ATOM")
yterm := parsec.OrdChoice(vector2scalar, ystr, yatom)
ycomma := parsec.Token(`,`, "FIELDSEP")
ycsv := parsec.Kleene(nil, parsec.Maybe(maybenode, yterm), ycomma)
Values can be one of the following:
- Double quoted string. Here, we can find a use case for Nodify with ystr, the Nodify callback prunes away the beginning quote, end quote and return the golang string as ParsecNode.
- An integer value.
- An atom of alpha numeric characters including special chars _.-. Atom always start with lower case or upper case alphabet.
In the above parsing logic, values are parsed as yterm. Since a term can be one of the value described above, we use OrdChoice.
Note that there is an ambiguity here, between second type of value, an Integer and third type of value, an Atom. In such cases, we should compose the parser in such a way that, more specific parsers are tried before trying more generic parsers. Although OrdChoice parses one of the value as ParsecNode, it is returned as an array of []ParsecNode with arity one. This is to keep it consistent with rest of the combinators like And, Kleene, Many. To unwrap the single item in the array we are once again using a nodify callback.
And finally we tie them up using the Kleene combinator. Kleene is used because we expect ZERO or more terms in the input. Combinators like Kleene and Many can take two parser, the first one parses the input for the actual value and the second one parses the separator token. In our case the separator token in a COMMA ,. Kleene will repeatedly apply the two parsers until they fail matching the input, at which point all o/p from the first parser will be collected in an array, of []ParsecNode, and dispatched to the nodify callback and/or returned back.
A note on Maybe: If input contains a string like GET,index.html,,, where the term can be empty, we still want the first parser to succeed so the Kleene can continue matching the remaining string. If indeed the input contains an empty term then Maybe combinator that wraps the term will return ParsecNode as MissingNone. And the final []ParsecNode returned by Kleene will contain MissingNone for all missing terms.
text = `<IP_ADDRESS> [07/Mar/2004:16:05:49] GET,"/index.html",401,1234`
y := parsec.And(nil, yip, ytm, ycsv)
scanner := NewScanner([]byte(text))
node, scanner := y(scanner)
So far we have only constructed parser functions, by composing simple parsers to create complex parser, using one of the Combinators like And, OrdChoice, Kleene, Many, Maybe. To actually parse the text we will have to use a scanner, that implement parsec.Scanner{} interface. Goparser provides a simple scanner constructed by calling NewScanner.


February 26, 2021
Ustage Day 25
February 25, 2021
Ustage Day 24
February 24, 2021
Ustage Day 23
February 23, 2021
Ustage Day 22
February 22, 2021
Ustage Day 21
February 20, 2021
Ustage Day 20
February 18, 2021
Ustage Day 19
February 17, 2021
Ustage Day 18
February 16, 2021
Ustage Day 17
February 15, 2021
Ustage Day 16
February 5, 2021
Ustage Day 15
February 4, 2021
Ustage Day 14
February 3, 2021
Ustage Day 13
February 2, 2021
Ustage Day 12
February 1, 2021
Ustage Day 11
January 29, 2021
Ustage Day 10
January 28, 2021
Ustage Day 9
January 27, 2021
Ustage Day 8
January 26, 2021
Ustage Day 7
January 25, 2021
Ustage Day 6
January 22, 2021
Ustage Day 5
January 21, 2021
Ustage Day 4
January 20, 2021
Ustage Day 3
January 19, 2021
Ustage Day 2
January 18, 2021
Ustage Day 1
January 13, 2021
부스트캠프 AI Tech 등록과 싸피 퇴소
January 9, 2021
부스트캠프 AI Tech 합격 후기


[NAT1 is likely to be a fundamental translational repressor, and its aberrant editing could contribute to the potent oncogenesis induced by overexpression of APOBEC-1.]. Sentence from MEDLINE/PubMed, a database of the U.S. National Library of Medicine. (gene-disease biomarker association) NAT1 - Carcinogenesis
Abstract:
Transgene expression of the apolipoprotein B mRNA-editing enzyme (APOBEC-1)
causes dysplasia and carcinoma in mouse and rabbit livers. Using a modified
differential display technique, we identified a novel mRNA (NAT1 for novel
APOBEC-1 target no. 1) that is extensively edited at multiple sites in these
livers. The aberrant editing alters encoded amino acids, creates stop codons, and
results in markedly reduced levels of the NAT1 protein in transgenic mouse
livers. NAT1 is expressed ubiquitously and is extraordinarily conserved among
species. It has homology to the carboxy-terminal portion of the eukaryotic
translation initiation factor (eIF) 4G that binds eIF4A and eIF4E to form eIF4F.
NAT1 binds eIF4A but not eIF4E and inhibits both cap-dependent and
cap-independent translation. NAT1 is likely to be a fundamental translational
repressor, and its aberrant editing could contribute to the potent oncogenesis
induced by overexpression of APOBEC-1.


An enthusiastic person who likes a challenge in programming specifically in server-side or front-end web development. I have a good understanding of the fundamentals of OOP, relational, and non-relational databases.
Built a React Front End Web App with a pre-existing REST API web server. Modeled it as a Single Page Application and had to work with Axios (AJAX). Understanding how to use React to give user a good experience.
DemoDemonstrates ability to design and build UI websites, and integrate JS, SCSS, or SASS packages if needed. Used Bootstrap framework to make mobile friendly. Applied other plugins when necessary.
Demo App that demonstrates ability to design and build dynamic web apps for the internet. This app is built with MEN (mongoDB, Express, Node.js) stack. Integrate API's and using REST software architectural style and is mobile friendly.
DemoShows the ability to analyze, design, and build Models, Validations, Workflows, and Processes. Customize existing standard Apps, Objects, and Fields or create them from scratch. Also administrative work such as building reports, dashboards, or making new users, and profiles.
Worked with Java and PostgreSQL to practice and build databases and queries for a Movie Rental Database. Involved up to 8 tables and working with the concepts of nested queries, procedures, triggers, JOINS, and the relationships between tables.
Then worked with Node.js with mySQL just to see the difference syntactically of how to connect with different databases with different languages.
After graduating from the University of Illinois at Chicago I spent ten years in my rural hometown in Mexico. I spent time helping build house and electrical infrastructures. I have returned to the USA in the past year and currently looking to help out in web develpoment projects. My interests lie in web development and looking to build and grow with a team of like-minded individuals. I like learning new technologies in back-end and front-end web development and currently have been working React.
When not studying or building web app demos, I like to spend time with family and friends. In the summer I play soccer and go to any festivals in the Chicagoland area.
During the winter and this COVID-19 crisis we are in I tend to conquer the world in CIV V as well as play FIFA. I enjoy practicing and playing the cello and bass guitar.