Hi,
You have two options here:

Projected gradient descent. Where after each step, you project p onto the space you want (here you want p = p / p.norm(1))
Use unconstrained version by learning p just like you do right now, but when you use it, use actual_p = p / p.norm(1). This way, you make sure that actual_p is always of the right norm (whatever the value of p is).