Community

Try our innovative online adaptive learning system, Alcumus.
Over 1100 problems and 60+ video lessons. FREE!
Login Register Memberlist Search AoPS Blogs Contests Galleries Forum Index
The time now is Fri Dec 04, 2009 9:52 am
All times are UTC - 8
View posts since last visit
View unanswered posts
Description of the package cse5
Moderators: fedja, stevem
Post new topic   Reply to topic View previous topicView next topic
19 Posts • Page 1 of 1
Author Message
fedja
Birch & Swinnerton Dyer
Birch & Swinnerton Dyer

Offline
Joined: 04 Feb 2005
Posts: 4279
Russian FederationUnited States

To rate posts you must be logged in
#1
Description of the package cse5

The aim of this thread is to describe the newly added package cse5 and it usage. I plan to do it as a series of posts in this topic. If you want to ask questions about this package, please, use separate posts to keep this thread clean. The latest "official" version of the package can be downloaded from http://www.artofproblemsolving.com/Forum/latexrender/asy/cse5.asy.

Acknowledgements This package would, probably, never be created without the discussion started by Hamster1800. As usual, special thanks go to Valentin for making it an easy add-on and for keeping this site running fairly smoothly Razz.

Why would one be interested in cse5?. Suppose your task is just to draw and label a couple of points and the line between them. After the usual assignment operator
pair A=(0,0),B=(1,1);
you would normally write
dot(A);dot(B);draw(A--B);label("A",A,W);label("B",B,E);
With cse5, you can write
D(A);D(B);D(A--B);MP("A",A,W);MP("B",B,E);
or, more in the style of the package,
D(MP("A",D(A),W)--MP("B",D(B),E));
which is already 30% shorter, so the 2000 charachter limit is effectively expanded to at least 3000 (for more advanced options, the gain is even larger) and you can do quite a lot with 1000 extra charachters (the full package code itself contains about 900 charachters, for instance). There is a small difference in the output as well:
import cse5; size(200); pair A=(0,0),B=(1,1); dot(A); dot(B); draw(A--B); label("A",A,W); label("B",B,E);...
The standard code produces the output on the left and the cse5 code the one on the right.
The difference in length is even more striking for commands like OP:
D(OP(A,B));
is equivalent to
dot((intersectionpoints(A,B))[1]);
and
a=IP(A,B);MP("X",D(a));
is equivalent to
a=intersectionpoint(A,B);dot(a);label("X",a,S);
with almost 50% gain. Besides IP() doesn't make the code crash even if the paths do not intersect, though, if you use its result for commands from outside the package in this case, the output will look strange (the package commands handle this situation in a much nicer way: you just don't see the objects defined using this fake point at all but see everything else).

