Only one non-nullable value across 3 columns
That's not what indexes are for, you need a check constraint for that, 

For the "at most one can be not null" you can use a little trick: casting a boolean expression to an integer yields 0 or 1. If you add up the values for a is not null condition, the rule "at most one can be not null" translates to "the sum of those must always be 1":

alter table contacts add constraint only_one_not_null
   check (   (a is not null)::int 
           + (b is not null)::int 
           + (c is not null)::int = 1);


The above can be simplified by using the num_nonnulls() function:

alter table contacts add constraint only_one_not_null 
   check (num_nonnulls(a,b,c) = 1);


This also covers the "not all three can be null" requirement.