What can be done using only commands from the package? One can fully illustrate any Compass and StraightEdge construction. (That's where the letters cse in the name come from; 5 is the average amount of symbols per command). The limit of 2000 symbols should be enough to design almost everything you can do on a standard sheet of paper without making a total mess. Lets. say, we need to construct the middle bisector of an interval with endpoint A=(0,0) and B=(3,0) in the standard way. The whole construction is here:
pair A=(0,0),B=(3,0),X1,X2;
D(MP("A",D(A))--MP("B",D(B)));
X1=MP("X_1",IP(D(CR(A,2)),D(CR(B,2))));
X2=MP("X_2",OP(CR(A,2),CR(B,2)));
D(L(D(X1),D(X2)));

import cse5; size(200); pair A=(0,0),B=(3,0),X1,X2; D(MP("A",D(A))--MP("B",D(B))); X1=MP("X_1",...
all done in 150 symbols (the assignment operators can be removed entirely, by the way). The number of storing, drawing, intersecting, and labeling operations is 23. The overhead (names,labels, and parameters) is 38. So, indeed, you have 5 symbols per operation as promised.But the most exciting point is that if you change the definition of B to B=(5,0); the code won't crash but just will show you what can be done:
import cse5; size(200); pair A=(0,0),B=(5,0),X1,X2; D(MP("A",D(A))--MP("B",D(B))); X1=MP("X_1",...
This may not sound utterly exciting until you realize that the (almost) equivalent standard code, which is
pair A=(0,0),B=(3,0),X1,X2;
dot(A);dot(B);label("A",A,S);label("B",B,S);draw(A--B);
path C1=circle(A,2),C2=circle(B,2),L;
draw(C1);draw(C2);
X1=intersectionpoint(C1,C2);dot(X1);label("X_1",X1,S);
X2=(intersectionpoints(C1,C2))[1];dot(X2);label("X_2",X2,S);
draw((2*X1-X2)--(2*X2-X1));

is about 290 symbols long and produces nothing but the "paths do not intersect" error message when B=(5,0).

Let's stop the shameless advertising here and go to the first meaningful subject.
Last edited by fedja on Tue Jul 17, 2007 8:20 am; edited 1 time in total 
PostPosted: Sat May 19, 2007 9:15 am  Back to top 
  ProfilePM
fedja
Birch & Swinnerton Dyer
Birch & Swinnerton Dyer

Offline
Joined: 04 Feb 2005
Posts: 4279
Russian FederationUnited States

To rate posts you must be logged in
#2
Drawing and Marking in cse5. The easiest way to understand what's going on is to work through an example. The typical code in the style of cse5 would be
pair A=(0,0),B=(1,2),C=(2,1),D=(3,0),E=(4,2);
pen P=black+linewidth(6),Q=green;
D(D(A)..MP("B",B)..D(MP("C",C))..MP("D",D(D,P) ,(0,3))..MP("E_{12}",D(E,P,-1),16,NW),Q);

which produces
import cse5; pair A=(0,0),B=(1,2),C=(2,1),D=(3,0),E=(4,2); pen P=black+linewidth(6),Q=green; D(D(A)..MP("B",B)..D(M...
First of all, why such names: D() and MP(). D stands for Draw and MP for MarkPoint, which seems to be natural enough considering what these commands do: D draws a dot or a curve (given by a pair or a path respectively) and MP puts a mark on some point given by a pair.

So, what do we see in the code? The outer D(...,Q); construct tells us that something will be drawn with pen Q, so it remains to figure out what that something is. Since it includes a lot of .., it is easy to realize that it is a path that should be given by a sequence of pairs or paths between the ..operator. It is not hard to realize that in this case, they are pairs.

The easiest one is the first pair D(A). It is just the same as A but already drawn on the picture in the default style of D, which is minimal width blue for curves and red for dots.

MP("B",B) is just B that is marked by the charachter B in the default position and style, which are South and fontsize(11) \LaTeX. Since D is not executed on B, the dot does not appear on the picture, only its label.

The next one is more interesting. It is still the pair C in disguise that is both marked (by the character C) and drawn in the default styles. It (almost) doesn't matter in which order to apply D and MP to a pair, co MP("C",D(C)) would produce the same effect.

I'll skip the next point except noting that it's label positioned north 3 times the usual distance from the point itself and that Asymptote is clever enough to understand which D is a pair and which is a drawing construct and come directly to MP("E",D(E,P,-1),16,NW), which shows each command with its most full list of parameters.

We see that the label E is put at the point E with font of size 16 in the NorthWest position, which is what appears on the picture. Why didn't D put a dot then? Because there is a negative integer parameter in the end. It seems silly to put D just to disable it later, but it comes handy in the constructs like
for(int k=0;k<10;++k) D((k,0),(k-3)*(k-7));
with the output
import cse5; for(int k=0; k<10; ++k) D((k,0),(k-3)*(k-7));

Two final remarks. First, you may use the result of D or MP in any construction in which you can use their arguments.except you cannot write something like
D(A)=expression;
but why would you need to when
A=D(expression) ;
has exactly the effect you might expect from the first construct? Second, you are not obliged to write as tersely as above, the code
pair A=(0,0),B=(1,2),C=(2,1),D=(3,0),E=(4,2);
pen P=black+linewidth(6),Q=green;
D(A..B..C..D..E,Q);
D(A);
MP("B",B);
D(MP("C",C));
MP("D",D(D,P),(0,3));
MP("E_{12}",D(E,P,-1),16,NW);

is just 9 symbols longer and produces a nicer picture:
import cse5; size(200); pair A=(0,0),B=(1,2),C=(2,1),D=(3,0),E=(4,2); pen P=black+linewidth(6),Q=green; D(A..B..C..D..E,Q); D...
Do you see what the difference between the pictures is, by the way? Usung draw, dot and label would require at least 20 more symbols (even if you forfeit the font change and the LaTeXication of labels) and the whole drawing part is about 85 symbols long, so we save 28% on drawing which is not that bad. The only thing that remains to do is to show the code for D and MP. Here goes:
Code:

path D(path p, pen q=blue, int m=1)
{
if(m>0) draw(p,q);
return p;
}
pair D(pair p, pen q=red, int m=1)
{
if ((p!=nullpair)&&(m>0)) dot(p,q);
return p;
}
pair MP(string s, pair A, int f=11,pair B=plain.S)
{
if (A!=nullpair) label("$"+s+"$",A,B,fontsize(f));
return A;
}

What on Earth is nullpair? That will become clear in the next post.
Last edited by fedja on Sat May 19, 2007 1:21 pm; edited 2 times in total 
PostPosted: Sat May 19, 2007 12:42 pm  Back to top 
  ProfilePM
fedja
Birch & Swinnerton Dyer
Birch & Swinnerton Dyer

Offline
Joined: 04 Feb 2005
Posts: 4279
Russian FederationUnited States

To rate posts you must be logged in
#3
Intersecting of paths in cse5. The name of the main command that does it is IP, which is, of course, just the abbreviation of IntersectionPoint. You can use
IP(A,B,m)
instead of
(intersectionpoints(A,B))[m]
anywhere in the asy code, which by itself is enough to cover the cost of
import cse5;
line: 9+12<28 but the main advantage is that the code with IP() doesn't crash even if the paths do not intersect because IP() always returns a pair. Only if the paths do not intersect, it is a very particular pair whose name is nullpair and whose value is currently (1.2345,6.7890) (can't explain why Mr. Green). All the internal routines of cse5 know how to handle this special pair and act appropriately. By the way, if you ever desperately need to use this particular pair for other purposes, you can reset the cse5 default value by
nullpair=(9876,5432)
or whatever else you wish in the beginning of the code (doing it in the middle is not advisable: the program won't crash but the nullpair created by some command before the change will not be recognised by the commands after the change and one of the the nicest properties of cse5, which is drawing exactly as much as possible, will be destroyed like in the code
import cse5;
size(200);
pair A=(0,0),B=(5,0),X1,X2;
D(MP("A",D(A))--MP("B",D(B)));
X1=MP("X_1",IP(D(CR(A,2)),D(CR(B,2))));
X2=MP("X_2",OP(CR(A,2),CR(B,2)));
nullpair=(2.345,30.23);
D(L(D(X1),D(X2)));

(our old code from the advertising part to which one command is added) which outputs
import cse5; size(200); pair A=(0,0),B=(5,0),X1,X2; D(MP("A",D(A))--MP("B",D(B))); X1=MP("X_1",...
See that red dot above that appeared? That's your old nullpair. It now came into existence. The code with new nullpair assignment done in the beginning (the best place for it is right after the import cse5; command) won't produce any such effect. The nullpair can never be brought into existence by the commands from cse5 but, if you run a mixed code with routines from other packages, you will get somewhat inexpected picture. Suppose, for instance, that we want to draw the quadrilateral AX_{1}BX_{2} in addition to our picture.
All we need to add to our old code is the line
D(A--X1--B--X2--A);
which in the "normal" case with B=(3,0) will produce
import cse5; size(200); pair A=(0,0),B=(3,0),X1,X2; D(MP("A",D(A))--MP("B",D(B))); X1=MP("X_1",...
but in the "irregular" case B=(5,0) gives
import cse5; size(200); pair A=(0,0),B=(5,0),X1,X2; D(MP("A",D(A))--MP("B",D(B))); X1=MP("X_1",...
which is not such a clean picture as before but it is still clear from it what exactly happened. Is it possible to make the standard operators like -- recognize the nullpair too? The answer is yes, to a certain extent. If all you need is that the path skip the fake points and just join all existing ones, that is easy to do and we'll see how to make such a quick fix later. If you want, it is possible to introduce a BL() (BrokenLine) command such that BL(A,B,C,D) would be equivalent to A--B--C--D in the normal case and to nullpath if one of the pairs A,B,C,D is equivalent to nullpair, but to make the paths A--B--C--D with at least one fake point completely disappear and -- as usable as before is hardly feasible.

Now, as we all remember, two paths may intersect at more than one point and we may want some particular point on the picture. Suppose that we have two paths: the green curve P and the blue line Q on this picture
import cse5; size(200); pair A=(0,0),B=(1,2),C=(2,1),D=(3,0),E=(4,2),G=(-1,1),F=(5,1); path P=D(MP("P",A,SE)..B..C....
They clearly intersect at 3 different points. Suppose we want to draw the middle point and to mark it with X. Writing
D(MP("X",IP(P,Q)));
will produce
import cse5; size(200); pair A=(0,0),B=(1,2),C=(2,1),D=(3,0),E=(4,2),G=(-1,1),F=(5,1); path P=D(MP("P",A,SE)..B..C....
which is not what we want. The way out is to write IP(P,Q,1) instead:
import cse5; size(200); pair A=(0,0),B=(1,2),C=(2,1),D=(3,0),E=(4,2),G=(-1,1),F=(5,1); path P=D(MP("P",A,SE)..B..C....
The last optional integer argument shows which particular point should be chosen. They are enumerated starting with the index 0, so plain IP(P,Q) is equivalent to IP(P,Q,0). If you choose it out of admissible range, nullpair will be returned, so, if for some reason, you wish to enumerate all the points and call the k-th point X_{k} and all you know for sure is that you have at most 10 points, you can write
string s;
for(int k=-2;k<10;++k)
{
s="X_"+string(k);
D(MP(s,IP(P,Q,k)));
}

with the output
import cse5; size(200); pair A=(0,0),B=(1,2),C=(2,1),D=(3,0),E=(4,2),G=(-1,1),F=(5,1); path P=D(MP("P",A,SE)..B..C....

Of course, -2 is here just to demonstrate that IP doesn't crash with negative integer argument either. 0 would be what you really want in this case. This is, of course, a not very clean shortcut. The perfect way of doing this would be to write
k<(intersectionpoints(P,Q)).length
but this expression is extremely expensive: 32 symbols instead of 4.

Since IP(P,Q,1) arises fairly often, cse5 has a special routine for it: OP(P,Q) where OP stands for OtherPoint.

The last thing to say before showing the code is that IP is, unfortunately, not completely foolproof: it handles the case when the paths do not intersect neatly but the case when the paths intersect at infinitely many points like, say, in IP(P,P), makes the program crash without even showing what is wrong. The reason is not a faulty code for IP but rather that for intersectionpoints in Asymptote. The older command intersectionpoint can handle this case but crashes for non-intersecting paths where intersectionpoints just returns an array of 0 length that IP can catch and resolve into nullpair.

Now the code:
Code:

pair IP(path A, path B, int m=0)
{
pair[] intpoints=intersectionpoints(A,B);
int len=intpoints.length-1;
if ((m>len)||(m<0)) return nullpair;
return intpoints[m];
}
pair OP(path A, path B)
{
return IP(A,B,1);
}


The next topic is other commands in cse5.

PostPosted: Sun May 20, 2007 6:11 am  Back to top 
  ProfilePM
fedja
Birch & Swinnerton Dyer
Birch & Swinnerton Dyer

Offline
Joined: 04 Feb 2005
Posts: 4279
Russian FederationUnited States

To rate posts you must be logged in
#4
Other commands of cse5.

L() This one, as one can guess, stands for Line. It allows you to create a path that is just a segment of a line going through the points A and B. The Line command has 4 parameters: 2 required (pairs A and B) and 2 optional (real a and real b). The role of A and B is clear and a and b tell you how much to extend the line beyond the points A and B. For instance,
L(A,B,1,0);
produces
import cse5; size(200); pair A=MP("A",D((0,0))), B=MP("B",D((3,1))); D(L(A,B,1,0));
which is a line extended beyond A by the length of the interval AB and not extended beyond B at all. Using L() with one real parameter instead of two gives the same result as if two equal parameters were used, so L(A,B,1.5) is exactly equivalent to L(A,B,1.5), both producing
import cse5; size(200); pair A=MP("A",D((0,0))), B=MP("B",D((3,1))); D(L(A,B,1.5));
You can even use negative parameters for a and b to produce a line that doesn't quite reach the points it defines. For instance,
L(A,B,-0.1,-0.5);
produces
import cse5; size(200); pair A=MP("A",D((0,0))), B=MP("B",D((3,1))); D(L(A,B,-0.1,-0.5));
You should be careful with negatives, though:
L(A,B,-1);
produces
import cse5; size(200); pair A=MP("A",D((0,0))), B=MP("B",D((3,1))); D(L(A,B,-1));
which looks exactly the same as the output of L(A,B,0). What's the difference? The path is now run in reverse. The default values are b=a=0.6

CR(A,r) or CirclebyRadius. It produces a circle with center A given by a pair and radius r given by a real. If r\le 0, it produces nullpath. That's all there is to say about it right now.

CP(A,B) or CirclebyPoint. It produces a circle with center A given by a pair going through another point B also given by a pair:
import cse5; size(200); pair A=MP("A",D((0,0))), B=MP("B",D((3,1))); D(CP(A,B));

d(A,B) returns the distance between the points given by the pairs A and B, so, you no longer need to write those sqrt((A.x-B.x)^2+(A.y-B.y)^2) in your code.

This list of commands can always be expanded if we find out that there are some other useful things we'd better predefine but now we've covered all the existing commands in the original version of cse5 and it is time to talk a bit about programming.

PostPosted: Tue May 22, 2007 5:44 am  Back to top 
  ProfilePM
fedja
Birch & Swinnerton Dyer
Birch & Swinnerton Dyer

Offline
Joined: 04 Feb 2005
Posts: 4279
Russian FederationUnited States

To rate posts you must be logged in
#5
Reading and writing terse code This is something you are under no obligation to do but it is what cse5 was originally designed for. Suppose you want to construct a bisector of an angle A in the triangle ABC. You can write something like that:
pair A=(0,0),B=(0,3),C=(3,2);
D(A);D(B);D(C);
MP("A",A);MP("B",B);MP("C",C);
D(A--B--C--A,black);
path K=CR(A,1);
D(K);
pair b=IP(K,A--B);
D(b);
MP("B_1",b);
pair c=IP(K,A--C);
D(c);
MP("C_1",c);
path Kb=CR(b,0.7);
D(Kb);
path Kc=CR(c,0.7);
D(Kc);
pair x=IP(Kb,Kc);
D(x);
MP("X",x);
pair y=OP(Kb,Kc);
D(y);
MP("Y",y);
path L=L(x,y);
D(L,green);

which is a nice code that produces
import cse5; size(200); pair A=(0,0),B=(0,3),C=(3,2); D(A);D(B);D(C); MP("A",A);MP("B",B);MP("C"...
It is 344 symbols long (counting spaces and carriage returns). Let's see if we can write a shorter program. The first obvious thing to do is to declare all paths, pairs, etc. in one long declaration. This will spare us a few symbols. So, we'll write
pair A=(0,0),B=(0,3),C=(3,2),b,c,x,y;
path K,Kb,Kc,L;
D(A);D(B);D(C);
MP("A",A);MP("B",B);MP("C",C);
D(A--B--C--A,black);
K=CR(A,1);
D(K);
b=IP(K,A--B);
D(b);
MP("B_1",b);
c=IP(K,A--C);
D(c);
MP("C_1",c);
Kb=CR(b,0.7);
D(Kb);
Kc=CR(c,0.7);
D(Kc);
x=IP(Kb,Kc);
D(x);
MP("X",x);
y=OP(Kb,Kc);
D(y);
MP("Y",y);
L=L(x,y);
D(L,green);

reducing the count to 334 symbols. Not a big gain, but a gain nevertheless. Now, let us look at the last two lines
L=L(x,y);
D(L,green);

We see that the symbol L appears just to be immediately used as an argument of the line routine and never appear again. What cse5 allows to do in this case is to get rid of L completely and write directly
D(L(x,y),green);[b]
Look now at
[b]y=OP(Kb,Kc);
D(y);
MP("Y",y);

It can be rewritten as
y=MP("Y",D(OP(Kb,Kc)));
Doing a few tricks like that, we get the code
[b]pair A=(0,0),B=(0,3),C=(3,2),b,c,x,y;
path K,Kb,Kc;
MP("A",D(A));MP("B",D(B));MP("C",D(C));
D(A--B--C--A,black);
K=D(CR(A,1));
b=MP("B_1",D(IP(K,A--B)));
c=MP("C_1",D(IP(K,A--C)));
Kb=D(CR(b,0.7));
Kc=D(CR(c,0.7));
x=MP("X",D(IP(Kb,Kc)));
y=MP("Y",D(OP(Kb,Kc)));
D(L(x,y),green);

which is 275 symbols long. That's quite a gain but we can go even further. Again, x and y appear just to be called as arguments and disappear entirely, so, down with them! The same happens with a and b. The next iteration is
pair A=(0,0),B=(0,3),C=(3,2);
path K,Kb,Kc;
D(MP("A",D(A))--MP("B",D(B))--MP("C",D(C))--A,black);
K=D(CR(A,1));
Kb=D(CR(MP("B_1",D(IP(K,A--B))),0.7));
Kc=D(CR(MP("C_1",D(IP(K,A--C))),0.7));
D(L(MP("X",D(IP(Kb,Kc))),MP("Y",D(OP(Kb,Kc)))),green);

which is 243 symbols long and still produces the same picture. How about getting rid of K, say? We can do it but it won't be an improvement because it is used as an argument twice, so replacing K by its definition won't help much. So, we have 243 symbol long program now instead of 344. Suppose that we have to draw all 3 bisectors in the triangle with full notation like we did for one of them. Ignoring the cost of drawing the triangle itself, we see that the cost of actual drawing a bisector is 140. So, will we need 243+2\cdot 140=523 symbols? We can afford it, it is still well below the limit but we can get away with fewer if we enclose the drawing piece into a subroutine, say B(), with B for Bisector. How to set a subroutine? First of all, extract the code that you planned to repeat without much thinking of what is written there:
pair A=(0,0),B=(0,3),C=(3,2);
path K,Kb,Kc;
D(MP("A",D(A))--MP("B",D(B))--MP("C",D(C))--A,black);

K=D(CR(A,1));
Kb=D(CR(MP("B_1",D(IP(K,A--B))),0.7));
Kc=D(CR(MP("C_1",D(IP(K,A--C))),0.7));
D(L(MP("X",D(IP(Kb,Kc))),MP("Y",D(OP(Kb,Kc)))),green);

Secondly, look at what's specific for this part and was going to change when rewriting. Those are, of course the pairs A,B,C and all the names given by strings in various MP's. Write them as arguments (a good idea is to make the string names look pretty much like the strings themselves), replace the strings by their names, and get
void B(pair A,pair B,pair C,string B1, string C1, string X, string Y)
{
K=D(CR(A,1));
Kb=D(CR(MP(B1,D(IP(K,A--B))),0.7));
Kc=D(CR(MP(C1,D(IP(K,A--C))),0.7));
D(L(MP(X,D(IP(Kb,Kc))),MP(Y,D(OP(Kb,Kc)))),green);
}

Only wait a minute. Why should B return void? It does a very particular thing: draws a line. So, let's return this line instead (it is not needed for just drawing but, if we are to find the incenter, it may come handy. So, our final version will be
path B(pair A,pair B,pair C,string B1, string C1, string X, string Y)
{
K=D(CR(A,1));
Kb=D(CR(MP(B1,D(IP(K,A--B))),0.7));
Kc=D(CR(MP(C1,D(IP(K,A--C))),0.7));
return D(L(MP(X,D(IP(Kb,Kc))),MP(Y,D(OP(Kb,Kc)))),green);
}

Now, we just call B three times with any notation we want to set up:
pair A=(0,0),B=(0,3),C=(3,2);
path K,Kb,Kc;
D(MP("A",D(A))--MP("B",D(B))--MP("C",D(C))--A,black);
path B(pair A,pair B,pair C,string B1, string C1, string X, string Y)
{
K=D(CR(A,1));
Kb=D(CR(MP(B1,D(IP(K,A--B))),0.7));
Kc=D(CR(MP(C1,D(IP(K,A--C))),0.7));
return D(L(MP(X,D(IP(Kb,Kc))),MP(Y,D(OP(Kb,Kc)))),green);
}
B(A,B,C,"B_a","C_a","X_a","Y_a");
B(B,C,A,"C_b","A_b","X_b","Y_b");
B(C,A,B,"A_c","B_c","X_c","Y_c");

and, voila, all three bisectors are there:
import cse5; size(200); pair A=(0,0),B=(0,3),C=(3,2); path K,Kb,Kc; D(MP("A",D(A))--MP("B",D(B))--MP(&quo...
The length of the code is just 415 symbols and the cost of a bisector is now 33 symbols per bisector compared to 140.

The last question is how to read such code when you see it. Start with the end. You see that some routine is called 3 times, so just figure out what it does one time. There are just four lines in the code of the routine, so, let's analyze the most complicated expression:
D(L(MP(X,D(IP(Kb,Kc))),MP(Y,D(OP(Kb,Kc)))),green);
You see that D is the outer command, so, something is going to be drawn in green. The next command is L, so it is a line. The line requires 2 points and in this case the points look terribly similar, so we are down to
MP(X,D(IP(Kb,Kc)))
to analize. MP just marks a point by X, D just draws it, so we are left withIP(Kb,Kc), which is clear enough.

The next topic is some tricks and treats. I hope that Valentin will install a new version of cse5 by then (the backward compatibility is complete), so I'll be able to describe some features that are not present yet Smile.

PostPosted: Tue May 22, 2007 9:03 am  Back to top 
  ProfilePM
Valentin Vornicu
Admin
Admin


Offline
Joined: 03 Feb 2003
Posts: 7080
Location: California, US
RomaniaUnited States

To rate posts you must be logged in
#6
fedja wrote:
The next topic is some tricks and treats. I hope that Valentin will install a new version of cse5 by then (the backward compatibility is complete), so I'll be able to describe some features that are not present yet Smile.
The newest version is installed.
_________________
We all use math everyday: to forecast weather, to tell time, to handle money; we also use math to analyze crime, reveal patterns, predict behavior. Using numbers we can solve the biggest mysteries we know.

PostPosted: Sat May 26, 2007 1:36 pm  Back to top 
  ProfilePMBlogAlbum
fedja
Birch & Swinnerton Dyer
Birch & Swinnerton Dyer

Offline
Joined: 04 Feb 2005
Posts: 4279
Russian FederationUnited States

To rate posts you must be logged in
#7
A new version of cse5
Here I'll describe a few features that were added to cse5 recently.

Choosing your drawing style. It is possible to customise the default pens cse5 uses for drawing paths and points. The names of the pens are pathpen and pointpen respectively. I personally like thin blue lines and small red dots but nobody said you should like them too. Suppose you like thick green lines and even thicker black dots. Just write
pathpen=green+linewidth(2);
pointpen=black+linewidth(6);

in the beginning of your code and you are there:
import cse5; size(200); pathpen=green+linewidth(2); pointpen=black+linewidth(6); D(D((0,0))--D((2,1))--D((4,2)));
There is one more pen in cse5 you may want to customise: errorpen. What is it for? Just wait a minute, we'll come to that in its time Smile.

Looking at the picture above, you may become a bit upset: the line is OK, but the points aren't nice and round but rather partially devoured by the line going through them. The middle point seems to suffer most. What to do? It is clear that it would be nice to draw all the points (and labels) after all lines. In this short code it is, of course, possible but suppose you have a long code with many points to draw. Should you assign a separate name to each point and end your code with a long string of D() commands? This will be really a headache and it'll effectively eliminate all the advantages of drawing-en-passe. The new version of cse5 offers a better solution inspired by how it is done in \LaTeX. There is a Boolean variable in cse5 called pathflag that you can set to either true or false. When it is true, it results in normal drawing, but when it is false, the paths are not drawn at all, only points and labels appear on the picture, so

pathflag=false;
pathpen=green+linewidth(2);
pointpen=black+linewidth(6);
D(MP("A",D((0,0)))--MP("B",D((2,1)))--MP("C",D((4,2))));

results in
import cse5; size(200); pathflag=false; pathpen=green+linewidth(2); pointpen=black+linewidth(6); D(MP("A",D((0,0)))...
It doesn't seem particularly useful by itself because you still want your paths back, but if you take your old picture with paths abusing points and draw your new picture with paths removed over it, the points will be restored to their full plumpy roundness. So, you'll have to execute your code twice: once with pathflag=true (which is the default, you do not need to set it up) and once with pathflag=false. Does it mean that you have to type your code twice? For God's sake, no! Just enclose your entire code into a subroutine, say B() for Beautification and write something like

import cse5;
size(YOUR SIZE);
void B()
{
YOUR FULL CODE
}
B();pathflag=false;B();

In our particular case, we get
import cse5; size(200); void B() { pathpen=green+linewidth(2); pointpen=black+linewidth(6); D(MP("A",D((0,0)))--MP(...
This beautification comes at a cost, of course, which is 33 extra symbols and doubling the running time but 33 is not such a huge number and posting a correct tried at home program that does something twice is better in terms of saving server time than posting an erratic program once, correcting it and posting it again, which is a sin most of us are guilty of. So, I wouldn't hesitate to use this trick with tried at home programs. Also, the thin paths of the default style do not abuse the points too much unless you have too many of them passing through one point, which makes this trick not always really necessary.

Now there are two more Boolean variables controlling the execution of D() in cse5 that you must be aware of: breakflag and fullbreak. What are they doing? As I said above, cse5 tries to do as much as it can even if there are some paths that do not intersect the way they should. If you are doing just a pure compass-straightedge construction, the output will be completely satisfactory. But if you are mixing it with other Asymptote commands or if you use cse5 just for the sake of drawing-en-passe and foolproof IP but your main construction is not about circles and lines at all, that nullpoint may create quite a mess. So, there is another way that allows you to see where you get an error. Let's try an example. Write something like

path[] P=(0,0)--(1,1)^^(2,-1)--(3,1);
path[] Q=(0,0)--(3,0)^^(3,0.5)--(0,0.5)^^(0,1)--(3,1);
D(MP("X",D(IP(DPA(Q,green),DPA(P),3)))--D((0,0)),black);

with output
import cse5; size(200); path[] P=(0,0)--(1,1)^^(2,-1)--(3,1); path[] Q=(0,0)--(3,0)^^(3,0.5)--(0,0.5)^^(0,1)--(3,1); D(MP(&qu...
What is DPA by the way? It is cse5 command for drawing path arrays, not individual paths. Note that ^^ creates not a path like .. or -- but a path array, so D() won't work in this case. Otherwise, DPA has the same (dis)advantages as D().

Now, we see that the green lines intersect the blue ones at 6 different points. So, asking for the intersection point with index 6 instead of 3,say, will result in a drawing error. Normally, this error will be resolved into
import cse5; size(200); path[] P=(0,0)--(1,1)^^(2,-1)--(3,1); path[] Q=(0,0)--(3,0)^^(3,0.5)--(0,0.5)^^(0,1)--(3,1); D(MP(&qu...
but if you add the

fullbreak=true;

line in the beginning of your code, you'll see
import cse5; size(200); fullbreak=true; path[] P=(0,0)--(1,1)^^(2,-1)--(3,1); path[] Q=(0,0)--(3,0)^^(3,0.5)--(0,0.5)^^(0,1)-...
This picture should be good enough to see from it where the program went astray. The only disadvantage is that fullbreak=true; suppresses all further drawing and labeling after the very first path intersection error, so, if you have several problems like that in your code, you'll see only the first one. The message appears near the point given by the pair messageplace (the default is (0,5)), which you are welcome to reset to whatever you wish. A good idea would be to set it a bit above or a bit below your drawings in the middle in the horizontal direction. So

messageplace=(1.5,2);

will be perfect for this particular picture:
import cse5; size(200); fullbreak=true; messageplace=(1.5,2); path[] P=(0,0)--(1,1)^^(2,-1)--(3,1); path[] Q=(0,0)--(3,0)^^(3...
The poorly intersecting paths are drawn with a special pen errorpen, which is yellow+linewidth(2) by default and which you can change to whatever your wish by errorpen=YOUR PEN command. The only advice is to choose some light color for errorpen on which the black intersection points and their numbers will be clearly visible. The breakflag variable is the auxiliary variable controlled by the IP command. If the paths do not intersect as they should, its value is set to true, which allows the drawing commands "see" that the drawing may be erratic after that. If fullbreak=true by that moment, they just don't draw anything at all but if fullbreak is still false, they continue to draw.

The next topic is about a few things you should know about IP in cse5.

PostPosted: Tue May 29, 2007 12:43 pm  Back to top 
  ProfilePM
fedja
Birch & Swinnerton Dyer
Birch & Swinnerton Dyer

Offline
Joined: 04 Feb 2005
Posts: 4279
Russian FederationUnited States

To rate posts you must be logged in
#8
A few things to know about IP(). In the latest version of cse5, the IP() command is based directly on the intersect command of Asymptote rather than on its derivatives intersectionpoint or intersectionpoints as in the original version. The reason is that intersectionpoint is not flexible enough and crashes the code when the paths fail to intersect and intersectionpoints can effectively suspend Asymptote when one tries to use it to find the common point of a line and a circle that is tangent to this line, not mentioning an attempt to intersect a path with itself. IP() seems to handle all these cases reasonably well. An attempt to intersect a path with itself results in an array of 100 pairs lying on the path near its beginning, so, the code

pair A=(0,0),B=(3,1);
MP("X",D(IP(D(A--B),A--B,5)));

say, doesn't result in an infinite loop the command (intersectionpoints(A--B,A--B))[5] would produce but rather returns a point on the path near its beginning. How near depends on the integer parameter in the IP() command: the point is the very beginning of the path if it is 0 and is about 1/3 of the path length from the beginning if it is 100. In our case, the output is
import cse5; size(200); pair A=(0,0),B=(3,1); MP("X",D(IP(D(A--B),A--B,5)));
The tangency points are taken care of quite nicely too. The code

fullbreak=true;
pair A=MP("A",(-2,1)),B=MP("B",(0,0)),C=MP("C",(2,3));
path P=A--B--C--cycle,Q=incircle(A,B,C);
IP(P,Q,3);

produces
import cse5; size(200); fullbreak=true; pair A=MP("A",(-2,1)),B=MP("B",(0,0)),C=MP("C",(2,3)); ...
which shows that IP() found all three tangency points and enumerated them correctly. If you try (intersectionpoints(P,Q))[3] instead, you'll just suspend the Asymptote. You may try it on your home computer where you can easily shut the non-responding programs down but please, abstain from doing such experiments on the site. So, using IP() instead of intersectionpoint and intersectionpoints seems to be quite advantageous in terms of safe and smooth execution of your code.

Of course, everything comes at a cost. There are two downsides of IP(). First, if your two paths intersect at more than 100 points, IP() will find only first 100 of them. Second, if you have 2 intersection points that lie at the distance of less than 1/300 of the total path length from each other, IP() will see only the first of them. I find these downsides quite minor compared to the erratic run of intersectionpoints in the case of tangency, but, if you think otherwise, you are welcome to try your code with the standard asymptote commands instead of IP and see if it runs any better.

The next thing you should know about IP() is that it is the single most time consuming command. The same is true for the intersectionpoints, of course. The running time is directly proportional to the number of common points (even if just one point is requested, IP() starts with finding them all) and to the complexity of the paths to intersect (so, intersecting 2 circles, say, takes more time than intersecting a circle and a line, which takes more time than intersecting 2 lines). So, if you need to work with more than just a few common points of 2 paths, it may be wise to use the cse5 command IPs() to get the full array once and then to work with the elements of that array instead of calling IP() again and again.

To illustrate what I'm talking about, let's suppose that you want to draw something like this;
import cse5; size(300); path[] P,Q; int k; for(k=0;k<360;k=k+10) P=P^^(0,0)--30.01*dir(k); for(k=10;k<=30;++k) Q=Q^^CR(...
The code

path[] P,Q;
int k;
for(k=0;k<360;k=k+10) P=P^^(0,0)--30.01*dir(k);
for(k=10;k<=30;++k) Q=Q^^CR((0,0),k);
for(k=0;k<36*21;++k) D(IP(P,Q,k));

will do the job eventually but this code took well over 3 minutes to execute on my home PC. The picture was actually drawn by the code

path[] P,Q;
int k;
for(k=0;k<360;k=k+10) P=P^^(0,0)--30.01*dir(k);
for(k=10;k<=30;++k) Q=Q^^CR((0,0),k);
pair[] S=IPs(DPA(P),DPA(Q));
for(k=0;k<S.length;++k) D(S[k]);

in which all the intersection points were found just once by executing a single IPs() command. This code ran in under 2 seconds. Note also the 30.01 instead of more natural 30. This is another little problem that IP() shares with intersectionpoint(s). The reason is that the Asymptote circle is actually a cubic spline and it is a bit wider than the true circle, so the non-extended radii fail to reach it. I think this can be corrected (if anyone cares) by playing a bit with the parameters of the intersect command but I decided that I bothered Valentin just enough for now, so, if there is enough interest in cse5, I'll update the site code in the end of each month during which there are some bug reports or suggestions for improvements.

As you noticed, IP() or IPs can find the intersection points not just of 2 paths, but also of 2 path arrays. They still allow only 100 points per each pair of paths in the arrays. The points are enumerated in the following way. When you have just two paths, they are assigned their numbers according to their order on the first path (so IP(P,Q) may be actually the same as IP(Q,P,3) or something like that. When you have path arrays, first the first path in the first array is intersected with each path in the second array, then the second path in the first array is intersected with each path in the second array, and so on.

Unlike IP(), the IPs command is not fullproof. It returns the array of intersection points but makes no attempt to guess what range of indices you will be interested in. So, it is your responsibility to ensure that you have enough intersection points when going with IPs().

The last thing to mention is one subtle difference between the open path A--B--C--A and the cyclic path A--B--C--cycle from the viepoint of the IP() command. In the first case, the starting and the ending A are considered as two distinct points and in the second case, they are considered as the same point. So an attempt to intersect the horizontal line (-1,0)--(1,0) with the path (0,0)--(1,1)--(-1,1)--(0,0) will result in 2 intersection points both located at (0,0) while intersecting the same line with (0,0)--(1,1)--(-1,1)--cycle will result in just one point. This is not a bug. These paths are also different from the viewpoint of the fill() command: it refuses to run with the first path as an argument claiming that it is not cyclic but runs perfectly well with the second.

The next topic is long names of cse5 commands.

PostPosted: Tue May 29, 2007 4:26 pm  Back to top 
  ProfilePM
fedja
Birch & Swinnerton Dyer
Birch & Swinnerton Dyer

Offline
Joined: 04 Feb 2005
Posts: 4279
Russian FederationUnited States

To rate posts you must be logged in
#9
Long names for cse5 commands. You, probably, wonder how to memorize all those one or two letter abbreviations CR, MP, D, IP, OP, etc. The secret is that each cse5 command has a nice long name that can be used anywhere in the code instead of the corresponding short name, the latter being just a natural abbreviation of the long name. Using long names improves the readability of the code for those who have never seen cse5 before and memorizing long names may be easier then memorizing the short ones but, of course, typing long names is more time-consuming and may easily create a code that exceeds the 2000 characters limit. You may want to go with long names if you have patience to type them and if your code is relatively short, so you do not need to squeeze a lot in one picture. Below is a full list of routine names in cse5:

distance(A,B) or d(A,B). Returns the distance between two points given by the pairs A,B.

Drawing(P,q,m) or D(P,q,m). Draws a path/pair P with pen q if real m is >0 and returns P. The last two arguments q and m are optional and are set to pathpen/pointpen and 1 by default.

DrawPathArray(P,q,m) or DPA(P,q,m). Draws all paths in a path array P with pen q if real m is >0 and returns P. The last two arguments q and m are optional and are set to pathpen and 1 by default.

MarkPoint(s,A,f,B) or MP(s,A,f,B). Marks (or, if you prefer, labels) a point given by the pair A by the string s written in the \LaTeX font of size given by the integer f in the direction given by the pair B from the point and returns A. The last two arguments f and B are optional and are set to 11 and plain.S (south, or (0,-1)) by default.

CirclebyRadius(A,R,a,b) or CR(A,R,a,b). Returns the path that is an arc of a circle centered at the point given by the pair A of radius given by real R from real a degrees to real b degrees. The last two arguments a and b are optional and set to 0 and 360 by default, in which case the full circle is returned as a cyclic path. Note that writing CR(A,R,20,380) will result in an open path that also goes all the way around the circle but is not cyclic, so, you cannot fill it, say. You can write CR(A,R,20,380)--cycle, of course, to get a cyclic path that represents the same full circle but I see absolutely no reason for doing so.

CirclebyPoint(A,B,a,b) or CP(A,B,a,b). Is equivalent (actually, is defined as) CirclebyRadius(A,distance(A,B),a,b) or, if you prefer, CR(A,d(A,B),a,b). The last two arguments a and b are optional and their default values and interpretation is the same as in CirclebyRadius.

Line(A,B,a,b) or L(A,B,a,b) Returns the path that is a line segment passing through the points given by pairs A and B and extended by real a times the distance between A and B beyond A and by real b times the distance between A and B beyond B. The last two arguments a and b are optional. The default values are a=0.6, b=a.

IntersectionPoints(P,Q) or IPs(P,Q). Returns the array of the common points for the paths in the path arrays P and Q. Note that a single path can always be cast into a path array of length 1 by Asymptote, so you do not need to care whether you use path P or path[] P as an argument.

IntersectionPoint(P,Q,m) or IP(P,Q,m). Is basically equivalent to (IPs(P,Q))[m] except it is foolproof. The last argument int m is optional and the default value of it is 0.

OtherPoint(P,Q) or OP(P,Q). Is equivalent to (actually, defined as) IP(P,Q,1).

The next topic is some DOs and DON'Ts.

PostPosted: Tue May 29, 2007 6:40 pm  Back to top 
  ProfilePM
fedja
Birch & Swinnerton Dyer
Birch & Swinnerton Dyer

Offline
Joined: 04 Feb 2005
Posts: 4279
Russian FederationUnited States

To rate posts you must be logged in
#10
Five DOs and five DON'Ts This is not so much about cse5 as about what I consider good and bad habits concerning using Asymptote on AoPS. Valentin is welcome to correct me if he disagrees with my statements and add whatever he deems important to this post.

DO design nice pictures illustrating your questions and solutions especially in the Geometry fora.
DO encode your pictures with Asymptote.
DO use subroutines for repetitive parts of your code.
DO run your code on your home computer before posting to make sure it works as intended.
DO learn Asymptote programming language and play with its various constructs at home.

DON'T try to describe complicated geometric figures in lengthy English sentences without any picture.
DON'T attach huge Word files.
DON'T post an erratic Asymptote code and try to correct it from the posting window.
DON'T post a code that takes a lot of time to execute or, worse, results in suspending Asymptote. This remark especially concerns very long or infinite loops.
DON'T use the site as a testing ground for unfamiliar Asymptote constructs (you are welcome to use the test forum for checking that something that runs well on your home computer runs equally well on the site, of course, but if you are trying something about which you are not 100% sure how exactly it will work, please, try it at home first).

I'd like to finish this manual with reproducing the most elaborate picture I've seen on the forum so far. The entire code is less than 1700 charachters long.
import cse5; size(500); pen d=dashed,b=black,g=grey,lb=lightblue,w=white,lw=linewidth(1); pair B=MP("B",D((0,0))),D...

PostPosted: Wed May 30, 2007 1:12 pm  Back to top 
  ProfilePM
mgao
Navier-Stokes Equations
Navier-Stokes Equations


Offline
Joined: 06 Mar 2006
Posts: 1466
ChinaUnited States

To rate posts you must be logged in
#11
This sounds like a stupid question I know, but is cse5 only on the site, if so, can you post it for download?
_________________
The large print giveth, and the fine print taketh away.

PostPosted: Sun Jul 15, 2007 8:28 am  Back to top 
  ProfilePMBlog
roadnottaken
Yang-Mills Theory
Yang-Mills Theory


Offline
Joined: 27 Nov 2006
Posts: 551
Location: I'm a figment of my own imagination.

To rate posts you must be logged in
#12
The link is http://www.artofproblemsolving.com/Forum/latexrender/cse5.asy. It was mentioned in another thread that got buried a while ago, and I've gotten tired of having to use the search every time I want to find the source code.
_________________
Two roads diverged in a wood, and I-
I took the one less traveled by,
And that has made all the difference.

PostPosted: Fri Aug 17, 2007 10:49 am  Back to top 
  ProfilePMWWW
Valentin Vornicu
Admin
Admin


Offline
Joined: 03 Feb 2003
Posts: 7080
Location: California, US
RomaniaUnited States

To rate posts you must be logged in
#13
A small update: in the code on the forum you don't need to add
Code:
import cse5;
in the beginning of the asy code anymore, it is automatically added Wink
_________________
We all use math everyday: to forecast weather, to tell time, to handle money; we also use math to analyze crime, reveal patterns, predict behavior. Using numbers we can solve the biggest mysteries we know.

PostPosted: Thu Oct 18, 2007 2:48 pm  Back to top 
  ProfilePMBlogAlbum
Valentin Vornicu
Admin
Admin


Offline
Joined: 03 Feb 2003
Posts: 7080
Location: California, US
RomaniaUnited States

To rate posts you must be logged in
#14
I've started to wikify some of this stuff, which is good for future reference: Asymptote: CSE5
Is it possible to have the mark angle (MA) function take 3 parameters (pair center, pair starting point, pair endpoint) of the angle?
_________________
We all use math everyday: to forecast weather, to tell time, to handle money; we also use math to analyze crime, reveal patterns, predict behavior. Using numbers we can solve the biggest mysteries we know.

PostPosted: Tue Oct 30, 2007 11:46 am  Back to top 
  ProfilePMBlogAlbum
ZhangPeijin
Navier-Stokes Equations
Navier-Stokes Equations


Offline
Joined: 27 Mar 2007
Posts: 1374
Location: Lexington, MA Rating: -1337
ChinaUnited States

To rate posts you must be logged in
#15
Wait, how do I actually use the package?
The download page is just a page of code.
_________________
Сфзшефдшяфешщт шы еру вшааукутсу иуецуут рудзштп нщгк Гтсду Офсл щаа ф рщкыу фтв рудзштп нщгк гтсду офсл щаа ф рщкыую

PostPosted: Sun Apr 06, 2008 4:17 pm  Back to top 
  ProfilePMBlog
Valentin Vornicu
Admin
Admin


Offline
Joined: 03 Feb 2003
Posts: 7080
Location: California, US
RomaniaUnited States

To rate posts you must be logged in
#16
You just use the commands in the asy code. The package is automatically imported in any asy code you make on the site. The package file is there if you want to use asymptote on your local environment (for error checking, learning, creating eps files, etc.)
_________________
We all use math everyday: to forecast weather, to tell time, to handle money; we also use math to analyze crime, reveal patterns, predict behavior. Using numbers we can solve the biggest mysteries we know.

PostPosted: Sun Apr 06, 2008 4:31 pm  Back to top 
  ProfilePMBlogAlbum
ZhangPeijin
Navier-Stokes Equations
Navier-Stokes Equations


Offline
Joined: 27 Mar 2007
Posts: 1374
Location: Lexington, MA Rating: -1337
ChinaUnited States

To rate posts you must be logged in
#17
What about in Texnic center?
_________________
Сфзшефдшяфешщт шы еру вшааукутсу иуецуут рудзштп нщгк Гтсду Офсл щаа ф рщкыу фтв рудзштп нщгк гтсду офсл щаа ф рщкыую

PostPosted: Sun Apr 06, 2008 4:36 pm  Back to top 
  ProfilePMBlog
RunpengFAILS
Navier-Stokes Equations
Navier-Stokes Equations

Offline
Joined: 26 Feb 2008
Posts: 1337
Location: Saint Louis, MO
ChinaUnited States

To rate posts you must be logged in
#18
Valentin Vornicu wrote:
You just use the commands in the asy code. The package is automatically imported in any asy code you make on the site. The package file is there if you want to use asymptote on your local environment (for error checking, learning, creating eps files, etc.)


What if I want to use in in Texnic Center?

PostPosted: Fri May 30, 2008 12:25 pm  Back to top 
  ProfilePMWWWBlog
Valentin Vornicu
Admin
Admin


Offline
Joined: 03 Feb 2003
Posts: 7080
Location: California, US
RomaniaUnited States

To rate posts you must be logged in
#19
Download the file cse5.asy (the link is given above), put it in the main Asymptote directory (usually C:\Program Files\Asymptote) and use the command import cse5; at the beginning of your asy file and compile as usual.
_________________
We all use math everyday: to forecast weather, to tell time, to handle money; we also use math to analyze crime, reveal patterns, predict behavior. Using numbers we can solve the biggest mysteries we know.

PostPosted: Fri May 30, 2008 12:29 pm  Back to top 
  ProfilePMBlogAlbum
Display posts from previous:   Sort by:   
19 Posts • Page 1 of 1
Post new topic   Reply to topic View previous topicView next topic
Jump to:  

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum
You cannot post calendar events in this forum


© Copyright 2008 AoPS Incorporated. All Rights Reserved. • FoundationPrivacyContact Us